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