GNU Linux-libre 5.19-rc6-gnu
[releases.git] / sound / soc / generic / simple-card.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // ASoC simple sound card support
4 //
5 // Copyright (C) 2012 Renesas Solutions Corp.
6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
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
25 static 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
31 static int asoc_simple_parse_platform(struct device_node *node,
32                                       struct snd_soc_dai_link_component *dlc)
33 {
34         struct of_phandle_args args;
35         int ret;
36
37         if (!node)
38                 return 0;
39
40         /*
41          * Get node via "sound-dai = <&phandle port>"
42          * it will be used as xxx_of_node on soc_bind_dai_link()
43          */
44         ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
45         if (ret)
46                 return ret;
47
48         /* dai_name is not required and may not exist for plat component */
49
50         dlc->of_node = args.np;
51
52         return 0;
53 }
54
55 static int asoc_simple_parse_dai(struct device_node *node,
56                                  struct snd_soc_dai_link_component *dlc,
57                                  int *is_single_link)
58 {
59         struct of_phandle_args args;
60         int ret;
61
62         if (!node)
63                 return 0;
64
65         /*
66          * Get node via "sound-dai = <&phandle port>"
67          * it will be used as xxx_of_node on soc_bind_dai_link()
68          */
69         ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
70         if (ret)
71                 return ret;
72
73         /*
74          * FIXME
75          *
76          * Here, dlc->dai_name is pointer to CPU/Codec DAI name.
77          * If user unbinded CPU or Codec driver, but not for Sound Card,
78          * dlc->dai_name is keeping unbinded CPU or Codec
79          * driver's pointer.
80          *
81          * If user re-bind CPU or Codec driver again, ALSA SoC will try
82          * to rebind Card via snd_soc_try_rebind_card(), but because of
83          * above reason, it might can't bind Sound Card.
84          * Because Sound Card is pointing to released dai_name pointer.
85          *
86          * To avoid this rebind Card issue,
87          * 1) It needs to alloc memory to keep dai_name eventhough
88          *    CPU or Codec driver was unbinded, or
89          * 2) user need to rebind Sound Card everytime
90          *    if he unbinded CPU or Codec.
91          */
92         ret = snd_soc_of_get_dai_name(node, &dlc->dai_name);
93         if (ret < 0)
94                 return ret;
95
96         dlc->of_node = args.np;
97
98         if (is_single_link)
99                 *is_single_link = !args.args_count;
100
101         return 0;
102 }
103
104 static void simple_parse_convert(struct device *dev,
105                                  struct device_node *np,
106                                  struct asoc_simple_data *adata)
107 {
108         struct device_node *top = dev->of_node;
109         struct device_node *node = of_get_parent(np);
110
111         asoc_simple_parse_convert(top,  PREFIX, adata);
112         asoc_simple_parse_convert(node, PREFIX, adata);
113         asoc_simple_parse_convert(node, NULL,   adata);
114         asoc_simple_parse_convert(np,   NULL,   adata);
115
116         of_node_put(node);
117 }
118
119 static void simple_parse_mclk_fs(struct device_node *top,
120                                  struct device_node *np,
121                                  struct simple_dai_props *props,
122                                  char *prefix)
123 {
124         struct device_node *node = of_get_parent(np);
125         char prop[128];
126
127         snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX);
128         of_property_read_u32(top,       prop, &props->mclk_fs);
129
130         snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
131         of_property_read_u32(node,      prop, &props->mclk_fs);
132         of_property_read_u32(np,        prop, &props->mclk_fs);
133
134         of_node_put(node);
135 }
136
137 static int simple_parse_node(struct asoc_simple_priv *priv,
138                              struct device_node *np,
139                              struct link_info *li,
140                              char *prefix,
141                              int *cpu)
142 {
143         struct device *dev = simple_priv_to_dev(priv);
144         struct device_node *top = dev->of_node;
145         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
146         struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
147         struct snd_soc_dai_link_component *dlc;
148         struct asoc_simple_dai *dai;
149         int ret;
150
151         if (cpu) {
152                 dlc = asoc_link_to_cpu(dai_link, 0);
153                 dai = simple_props_to_dai_cpu(dai_props, 0);
154         } else {
155                 dlc = asoc_link_to_codec(dai_link, 0);
156                 dai = simple_props_to_dai_codec(dai_props, 0);
157         }
158
159         simple_parse_mclk_fs(top, np, dai_props, prefix);
160
161         ret = asoc_simple_parse_dai(np, dlc, cpu);
162         if (ret)
163                 return ret;
164
165         ret = asoc_simple_parse_clk(dev, np, dai, dlc);
166         if (ret)
167                 return ret;
168
169         ret = asoc_simple_parse_tdm(np, dai);
170         if (ret)
171                 return ret;
172
173         return 0;
174 }
175
176 static int simple_link_init(struct asoc_simple_priv *priv,
177                             struct device_node *node,
178                             struct device_node *codec,
179                             struct link_info *li,
180                             char *prefix, char *name)
181 {
182         struct device *dev = simple_priv_to_dev(priv);
183         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
184         int ret;
185
186         ret = asoc_simple_parse_daifmt(dev, node, codec,
187                                        prefix, &dai_link->dai_fmt);
188         if (ret < 0)
189                 return 0;
190
191         dai_link->init                  = asoc_simple_dai_init;
192         dai_link->ops                   = &simple_ops;
193
194         return asoc_simple_set_dailink_name(dev, dai_link, name);
195 }
196
197 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
198                                    struct device_node *np,
199                                    struct device_node *codec,
200                                    struct link_info *li,
201                                    bool is_top)
202 {
203         struct device *dev = simple_priv_to_dev(priv);
204         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
205         struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
206         struct device_node *top = dev->of_node;
207         struct device_node *node = of_get_parent(np);
208         char *prefix = "";
209         char dai_name[64];
210         int ret;
211
212         dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
213
214         /* For single DAI link & old style of DT node */
215         if (is_top)
216                 prefix = PREFIX;
217
218         if (li->cpu) {
219                 struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
220                 struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
221                 int is_single_links = 0;
222
223                 /* Codec is dummy */
224
225                 /* FE settings */
226                 dai_link->dynamic               = 1;
227                 dai_link->dpcm_merged_format    = 1;
228
229                 ret = simple_parse_node(priv, np, li, prefix, &is_single_links);
230                 if (ret < 0)
231                         goto out_put_node;
232
233                 snprintf(dai_name, sizeof(dai_name), "fe.%s", cpus->dai_name);
234
235                 asoc_simple_canonicalize_cpu(cpus, is_single_links);
236                 asoc_simple_canonicalize_platform(platforms, cpus);
237         } else {
238                 struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
239                 struct snd_soc_codec_conf *cconf;
240
241                 /* CPU is dummy */
242
243                 /* BE settings */
244                 dai_link->no_pcm                = 1;
245                 dai_link->be_hw_params_fixup    = asoc_simple_be_hw_params_fixup;
246
247                 cconf   = simple_props_to_codec_conf(dai_props, 0);
248
249                 ret = simple_parse_node(priv, np, li, prefix, NULL);
250                 if (ret < 0)
251                         goto out_put_node;
252
253                 snprintf(dai_name, sizeof(dai_name), "be.%s", codecs->dai_name);
254
255                 /* check "prefix" from top node */
256                 snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
257                                               PREFIX "prefix");
258                 snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
259                                              "prefix");
260                 snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
261                                              "prefix");
262         }
263
264         simple_parse_convert(dev, np, &dai_props->adata);
265
266         snd_soc_dai_link_set_capabilities(dai_link);
267
268         ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
269
270 out_put_node:
271         li->link++;
272
273         of_node_put(node);
274         return ret;
275 }
276
277 static int simple_dai_link_of(struct asoc_simple_priv *priv,
278                               struct device_node *np,
279                               struct device_node *codec,
280                               struct link_info *li,
281                               bool is_top)
282 {
283         struct device *dev = simple_priv_to_dev(priv);
284         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
285         struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
286         struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
287         struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
288         struct device_node *cpu = NULL;
289         struct device_node *node = NULL;
290         struct device_node *plat = NULL;
291         char dai_name[64];
292         char prop[128];
293         char *prefix = "";
294         int ret, single_cpu = 0;
295
296         cpu  = np;
297         node = of_get_parent(np);
298
299         dev_dbg(dev, "link_of (%pOF)\n", node);
300
301         /* For single DAI link & old style of DT node */
302         if (is_top)
303                 prefix = PREFIX;
304
305         snprintf(prop, sizeof(prop), "%splat", prefix);
306         plat = of_get_child_by_name(node, prop);
307
308         ret = simple_parse_node(priv, cpu, li, prefix, &single_cpu);
309         if (ret < 0)
310                 goto dai_link_of_err;
311
312         ret = simple_parse_node(priv, codec, li, prefix, NULL);
313         if (ret < 0)
314                 goto dai_link_of_err;
315
316         ret = asoc_simple_parse_platform(plat, platforms);
317         if (ret < 0)
318                 goto dai_link_of_err;
319
320         snprintf(dai_name, sizeof(dai_name),
321                  "%s-%s", cpus->dai_name, codecs->dai_name);
322
323         asoc_simple_canonicalize_cpu(cpus, single_cpu);
324         asoc_simple_canonicalize_platform(platforms, cpus);
325
326         ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
327
328 dai_link_of_err:
329         of_node_put(plat);
330         of_node_put(node);
331
332         li->link++;
333
334         return ret;
335 }
336
337 static int __simple_for_each_link(struct asoc_simple_priv *priv,
338                         struct link_info *li,
339                         int (*func_noml)(struct asoc_simple_priv *priv,
340                                          struct device_node *np,
341                                          struct device_node *codec,
342                                          struct link_info *li, bool is_top),
343                         int (*func_dpcm)(struct asoc_simple_priv *priv,
344                                          struct device_node *np,
345                                          struct device_node *codec,
346                                          struct link_info *li, bool is_top))
347 {
348         struct device *dev = simple_priv_to_dev(priv);
349         struct device_node *top = dev->of_node;
350         struct device_node *node;
351         uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
352         bool is_top = 0;
353         int ret = 0;
354
355         /* Check if it has dai-link */
356         node = of_get_child_by_name(top, PREFIX "dai-link");
357         if (!node) {
358                 node = of_node_get(top);
359                 is_top = 1;
360         }
361
362         /* loop for all dai-link */
363         do {
364                 struct asoc_simple_data adata;
365                 struct device_node *codec;
366                 struct device_node *plat;
367                 struct device_node *np;
368                 int num = of_get_child_count(node);
369
370                 /* get codec */
371                 codec = of_get_child_by_name(node, is_top ?
372                                              PREFIX "codec" : "codec");
373                 if (!codec) {
374                         ret = -ENODEV;
375                         goto error;
376                 }
377                 /* get platform */
378                 plat = of_get_child_by_name(node, is_top ?
379                                             PREFIX "plat" : "plat");
380
381                 /* get convert-xxx property */
382                 memset(&adata, 0, sizeof(adata));
383                 for_each_child_of_node(node, np)
384                         simple_parse_convert(dev, np, &adata);
385
386                 /* loop for all CPU/Codec node */
387                 for_each_child_of_node(node, np) {
388                         if (plat == np)
389                                 continue;
390                         /*
391                          * It is DPCM
392                          * if it has many CPUs,
393                          * or has convert-xxx property
394                          */
395                         if (dpcm_selectable &&
396                             (num > 2 ||
397                              adata.convert_rate || adata.convert_channels)) {
398                                 /*
399                                  * np
400                                  *       |1(CPU)|0(Codec)  li->cpu
401                                  * CPU   |Pass  |return
402                                  * Codec |return|Pass
403                                  */
404                                 if (li->cpu != (np == codec))
405                                         ret = func_dpcm(priv, np, codec, li, is_top);
406                         /* else normal sound */
407                         } else {
408                                 /*
409                                  * np
410                                  *       |1(CPU)|0(Codec)  li->cpu
411                                  * CPU   |Pass  |return
412                                  * Codec |return|return
413                                  */
414                                 if (li->cpu && (np != codec))
415                                         ret = func_noml(priv, np, codec, li, is_top);
416                         }
417
418                         if (ret < 0) {
419                                 of_node_put(codec);
420                                 of_node_put(np);
421                                 goto error;
422                         }
423                 }
424
425                 of_node_put(codec);
426                 node = of_get_next_child(top, node);
427         } while (!is_top && node);
428
429  error:
430         of_node_put(node);
431         return ret;
432 }
433
434 static int simple_for_each_link(struct asoc_simple_priv *priv,
435                                 struct link_info *li,
436                                 int (*func_noml)(struct asoc_simple_priv *priv,
437                                                  struct device_node *np,
438                                                  struct device_node *codec,
439                                                  struct link_info *li, bool is_top),
440                                 int (*func_dpcm)(struct asoc_simple_priv *priv,
441                                                  struct device_node *np,
442                                                  struct device_node *codec,
443                                                  struct link_info *li, bool is_top))
444 {
445         int ret;
446         /*
447          * Detect all CPU first, and Detect all Codec 2nd.
448          *
449          * In Normal sound case, all DAIs are detected
450          * as "CPU-Codec".
451          *
452          * In DPCM sound case,
453          * all CPUs   are detected as "CPU-dummy", and
454          * all Codecs are detected as "dummy-Codec".
455          * To avoid random sub-device numbering,
456          * detect "dummy-Codec" in last;
457          */
458         for (li->cpu = 1; li->cpu >= 0; li->cpu--) {
459                 ret = __simple_for_each_link(priv, li, func_noml, func_dpcm);
460                 if (ret < 0)
461                         break;
462         }
463
464         return ret;
465 }
466
467 static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
468 {
469         struct snd_soc_card *card = simple_priv_to_card(priv);
470         int ret;
471
472         ret = asoc_simple_parse_widgets(card, PREFIX);
473         if (ret < 0)
474                 return ret;
475
476         ret = asoc_simple_parse_routing(card, PREFIX);
477         if (ret < 0)
478                 return ret;
479
480         ret = asoc_simple_parse_pin_switches(card, PREFIX);
481         if (ret < 0)
482                 return ret;
483
484         /* Single/Muti DAI link(s) & New style of DT node */
485         memset(li, 0, sizeof(*li));
486         ret = simple_for_each_link(priv, li,
487                                    simple_dai_link_of,
488                                    simple_dai_link_of_dpcm);
489         if (ret < 0)
490                 return ret;
491
492         ret = asoc_simple_parse_card_name(card, PREFIX);
493         if (ret < 0)
494                 return ret;
495
496         ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
497
498         return ret;
499 }
500
501 static int simple_count_noml(struct asoc_simple_priv *priv,
502                              struct device_node *np,
503                              struct device_node *codec,
504                              struct link_info *li, bool is_top)
505 {
506         if (li->link >= SNDRV_MAX_LINKS) {
507                 struct device *dev = simple_priv_to_dev(priv);
508
509                 dev_err(dev, "too many links\n");
510                 return -EINVAL;
511         }
512
513         li->num[li->link].cpus          = 1;
514         li->num[li->link].codecs        = 1;
515         li->num[li->link].platforms     = 1;
516
517         li->link += 1;
518
519         return 0;
520 }
521
522 static int simple_count_dpcm(struct asoc_simple_priv *priv,
523                              struct device_node *np,
524                              struct device_node *codec,
525                              struct link_info *li, bool is_top)
526 {
527         if (li->link >= SNDRV_MAX_LINKS) {
528                 struct device *dev = simple_priv_to_dev(priv);
529
530                 dev_err(dev, "too many links\n");
531                 return -EINVAL;
532         }
533
534         if (li->cpu) {
535                 li->num[li->link].cpus          = 1;
536                 li->num[li->link].platforms     = 1;
537
538                 li->link++; /* CPU-dummy */
539         } else {
540                 li->num[li->link].codecs        = 1;
541
542                 li->link++; /* dummy-Codec */
543         }
544
545         return 0;
546 }
547
548 static int simple_get_dais_count(struct asoc_simple_priv *priv,
549                                  struct link_info *li)
550 {
551         struct device *dev = simple_priv_to_dev(priv);
552         struct device_node *top = dev->of_node;
553
554         /*
555          * link_num :   number of links.
556          *              CPU-Codec / CPU-dummy / dummy-Codec
557          * dais_num :   number of DAIs
558          * ccnf_num :   number of codec_conf
559          *              same number for "dummy-Codec"
560          *
561          * ex1)
562          * CPU0 --- Codec0      link : 5
563          * CPU1 --- Codec1      dais : 7
564          * CPU2 -/              ccnf : 1
565          * CPU3 --- Codec2
566          *
567          *      => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
568          *      => 7 DAIs  = 4xCPU + 3xCodec
569          *      => 1 ccnf  = 1xdummy-Codec
570          *
571          * ex2)
572          * CPU0 --- Codec0      link : 5
573          * CPU1 --- Codec1      dais : 6
574          * CPU2 -/              ccnf : 1
575          * CPU3 -/
576          *
577          *      => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
578          *      => 6 DAIs  = 4xCPU + 2xCodec
579          *      => 1 ccnf  = 1xdummy-Codec
580          *
581          * ex3)
582          * CPU0 --- Codec0      link : 6
583          * CPU1 -/              dais : 6
584          * CPU2 --- Codec1      ccnf : 2
585          * CPU3 -/
586          *
587          *      => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
588          *      => 6 DAIs  = 4xCPU + 2xCodec
589          *      => 2 ccnf  = 2xdummy-Codec
590          *
591          * ex4)
592          * CPU0 --- Codec0 (convert-rate)       link : 3
593          * CPU1 --- Codec1                      dais : 4
594          *                                      ccnf : 1
595          *
596          *      => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
597          *      => 4 DAIs  = 2xCPU + 2xCodec
598          *      => 1 ccnf  = 1xdummy-Codec
599          */
600         if (!top) {
601                 li->num[0].cpus         = 1;
602                 li->num[0].codecs       = 1;
603                 li->num[0].platforms    = 1;
604
605                 li->link = 1;
606                 return 0;
607         }
608
609         return simple_for_each_link(priv, li,
610                                     simple_count_noml,
611                                     simple_count_dpcm);
612 }
613
614 static int simple_soc_probe(struct snd_soc_card *card)
615 {
616         struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
617         int ret;
618
619         ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
620         if (ret < 0)
621                 return ret;
622
623         ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
624         if (ret < 0)
625                 return ret;
626
627         return 0;
628 }
629
630 static int asoc_simple_probe(struct platform_device *pdev)
631 {
632         struct asoc_simple_priv *priv;
633         struct device *dev = &pdev->dev;
634         struct device_node *np = dev->of_node;
635         struct snd_soc_card *card;
636         struct link_info *li;
637         int ret;
638
639         /* Allocate the private data and the DAI link array */
640         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
641         if (!priv)
642                 return -ENOMEM;
643
644         card = simple_priv_to_card(priv);
645         card->owner             = THIS_MODULE;
646         card->dev               = dev;
647         card->probe             = simple_soc_probe;
648         card->driver_name       = "simple-card";
649
650         li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
651         if (!li)
652                 return -ENOMEM;
653
654         ret = simple_get_dais_count(priv, li);
655         if (ret < 0)
656                 return ret;
657
658         if (!li->link)
659                 return -EINVAL;
660
661         ret = asoc_simple_init_priv(priv, li);
662         if (ret < 0)
663                 return ret;
664
665         if (np && of_device_is_available(np)) {
666
667                 ret = simple_parse_of(priv, li);
668                 if (ret < 0) {
669                         dev_err_probe(dev, ret, "parse error\n");
670                         goto err;
671                 }
672
673         } else {
674                 struct asoc_simple_card_info *cinfo;
675                 struct snd_soc_dai_link_component *cpus;
676                 struct snd_soc_dai_link_component *codecs;
677                 struct snd_soc_dai_link_component *platform;
678                 struct snd_soc_dai_link *dai_link = priv->dai_link;
679                 struct simple_dai_props *dai_props = priv->dai_props;
680
681                 cinfo = dev->platform_data;
682                 if (!cinfo) {
683                         dev_err(dev, "no info for asoc-simple-card\n");
684                         return -EINVAL;
685                 }
686
687                 if (!cinfo->name ||
688                     !cinfo->codec_dai.name ||
689                     !cinfo->codec ||
690                     !cinfo->platform ||
691                     !cinfo->cpu_dai.name) {
692                         dev_err(dev, "insufficient asoc_simple_card_info settings\n");
693                         return -EINVAL;
694                 }
695
696                 cpus                    = dai_link->cpus;
697                 cpus->dai_name          = cinfo->cpu_dai.name;
698
699                 codecs                  = dai_link->codecs;
700                 codecs->name            = cinfo->codec;
701                 codecs->dai_name        = cinfo->codec_dai.name;
702
703                 platform                = dai_link->platforms;
704                 platform->name          = cinfo->platform;
705
706                 card->name              = (cinfo->card) ? cinfo->card : cinfo->name;
707                 dai_link->name          = cinfo->name;
708                 dai_link->stream_name   = cinfo->name;
709                 dai_link->dai_fmt       = cinfo->daifmt;
710                 dai_link->init          = asoc_simple_dai_init;
711                 memcpy(dai_props->cpu_dai, &cinfo->cpu_dai,
712                                         sizeof(*dai_props->cpu_dai));
713                 memcpy(dai_props->codec_dai, &cinfo->codec_dai,
714                                         sizeof(*dai_props->codec_dai));
715         }
716
717         snd_soc_card_set_drvdata(card, priv);
718
719         asoc_simple_debug_info(priv);
720
721         ret = devm_snd_soc_register_card(dev, card);
722         if (ret < 0)
723                 goto err;
724
725         devm_kfree(dev, li);
726         return 0;
727 err:
728         asoc_simple_clean_reference(card);
729
730         return ret;
731 }
732
733 static const struct of_device_id simple_of_match[] = {
734         { .compatible = "simple-audio-card", },
735         { .compatible = "simple-scu-audio-card",
736           .data = (void *)DPCM_SELECTABLE },
737         {},
738 };
739 MODULE_DEVICE_TABLE(of, simple_of_match);
740
741 static struct platform_driver asoc_simple_card = {
742         .driver = {
743                 .name = "asoc-simple-card",
744                 .pm = &snd_soc_pm_ops,
745                 .of_match_table = simple_of_match,
746         },
747         .probe = asoc_simple_probe,
748         .remove = asoc_simple_remove,
749 };
750
751 module_platform_driver(asoc_simple_card);
752
753 MODULE_ALIAS("platform:asoc-simple-card");
754 MODULE_LICENSE("GPL v2");
755 MODULE_DESCRIPTION("ASoC Simple Sound Card");
756 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");