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
625 li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
626 if (!li)
627 return -ENOMEM;
628
629 ret = simple_get_dais_count(priv, li);
630 if (ret < 0)
631 return ret;
632
633 if (!li->link)
634 return -EINVAL;
635
636 ret = asoc_simple_init_priv(priv, li);
637 if (ret < 0)
638 return ret;
639
640 if (np && of_device_is_available(np)) {
641
642 ret = simple_parse_of(priv, li);
643 if (ret < 0) {
644 if (ret != -EPROBE_DEFER)
645 dev_err(dev, "parse error %d\n", ret);
646 goto err;
647 }
648
649 } else {
650 struct asoc_simple_card_info *cinfo;
651 struct snd_soc_dai_link_component *cpus;
652 struct snd_soc_dai_link_component *codecs;
653 struct snd_soc_dai_link_component *platform;
654 struct snd_soc_dai_link *dai_link = priv->dai_link;
655 struct simple_dai_props *dai_props = priv->dai_props;
656
657 cinfo = dev->platform_data;
658 if (!cinfo) {
659 dev_err(dev, "no info for asoc-simple-card\n");
660 return -EINVAL;
661 }
662
663 if (!cinfo->name ||
664 !cinfo->codec_dai.name ||
665 !cinfo->codec ||
666 !cinfo->platform ||
667 !cinfo->cpu_dai.name) {
668 dev_err(dev, "insufficient asoc_simple_card_info settings\n");
669 return -EINVAL;
670 }
671
672 cpus = dai_link->cpus;
673 cpus->dai_name = cinfo->cpu_dai.name;
674
675 codecs = dai_link->codecs;
676 codecs->name = cinfo->codec;
677 codecs->dai_name = cinfo->codec_dai.name;
678
679 platform = dai_link->platforms;
680 platform->name = cinfo->platform;
681
682 card->name = (cinfo->card) ? cinfo->card : cinfo->name;
683 dai_link->name = cinfo->name;
684 dai_link->stream_name = cinfo->name;
685 dai_link->dai_fmt = cinfo->daifmt;
686 dai_link->init = asoc_simple_dai_init;
687 memcpy(dai_props->cpu_dai, &cinfo->cpu_dai,
688 sizeof(*dai_props->cpu_dai));
689 memcpy(dai_props->codec_dai, &cinfo->codec_dai,
690 sizeof(*dai_props->codec_dai));
691 }
692
693 snd_soc_card_set_drvdata(card, priv);
694
695 asoc_simple_debug_info(priv);
696
697 ret = devm_snd_soc_register_card(dev, card);
698 if (ret < 0)
699 goto err;
700
701 devm_kfree(dev, li);
702 return 0;
703err:
704 asoc_simple_clean_reference(card);
705
706 return ret;
707}
708
709static const struct of_device_id simple_of_match[] = {
710 { .compatible = "simple-audio-card", },
711 { .compatible = "simple-scu-audio-card",
712 .data = (void *)DPCM_SELECTABLE },
713 {},
714};
715MODULE_DEVICE_TABLE(of, simple_of_match);
716
717static struct platform_driver asoc_simple_card = {
718 .driver = {
719 .name = "asoc-simple-card",
720 .pm = &snd_soc_pm_ops,
721 .of_match_table = simple_of_match,
722 },
723 .probe = asoc_simple_probe,
724 .remove = asoc_simple_remove,
725};
726
727module_platform_driver(asoc_simple_card);
728
729MODULE_ALIAS("platform:asoc-simple-card");
730MODULE_LICENSE("GPL v2");
731MODULE_DESCRIPTION("ASoC Simple Sound Card");
732MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
733