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