1
2
3
4
5
6
7
8#include <linux/clk.h>
9#include <linux/device.h>
10#include <linux/module.h>
11#include <linux/of.h>
12#include <linux/of_device.h>
13#include <linux/platform_device.h>
14#include <linux/string.h>
15#include <sound/simple_card.h>
16#include <sound/soc-dai.h>
17#include <sound/soc.h>
18
19#define DPCM_SELECTABLE 1
20
21#define DAI "sound-dai"
22#define CELL "#sound-dai-cells"
23#define PREFIX "simple-audio-card,"
24
25static const struct snd_soc_ops simple_ops = {
26 .startup = asoc_simple_startup,
27 .shutdown = asoc_simple_shutdown,
28 .hw_params = asoc_simple_hw_params,
29};
30
31static int asoc_simple_parse_dai(struct device_node *node,
32 struct snd_soc_dai_link_component *dlc,
33 int *is_single_link)
34{
35 struct of_phandle_args args;
36 int ret;
37
38 if (!node)
39 return 0;
40
41
42
43
44
45 ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
46 if (ret)
47 return ret;
48
49
50 ret = snd_soc_of_get_dai_name(node, &dlc->dai_name);
51 if (ret < 0)
52 return ret;
53
54 dlc->of_node = args.np;
55
56 if (is_single_link)
57 *is_single_link = !args.args_count;
58
59 return 0;
60}
61
62static void simple_parse_convert(struct device *dev,
63 struct device_node *np,
64 struct asoc_simple_data *adata)
65{
66 struct device_node *top = dev->of_node;
67 struct device_node *node = of_get_parent(np);
68
69 asoc_simple_parse_convert(dev, top, PREFIX, adata);
70 asoc_simple_parse_convert(dev, node, PREFIX, adata);
71 asoc_simple_parse_convert(dev, node, NULL, adata);
72 asoc_simple_parse_convert(dev, np, NULL, adata);
73
74 of_node_put(node);
75}
76
77static void simple_parse_mclk_fs(struct device_node *top,
78 struct device_node *cpu,
79 struct device_node *codec,
80 struct simple_dai_props *props,
81 char *prefix)
82{
83 struct device_node *node = of_get_parent(cpu);
84 char prop[128];
85
86 snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX);
87 of_property_read_u32(top, prop, &props->mclk_fs);
88
89 snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
90 of_property_read_u32(node, prop, &props->mclk_fs);
91 of_property_read_u32(cpu, prop, &props->mclk_fs);
92 of_property_read_u32(codec, prop, &props->mclk_fs);
93
94 of_node_put(node);
95}
96
97static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
98 struct device_node *np,
99 struct device_node *codec,
100 struct link_info *li,
101 bool is_top)
102{
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 asoc_simple_dai *dai;
107 struct snd_soc_dai_link_component *cpus = dai_link->cpus;
108 struct snd_soc_dai_link_component *codecs = dai_link->codecs;
109 struct device_node *top = dev->of_node;
110 struct device_node *node = of_get_parent(np);
111 char *prefix = "";
112 int ret;
113
114
115
116
117
118
119
120 if (li->cpu == (np == codec))
121 return 0;
122
123 dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
124
125 li->link++;
126
127
128 if (is_top)
129 prefix = PREFIX;
130
131 if (li->cpu) {
132 int is_single_links = 0;
133
134
135 codecs->of_node = NULL;
136 codecs->dai_name = "snd-soc-dummy-dai";
137 codecs->name = "snd-soc-dummy";
138
139
140 dai_link->dynamic = 1;
141 dai_link->dpcm_merged_format = 1;
142
143 dai =
144 dai_props->cpu_dai = &priv->dais[li->dais++];
145
146 ret = asoc_simple_parse_cpu(np, dai_link, &is_single_links);
147 if (ret)
148 goto out_put_node;
149
150 ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai);
151 if (ret < 0)
152 goto out_put_node;
153
154 ret = asoc_simple_set_dailink_name(dev, dai_link,
155 "fe.%s",
156 cpus->dai_name);
157 if (ret < 0)
158 goto out_put_node;
159
160 asoc_simple_canonicalize_cpu(dai_link, is_single_links);
161 } else {
162 struct snd_soc_codec_conf *cconf;
163
164
165 cpus->of_node = NULL;
166 cpus->dai_name = "snd-soc-dummy-dai";
167 cpus->name = "snd-soc-dummy";
168
169
170 dai_link->no_pcm = 1;
171 dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
172
173 dai =
174 dai_props->codec_dai = &priv->dais[li->dais++];
175
176 cconf =
177 dai_props->codec_conf = &priv->codec_conf[li->conf++];
178
179 ret = asoc_simple_parse_codec(np, dai_link);
180 if (ret < 0)
181 goto out_put_node;
182
183 ret = asoc_simple_parse_clk_codec(dev, np, dai_link, dai);
184 if (ret < 0)
185 goto out_put_node;
186
187 ret = asoc_simple_set_dailink_name(dev, dai_link,
188 "be.%s",
189 codecs->dai_name);
190 if (ret < 0)
191 goto out_put_node;
192
193
194 snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
195 PREFIX "prefix");
196 snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
197 "prefix");
198 snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
199 "prefix");
200 }
201
202 simple_parse_convert(dev, np, &dai_props->adata);
203 simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
204
205 asoc_simple_canonicalize_platform(dai_link);
206
207 ret = asoc_simple_parse_tdm(np, dai);
208 if (ret)
209 goto out_put_node;
210
211 ret = asoc_simple_parse_daifmt(dev, node, codec,
212 prefix, &dai_link->dai_fmt);
213 if (ret < 0)
214 goto out_put_node;
215
216 dai_link->dpcm_playback = 1;
217 dai_link->dpcm_capture = 1;
218 dai_link->ops = &simple_ops;
219 dai_link->init = asoc_simple_dai_init;
220
221out_put_node:
222 of_node_put(node);
223 return ret;
224}
225
226static int simple_dai_link_of(struct asoc_simple_priv *priv,
227 struct device_node *np,
228 struct device_node *codec,
229 struct link_info *li,
230 bool is_top)
231{
232 struct device *dev = simple_priv_to_dev(priv);
233 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
234 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
235 struct asoc_simple_dai *cpu_dai;
236 struct asoc_simple_dai *codec_dai;
237 struct device_node *top = dev->of_node;
238 struct device_node *cpu = NULL;
239 struct device_node *node = NULL;
240 struct device_node *plat = NULL;
241 char prop[128];
242 char *prefix = "";
243 int ret, single_cpu;
244
245
246
247
248
249
250
251 if (!li->cpu || np == codec)
252 return 0;
253
254 cpu = np;
255 node = of_get_parent(np);
256 li->link++;
257
258 dev_dbg(dev, "link_of (%pOF)\n", node);
259
260
261 if (is_top)
262 prefix = PREFIX;
263
264 snprintf(prop, sizeof(prop), "%splat", prefix);
265 plat = of_get_child_by_name(node, prop);
266
267 cpu_dai =
268 dai_props->cpu_dai = &priv->dais[li->dais++];
269 codec_dai =
270 dai_props->codec_dai = &priv->dais[li->dais++];
271
272 ret = asoc_simple_parse_daifmt(dev, node, codec,
273 prefix, &dai_link->dai_fmt);
274 if (ret < 0)
275 goto dai_link_of_err;
276
277 simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix);
278
279 ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu);
280 if (ret < 0)
281 goto dai_link_of_err;
282
283 ret = asoc_simple_parse_codec(codec, dai_link);
284 if (ret < 0)
285 goto dai_link_of_err;
286
287 ret = asoc_simple_parse_platform(plat, dai_link);
288 if (ret < 0)
289 goto dai_link_of_err;
290
291 ret = asoc_simple_parse_tdm(cpu, cpu_dai);
292 if (ret < 0)
293 goto dai_link_of_err;
294
295 ret = asoc_simple_parse_tdm(codec, codec_dai);
296 if (ret < 0)
297 goto dai_link_of_err;
298
299 ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
300 if (ret < 0)
301 goto dai_link_of_err;
302
303 ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai);
304 if (ret < 0)
305 goto dai_link_of_err;
306
307 ret = asoc_simple_set_dailink_name(dev, dai_link,
308 "%s-%s",
309 dai_link->cpus->dai_name,
310 dai_link->codecs->dai_name);
311 if (ret < 0)
312 goto dai_link_of_err;
313
314 dai_link->ops = &simple_ops;
315 dai_link->init = asoc_simple_dai_init;
316
317 asoc_simple_canonicalize_cpu(dai_link, single_cpu);
318 asoc_simple_canonicalize_platform(dai_link);
319
320dai_link_of_err:
321 of_node_put(plat);
322 of_node_put(node);
323
324 return ret;
325}
326
327static int simple_for_each_link(struct asoc_simple_priv *priv,
328 struct link_info *li,
329 int (*func_noml)(struct asoc_simple_priv *priv,
330 struct device_node *np,
331 struct device_node *codec,
332 struct link_info *li, bool is_top),
333 int (*func_dpcm)(struct asoc_simple_priv *priv,
334 struct device_node *np,
335 struct device_node *codec,
336 struct link_info *li, bool is_top))
337{
338 struct device *dev = simple_priv_to_dev(priv);
339 struct device_node *top = dev->of_node;
340 struct device_node *node;
341 uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
342 bool is_top = 0;
343 int ret = 0;
344
345
346 node = of_get_child_by_name(top, PREFIX "dai-link");
347 if (!node) {
348 node = of_node_get(top);
349 is_top = 1;
350 }
351
352
353 do {
354 struct asoc_simple_data adata;
355 struct device_node *codec;
356 struct device_node *np;
357 int num = of_get_child_count(node);
358
359
360 codec = of_get_child_by_name(node, is_top ?
361 PREFIX "codec" : "codec");
362 if (!codec) {
363 ret = -ENODEV;
364 goto error;
365 }
366
367
368 memset(&adata, 0, sizeof(adata));
369 for_each_child_of_node(node, np)
370 simple_parse_convert(dev, np, &adata);
371
372
373 for_each_child_of_node(node, np) {
374
375
376
377
378
379 if (dpcm_selectable &&
380 (num > 2 ||
381 adata.convert_rate || adata.convert_channels))
382 ret = func_dpcm(priv, np, codec, li, is_top);
383
384 else
385 ret = func_noml(priv, np, codec, li, is_top);
386
387 if (ret < 0) {
388 of_node_put(codec);
389 of_node_put(np);
390 goto error;
391 }
392 }
393
394 of_node_put(codec);
395 node = of_get_next_child(top, node);
396 } while (!is_top && node);
397
398 error:
399 of_node_put(node);
400 return ret;
401}
402
403static int simple_parse_aux_devs(struct device_node *node,
404 struct asoc_simple_priv *priv)
405{
406 struct device *dev = simple_priv_to_dev(priv);
407 struct device_node *aux_node;
408 struct snd_soc_card *card = simple_priv_to_card(priv);
409 int i, n, len;
410
411 if (!of_find_property(node, PREFIX "aux-devs", &len))
412 return 0;
413
414 n = len / sizeof(__be32);
415 if (n <= 0)
416 return -EINVAL;
417
418 card->aux_dev = devm_kcalloc(dev,
419 n, sizeof(*card->aux_dev), GFP_KERNEL);
420 if (!card->aux_dev)
421 return -ENOMEM;
422
423 for (i = 0; i < n; i++) {
424 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
425 if (!aux_node)
426 return -EINVAL;
427 card->aux_dev[i].codec_of_node = aux_node;
428 }
429
430 card->num_aux_devs = n;
431 return 0;
432}
433
434static int simple_parse_of(struct asoc_simple_priv *priv)
435{
436 struct device *dev = simple_priv_to_dev(priv);
437 struct device_node *top = dev->of_node;
438 struct snd_soc_card *card = simple_priv_to_card(priv);
439 struct link_info li;
440 int ret;
441
442 if (!top)
443 return -EINVAL;
444
445 ret = asoc_simple_parse_widgets(card, PREFIX);
446 if (ret < 0)
447 return ret;
448
449 ret = asoc_simple_parse_routing(card, PREFIX);
450 if (ret < 0)
451 return ret;
452
453 ret = asoc_simple_parse_pin_switches(card, PREFIX);
454 if (ret < 0)
455 return ret;
456
457
458 memset(&li, 0, sizeof(li));
459 for (li.cpu = 1; li.cpu >= 0; li.cpu--) {
460
461
462
463
464
465
466
467
468
469
470
471
472 ret = simple_for_each_link(priv, &li,
473 simple_dai_link_of,
474 simple_dai_link_of_dpcm);
475 if (ret < 0)
476 return ret;
477 }
478
479 ret = asoc_simple_parse_card_name(card, PREFIX);
480 if (ret < 0)
481 return ret;
482
483 ret = simple_parse_aux_devs(top, priv);
484
485 return ret;
486}
487
488static int simple_count_noml(struct asoc_simple_priv *priv,
489 struct device_node *np,
490 struct device_node *codec,
491 struct link_info *li, bool is_top)
492{
493 li->dais++;
494 if (np != codec)
495 li->link++;
496
497 return 0;
498}
499
500static int simple_count_dpcm(struct asoc_simple_priv *priv,
501 struct device_node *np,
502 struct device_node *codec,
503 struct link_info *li, bool is_top)
504{
505 li->dais++;
506 li->link++;
507 if (np == codec)
508 li->conf++;
509
510 return 0;
511}
512
513static void simple_get_dais_count(struct asoc_simple_priv *priv,
514 struct link_info *li)
515{
516 struct device *dev = simple_priv_to_dev(priv);
517 struct device_node *top = dev->of_node;
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
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565 if (!top) {
566 li->link = 1;
567 li->dais = 2;
568 li->conf = 0;
569 return;
570 }
571
572 simple_for_each_link(priv, li,
573 simple_count_noml,
574 simple_count_dpcm);
575
576 dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
577 li->link, li->dais, li->conf);
578}
579
580static int simple_soc_probe(struct snd_soc_card *card)
581{
582 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
583 int ret;
584
585 ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
586 if (ret < 0)
587 return ret;
588
589 ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
590 if (ret < 0)
591 return ret;
592
593 return 0;
594}
595
596static int asoc_simple_probe(struct platform_device *pdev)
597{
598 struct asoc_simple_priv *priv;
599 struct device *dev = &pdev->dev;
600 struct device_node *np = dev->of_node;
601 struct snd_soc_card *card;
602 struct link_info li;
603 int ret;
604
605
606 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
607 if (!priv)
608 return -ENOMEM;
609
610 card = simple_priv_to_card(priv);
611 card->owner = THIS_MODULE;
612 card->dev = dev;
613 card->probe = simple_soc_probe;
614
615 memset(&li, 0, sizeof(li));
616 simple_get_dais_count(priv, &li);
617 if (!li.link || !li.dais)
618 return -EINVAL;
619
620 ret = asoc_simple_init_priv(priv, &li);
621 if (ret < 0)
622 return ret;
623
624 if (np && of_device_is_available(np)) {
625
626 ret = simple_parse_of(priv);
627 if (ret < 0) {
628 if (ret != -EPROBE_DEFER)
629 dev_err(dev, "parse error %d\n", ret);
630 goto err;
631 }
632
633 } else {
634 struct asoc_simple_card_info *cinfo;
635 struct snd_soc_dai_link_component *cpus;
636 struct snd_soc_dai_link_component *codecs;
637 struct snd_soc_dai_link_component *platform;
638 struct snd_soc_dai_link *dai_link = priv->dai_link;
639 struct simple_dai_props *dai_props = priv->dai_props;
640
641 int dai_idx = 0;
642
643 cinfo = dev->platform_data;
644 if (!cinfo) {
645 dev_err(dev, "no info for asoc-simple-card\n");
646 return -EINVAL;
647 }
648
649 if (!cinfo->name ||
650 !cinfo->codec_dai.name ||
651 !cinfo->codec ||
652 !cinfo->platform ||
653 !cinfo->cpu_dai.name) {
654 dev_err(dev, "insufficient asoc_simple_card_info settings\n");
655 return -EINVAL;
656 }
657
658 dai_props->cpu_dai = &priv->dais[dai_idx++];
659 dai_props->codec_dai = &priv->dais[dai_idx++];
660
661 cpus = dai_link->cpus;
662 cpus->dai_name = cinfo->cpu_dai.name;
663
664 codecs = dai_link->codecs;
665 codecs->name = cinfo->codec;
666 codecs->dai_name = cinfo->codec_dai.name;
667
668 platform = dai_link->platforms;
669 platform->name = cinfo->platform;
670
671 card->name = (cinfo->card) ? cinfo->card : cinfo->name;
672 dai_link->name = cinfo->name;
673 dai_link->stream_name = cinfo->name;
674 dai_link->dai_fmt = cinfo->daifmt;
675 dai_link->init = asoc_simple_dai_init;
676 memcpy(dai_props->cpu_dai, &cinfo->cpu_dai,
677 sizeof(*dai_props->cpu_dai));
678 memcpy(dai_props->codec_dai, &cinfo->codec_dai,
679 sizeof(*dai_props->codec_dai));
680 }
681
682 snd_soc_card_set_drvdata(card, priv);
683
684 asoc_simple_debug_info(priv);
685
686 ret = devm_snd_soc_register_card(dev, card);
687 if (ret < 0)
688 goto err;
689
690 return 0;
691err:
692 asoc_simple_clean_reference(card);
693
694 return ret;
695}
696
697static int asoc_simple_remove(struct platform_device *pdev)
698{
699 struct snd_soc_card *card = platform_get_drvdata(pdev);
700
701 return asoc_simple_clean_reference(card);
702}
703
704static const struct of_device_id simple_of_match[] = {
705 { .compatible = "simple-audio-card", },
706 { .compatible = "simple-scu-audio-card",
707 .data = (void *)DPCM_SELECTABLE },
708 {},
709};
710MODULE_DEVICE_TABLE(of, simple_of_match);
711
712static struct platform_driver asoc_simple_card = {
713 .driver = {
714 .name = "asoc-simple-card",
715 .pm = &snd_soc_pm_ops,
716 .of_match_table = simple_of_match,
717 },
718 .probe = asoc_simple_probe,
719 .remove = asoc_simple_remove,
720};
721
722module_platform_driver(asoc_simple_card);
723
724MODULE_ALIAS("platform:asoc-simple-card");
725MODULE_LICENSE("GPL v2");
726MODULE_DESCRIPTION("ASoC Simple Sound Card");
727MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
728