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