]> asedeno.scripts.mit.edu Git - linux.git/blob - sound/soc/generic/simple-card.c
dc18c44929557d68b04fd2e4c470c6ac63b593bb
[linux.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/platform_device.h>
13 #include <linux/string.h>
14 #include <sound/simple_card.h>
15 #include <sound/soc-dai.h>
16 #include <sound/soc.h>
17
18 struct simple_priv {
19         struct snd_soc_card snd_card;
20         struct simple_dai_props {
21                 struct asoc_simple_dai *cpu_dai;
22                 struct asoc_simple_dai *codec_dai;
23                 struct snd_soc_dai_link_component codecs; /* single codec */
24                 struct snd_soc_dai_link_component platforms;
25                 struct asoc_simple_card_data adata;
26                 struct snd_soc_codec_conf *codec_conf;
27                 unsigned int mclk_fs;
28         } *dai_props;
29         struct asoc_simple_jack hp_jack;
30         struct asoc_simple_jack mic_jack;
31         struct snd_soc_dai_link *dai_link;
32         struct asoc_simple_dai *dais;
33         struct snd_soc_codec_conf *codec_conf;
34 };
35
36 struct link_info {
37         int dais; /* number of dai  */
38         int link; /* number of link */
39         int conf; /* number of codec_conf */
40         int cpu;  /* turn for CPU / Codec */
41 };
42
43 #define simple_priv_to_card(priv) (&(priv)->snd_card)
44 #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
45 #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
46 #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
47
48 #define DAI     "sound-dai"
49 #define CELL    "#sound-dai-cells"
50 #define PREFIX  "simple-audio-card,"
51
52 static int simple_startup(struct snd_pcm_substream *substream)
53 {
54         struct snd_soc_pcm_runtime *rtd = substream->private_data;
55         struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
56         struct simple_dai_props *dai_props =
57                 simple_priv_to_props(priv, rtd->num);
58         int ret;
59
60         ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
61         if (ret)
62                 return ret;
63
64         ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
65         if (ret)
66                 asoc_simple_card_clk_disable(dai_props->cpu_dai);
67
68         return ret;
69 }
70
71 static void simple_shutdown(struct snd_pcm_substream *substream)
72 {
73         struct snd_soc_pcm_runtime *rtd = substream->private_data;
74         struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
75         struct simple_dai_props *dai_props =
76                 simple_priv_to_props(priv, rtd->num);
77
78         asoc_simple_card_clk_disable(dai_props->cpu_dai);
79
80         asoc_simple_card_clk_disable(dai_props->codec_dai);
81 }
82
83 static int simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
84                                unsigned long rate)
85 {
86         if (!simple_dai)
87                 return 0;
88
89         if (!simple_dai->clk)
90                 return 0;
91
92         if (clk_get_rate(simple_dai->clk) == rate)
93                 return 0;
94
95         return clk_set_rate(simple_dai->clk, rate);
96 }
97
98 static int simple_hw_params(struct snd_pcm_substream *substream,
99                             struct snd_pcm_hw_params *params)
100 {
101         struct snd_soc_pcm_runtime *rtd = substream->private_data;
102         struct snd_soc_dai *codec_dai = rtd->codec_dai;
103         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
104         struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
105         struct simple_dai_props *dai_props =
106                 simple_priv_to_props(priv, rtd->num);
107         unsigned int mclk, mclk_fs = 0;
108         int ret = 0;
109
110         if (dai_props->mclk_fs)
111                 mclk_fs = dai_props->mclk_fs;
112
113         if (mclk_fs) {
114                 mclk = params_rate(params) * mclk_fs;
115
116                 ret = simple_set_clk_rate(dai_props->codec_dai, mclk);
117                 if (ret < 0)
118                         return ret;
119
120                 ret = simple_set_clk_rate(dai_props->cpu_dai, mclk);
121                 if (ret < 0)
122                         return ret;
123
124                 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
125                                              SND_SOC_CLOCK_IN);
126                 if (ret && ret != -ENOTSUPP)
127                         goto err;
128
129                 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
130                                              SND_SOC_CLOCK_OUT);
131                 if (ret && ret != -ENOTSUPP)
132                         goto err;
133         }
134         return 0;
135 err:
136         return ret;
137 }
138
139 static const struct snd_soc_ops simple_ops = {
140         .startup        = simple_startup,
141         .shutdown       = simple_shutdown,
142         .hw_params      = simple_hw_params,
143 };
144
145 static int simple_dai_init(struct snd_soc_pcm_runtime *rtd)
146 {
147         struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
148         struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
149         int ret;
150
151         ret = asoc_simple_card_init_dai(rtd->codec_dai,
152                                         dai_props->codec_dai);
153         if (ret < 0)
154                 return ret;
155
156         ret = asoc_simple_card_init_dai(rtd->cpu_dai,
157                                         dai_props->cpu_dai);
158         if (ret < 0)
159                 return ret;
160
161         return 0;
162 }
163
164 static int simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
165                                      struct snd_pcm_hw_params *params)
166 {
167         struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
168         struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
169
170         asoc_simple_card_convert_fixup(&dai_props->adata, params);
171
172         return 0;
173 }
174
175 static void simple_get_conversion(struct device *dev,
176                                   struct device_node *np,
177                                   struct asoc_simple_card_data *adata)
178 {
179         struct device_node *top = dev->of_node;
180         struct device_node *node = of_get_parent(np);
181
182         asoc_simple_card_parse_convert(dev, top,  PREFIX, adata);
183         asoc_simple_card_parse_convert(dev, node, PREFIX, adata);
184         asoc_simple_card_parse_convert(dev, node, NULL,   adata);
185         asoc_simple_card_parse_convert(dev, np,   NULL,   adata);
186
187         of_node_put(node);
188 }
189
190 static int simple_dai_link_of_dpcm(struct simple_priv *priv,
191                                    struct device_node *np,
192                                    struct device_node *codec,
193                                    struct link_info *li,
194                                    bool is_top)
195 {
196         struct device *dev = simple_priv_to_dev(priv);
197         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
198         struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
199         struct asoc_simple_dai *dai;
200         struct snd_soc_dai_link_component *codecs = dai_link->codecs;
201         struct device_node *top = dev->of_node;
202         struct device_node *node = of_get_parent(np);
203         char prop[128];
204         char *prefix = "";
205         int ret;
206
207         /*
208          *       |CPU   |Codec   : turn
209          * CPU   |Pass  |return
210          * Codec |return|Pass
211          * np
212          */
213         if (li->cpu == (np == codec))
214                 return 0;
215
216         dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
217
218         li->link++;
219
220         of_node_put(node);
221
222         /* For single DAI link & old style of DT node */
223         if (is_top)
224                 prefix = PREFIX;
225
226         if (li->cpu) {
227                 int is_single_links = 0;
228
229                 /* BE is dummy */
230                 codecs->of_node         = NULL;
231                 codecs->dai_name        = "snd-soc-dummy-dai";
232                 codecs->name            = "snd-soc-dummy";
233
234                 /* FE settings */
235                 dai_link->dynamic               = 1;
236                 dai_link->dpcm_merged_format    = 1;
237
238                 dai =
239                 dai_props->cpu_dai      = &priv->dais[li->dais++];
240
241                 ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
242                                                  &is_single_links);
243                 if (ret)
244                         return ret;
245
246                 ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
247                 if (ret < 0)
248                         return ret;
249
250                 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
251                                                         "fe.%s",
252                                                         dai_link->cpu_dai_name);
253                 if (ret < 0)
254                         return ret;
255
256                 asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
257         } else {
258                 struct snd_soc_codec_conf *cconf;
259
260                 /* FE is dummy */
261                 dai_link->cpu_of_node           = NULL;
262                 dai_link->cpu_dai_name          = "snd-soc-dummy-dai";
263                 dai_link->cpu_name              = "snd-soc-dummy";
264
265                 /* BE settings */
266                 dai_link->no_pcm                = 1;
267                 dai_link->be_hw_params_fixup    = simple_be_hw_params_fixup;
268
269                 dai =
270                 dai_props->codec_dai    = &priv->dais[li->dais++];
271
272                 cconf =
273                 dai_props->codec_conf   = &priv->codec_conf[li->conf++];
274
275                 ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
276                 if (ret < 0)
277                         return ret;
278
279                 ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
280                 if (ret < 0)
281                         return ret;
282
283                 ret = asoc_simple_card_set_dailink_name(dev, dai_link,
284                                                         "be.%s",
285                                                         codecs->dai_name);
286                 if (ret < 0)
287                         return ret;
288
289                 /* check "prefix" from top node */
290                 snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
291                                               PREFIX "prefix");
292                 snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
293                                              "prefix");
294                 snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
295                                              "prefix");
296         }
297
298         simple_get_conversion(dev, np, &dai_props->adata);
299
300         asoc_simple_card_canonicalize_platform(dai_link);
301
302         ret = asoc_simple_card_of_parse_tdm(np, dai);
303         if (ret)
304                 return ret;
305
306         snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
307         of_property_read_u32(top,  PREFIX "mclk-fs", &dai_props->mclk_fs);
308         of_property_read_u32(node, prop, &dai_props->mclk_fs);
309         of_property_read_u32(np,   prop, &dai_props->mclk_fs);
310
311         ret = asoc_simple_card_parse_daifmt(dev, node, codec,
312                                             prefix, &dai_link->dai_fmt);
313         if (ret < 0)
314                 return ret;
315
316         dai_link->dpcm_playback         = 1;
317         dai_link->dpcm_capture          = 1;
318         dai_link->ops                   = &simple_ops;
319         dai_link->init                  = simple_dai_init;
320
321         return 0;
322 }
323
324 static int simple_dai_link_of(struct simple_priv *priv,
325                               struct device_node *np,
326                               struct device_node *codec,
327                               struct link_info *li,
328                               bool is_top)
329 {
330         struct device *dev = simple_priv_to_dev(priv);
331         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
332         struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
333         struct asoc_simple_dai *cpu_dai;
334         struct asoc_simple_dai *codec_dai;
335         struct device_node *top = dev->of_node;
336         struct device_node *cpu = NULL;
337         struct device_node *node = NULL;
338         struct device_node *plat = NULL;
339         char prop[128];
340         char *prefix = "";
341         int ret, single_cpu;
342
343         /*
344          *       |CPU   |Codec   : turn
345          * CPU   |Pass  |return
346          * Codec |return|return
347          * np
348          */
349         if (!li->cpu || np == codec)
350                 return 0;
351
352         cpu  = np;
353         node = of_get_parent(np);
354         li->link++;
355
356         dev_dbg(dev, "link_of (%pOF)\n", node);
357
358         /* For single DAI link & old style of DT node */
359         if (is_top)
360                 prefix = PREFIX;
361
362         snprintf(prop, sizeof(prop), "%splat", prefix);
363         plat = of_get_child_by_name(node, prop);
364
365         cpu_dai                 =
366         dai_props->cpu_dai      = &priv->dais[li->dais++];
367         codec_dai               =
368         dai_props->codec_dai    = &priv->dais[li->dais++];
369
370         ret = asoc_simple_card_parse_daifmt(dev, node, codec,
371                                             prefix, &dai_link->dai_fmt);
372         if (ret < 0)
373                 goto dai_link_of_err;
374
375         snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
376         of_property_read_u32(top,  PREFIX "mclk-fs", &dai_props->mclk_fs);
377         of_property_read_u32(node,  prop, &dai_props->mclk_fs);
378         of_property_read_u32(cpu,   prop, &dai_props->mclk_fs);
379         of_property_read_u32(codec, prop, &dai_props->mclk_fs);
380
381         ret = asoc_simple_card_parse_cpu(cpu, dai_link,
382                                          DAI, CELL, &single_cpu);
383         if (ret < 0)
384                 goto dai_link_of_err;
385
386         ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
387         if (ret < 0)
388                 goto dai_link_of_err;
389
390         ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
391         if (ret < 0)
392                 goto dai_link_of_err;
393
394         ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
395         if (ret < 0)
396                 goto dai_link_of_err;
397
398         ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
399         if (ret < 0)
400                 goto dai_link_of_err;
401
402         ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
403         if (ret < 0)
404                 goto dai_link_of_err;
405
406         ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
407         if (ret < 0)
408                 goto dai_link_of_err;
409
410         ret = asoc_simple_card_set_dailink_name(dev, dai_link,
411                                                 "%s-%s",
412                                                 dai_link->cpu_dai_name,
413                                                 dai_link->codecs->dai_name);
414         if (ret < 0)
415                 goto dai_link_of_err;
416
417         dai_link->ops = &simple_ops;
418         dai_link->init = simple_dai_init;
419
420         asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
421         asoc_simple_card_canonicalize_platform(dai_link);
422
423 dai_link_of_err:
424         of_node_put(node);
425
426         return ret;
427 }
428
429 static int simple_for_each_link(struct simple_priv *priv,
430                         struct link_info *li,
431                         int (*func_noml)(struct simple_priv *priv,
432                                          struct device_node *np,
433                                          struct device_node *codec,
434                                          struct link_info *li, bool is_top),
435                         int (*func_dpcm)(struct simple_priv *priv,
436                                          struct device_node *np,
437                                          struct device_node *codec,
438                                          struct link_info *li, bool is_top))
439 {
440         struct device *dev = simple_priv_to_dev(priv);
441         struct device_node *top = dev->of_node;
442         struct device_node *node;
443         bool is_top = 0;
444
445         /* Check if it has dai-link */
446         node = of_get_child_by_name(top, PREFIX "dai-link");
447         if (!node) {
448                 node = of_node_get(top);
449                 is_top = 1;
450         }
451
452         /* loop for all dai-link */
453         do {
454                 struct asoc_simple_card_data adata;
455                 struct device_node *codec;
456                 struct device_node *np;
457                 int num = of_get_child_count(node);
458                 int ret;
459
460                 /* get codec */
461                 codec = of_get_child_by_name(node, is_top ?
462                                              PREFIX "codec" : "codec");
463                 if (!codec)
464                         return -ENODEV;
465
466                 of_node_put(codec);
467
468                 /* get convert-xxx property */
469                 memset(&adata, 0, sizeof(adata));
470                 for_each_child_of_node(node, np)
471                         simple_get_conversion(dev, np, &adata);
472
473                 /* loop for all CPU/Codec node */
474                 for_each_child_of_node(node, np) {
475                         /*
476                          * It is DPCM
477                          * if it has many CPUs,
478                          * or has convert-xxx property
479                          */
480                         if (num > 2 ||
481                             adata.convert_rate || adata.convert_channels)
482                                 ret = func_dpcm(priv, np, codec, li, is_top);
483                         /* else normal sound */
484                         else
485                                 ret = func_noml(priv, np, codec, li, is_top);
486
487                         if (ret < 0)
488                                 return ret;
489                 }
490
491                 node = of_get_next_child(top, node);
492         } while (!is_top && node);
493
494         return 0;
495 }
496
497 static int simple_parse_aux_devs(struct device_node *node,
498                                  struct simple_priv *priv)
499 {
500         struct device *dev = simple_priv_to_dev(priv);
501         struct device_node *aux_node;
502         struct snd_soc_card *card = simple_priv_to_card(priv);
503         int i, n, len;
504
505         if (!of_find_property(node, PREFIX "aux-devs", &len))
506                 return 0;               /* Ok to have no aux-devs */
507
508         n = len / sizeof(__be32);
509         if (n <= 0)
510                 return -EINVAL;
511
512         card->aux_dev = devm_kcalloc(dev,
513                         n, sizeof(*card->aux_dev), GFP_KERNEL);
514         if (!card->aux_dev)
515                 return -ENOMEM;
516
517         for (i = 0; i < n; i++) {
518                 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
519                 if (!aux_node)
520                         return -EINVAL;
521                 card->aux_dev[i].codec_of_node = aux_node;
522         }
523
524         card->num_aux_devs = n;
525         return 0;
526 }
527
528 static int simple_parse_of(struct simple_priv *priv)
529 {
530         struct device *dev = simple_priv_to_dev(priv);
531         struct device_node *top = dev->of_node;
532         struct snd_soc_card *card = simple_priv_to_card(priv);
533         struct link_info li;
534         int ret;
535
536         if (!top)
537                 return -EINVAL;
538
539         ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
540         if (ret < 0)
541                 return ret;
542
543         ret = asoc_simple_card_of_parse_routing(card, PREFIX);
544         if (ret < 0)
545                 return ret;
546
547         /* Single/Muti DAI link(s) & New style of DT node */
548         memset(&li, 0, sizeof(li));
549         for (li.cpu = 1; li.cpu >= 0; li.cpu--) {
550                 /*
551                  * Detect all CPU first, and Detect all Codec 2nd.
552                  *
553                  * In Normal sound case, all DAIs are detected
554                  * as "CPU-Codec".
555                  *
556                  * In DPCM sound case,
557                  * all CPUs   are detected as "CPU-dummy", and
558                  * all Codecs are detected as "dummy-Codec".
559                  * To avoid random sub-device numbering,
560                  * detect "dummy-Codec" in last;
561                  */
562                 ret = simple_for_each_link(priv, &li,
563                                            simple_dai_link_of,
564                                            simple_dai_link_of_dpcm);
565                 if (ret < 0)
566                         return ret;
567         }
568
569         ret = asoc_simple_card_parse_card_name(card, PREFIX);
570         if (ret < 0)
571                 return ret;
572
573         ret = simple_parse_aux_devs(top, priv);
574
575         return ret;
576 }
577
578 static int simple_count_noml(struct simple_priv *priv,
579                              struct device_node *np,
580                              struct device_node *codec,
581                              struct link_info *li, bool is_top)
582 {
583         li->dais++; /* CPU or Codec */
584         if (np != codec)
585                 li->link++; /* CPU-Codec */
586
587         return 0;
588 }
589
590 static int simple_count_dpcm(struct simple_priv *priv,
591                              struct device_node *np,
592                              struct device_node *codec,
593                              struct link_info *li, bool is_top)
594 {
595         li->dais++; /* CPU or Codec */
596         li->link++; /* CPU-dummy or dummy-Codec */
597         if (np == codec)
598                 li->conf++;
599
600         return 0;
601 }
602
603 static void simple_get_dais_count(struct simple_priv *priv,
604                                   struct link_info *li)
605 {
606         struct device *dev = simple_priv_to_dev(priv);
607         struct device_node *top = dev->of_node;
608
609         /*
610          * link_num :   number of links.
611          *              CPU-Codec / CPU-dummy / dummy-Codec
612          * dais_num :   number of DAIs
613          * ccnf_num :   number of codec_conf
614          *              same number for "dummy-Codec"
615          *
616          * ex1)
617          * CPU0 --- Codec0      link : 5
618          * CPU1 --- Codec1      dais : 7
619          * CPU2 -/              ccnf : 1
620          * CPU3 --- Codec2
621          *
622          *      => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
623          *      => 7 DAIs  = 4xCPU + 3xCodec
624          *      => 1 ccnf  = 1xdummy-Codec
625          *
626          * ex2)
627          * CPU0 --- Codec0      link : 5
628          * CPU1 --- Codec1      dais : 6
629          * CPU2 -/              ccnf : 1
630          * CPU3 -/
631          *
632          *      => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
633          *      => 6 DAIs  = 4xCPU + 2xCodec
634          *      => 1 ccnf  = 1xdummy-Codec
635          *
636          * ex3)
637          * CPU0 --- Codec0      link : 6
638          * CPU1 -/              dais : 6
639          * CPU2 --- Codec1      ccnf : 2
640          * CPU3 -/
641          *
642          *      => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
643          *      => 6 DAIs  = 4xCPU + 2xCodec
644          *      => 2 ccnf  = 2xdummy-Codec
645          *
646          * ex4)
647          * CPU0 --- Codec0 (convert-rate)       link : 3
648          * CPU1 --- Codec1                      dais : 4
649          *                                      ccnf : 1
650          *
651          *      => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
652          *      => 4 DAIs  = 2xCPU + 2xCodec
653          *      => 1 ccnf  = 1xdummy-Codec
654          */
655         if (!top) {
656                 li->link = 1;
657                 li->dais = 2;
658                 li->conf = 0;
659                 return;
660         }
661
662         simple_for_each_link(priv, li,
663                              simple_count_noml,
664                              simple_count_dpcm);
665
666         dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
667                 li->link, li->dais, li->conf);
668 }
669
670 static int simple_soc_probe(struct snd_soc_card *card)
671 {
672         struct simple_priv *priv = snd_soc_card_get_drvdata(card);
673         int ret;
674
675         ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
676         if (ret < 0)
677                 return ret;
678
679         ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
680         if (ret < 0)
681                 return ret;
682
683         return 0;
684 }
685
686 static int simple_probe(struct platform_device *pdev)
687 {
688         struct simple_priv *priv;
689         struct snd_soc_dai_link *dai_link;
690         struct simple_dai_props *dai_props;
691         struct asoc_simple_dai *dais;
692         struct device *dev = &pdev->dev;
693         struct device_node *np = dev->of_node;
694         struct snd_soc_card *card;
695         struct snd_soc_codec_conf *cconf;
696         struct link_info li;
697         int ret, i;
698
699         /* Allocate the private data and the DAI link array */
700         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
701         if (!priv)
702                 return -ENOMEM;
703
704         card = simple_priv_to_card(priv);
705         card->owner             = THIS_MODULE;
706         card->dev               = dev;
707         card->probe             = simple_soc_probe;
708
709         memset(&li, 0, sizeof(li));
710         simple_get_dais_count(priv, &li);
711         if (!li.link || !li.dais)
712                 return -EINVAL;
713
714         dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL);
715         dai_link  = devm_kcalloc(dev, li.link, sizeof(*dai_link),  GFP_KERNEL);
716         dais      = devm_kcalloc(dev, li.dais, sizeof(*dais),      GFP_KERNEL);
717         cconf     = devm_kcalloc(dev, li.conf, sizeof(*cconf),     GFP_KERNEL);
718         if (!dai_props || !dai_link || !dais)
719                 return -ENOMEM;
720
721         /*
722          * Use snd_soc_dai_link_component instead of legacy style
723          * It is codec only. but cpu/platform will be supported in the future.
724          * see
725          *      soc-core.c :: snd_soc_init_multicodec()
726          */
727         for (i = 0; i < li.link; i++) {
728                 dai_link[i].codecs      = &dai_props[i].codecs;
729                 dai_link[i].num_codecs  = 1;
730                 dai_link[i].platforms   = &dai_props[i].platforms;
731                 dai_link[i].num_platforms = 1;
732         }
733
734         priv->dai_props         = dai_props;
735         priv->dai_link          = dai_link;
736         priv->dais              = dais;
737         priv->codec_conf        = cconf;
738
739         card->dai_link          = priv->dai_link;
740         card->num_links         = li.link;
741         card->codec_conf        = cconf;
742         card->num_configs       = li.conf;
743
744         if (np && of_device_is_available(np)) {
745
746                 ret = simple_parse_of(priv);
747                 if (ret < 0) {
748                         if (ret != -EPROBE_DEFER)
749                                 dev_err(dev, "parse error %d\n", ret);
750                         goto err;
751                 }
752
753         } else {
754                 struct asoc_simple_card_info *cinfo;
755                 struct snd_soc_dai_link_component *codecs;
756                 struct snd_soc_dai_link_component *platform;
757                 int dai_idx = 0;
758
759                 cinfo = dev->platform_data;
760                 if (!cinfo) {
761                         dev_err(dev, "no info for asoc-simple-card\n");
762                         return -EINVAL;
763                 }
764
765                 if (!cinfo->name ||
766                     !cinfo->codec_dai.name ||
767                     !cinfo->codec ||
768                     !cinfo->platform ||
769                     !cinfo->cpu_dai.name) {
770                         dev_err(dev, "insufficient asoc_simple_card_info settings\n");
771                         return -EINVAL;
772                 }
773
774                 dai_props->cpu_dai      = &priv->dais[dai_idx++];
775                 dai_props->codec_dai    = &priv->dais[dai_idx++];
776
777                 codecs                  = dai_link->codecs;
778                 codecs->name            = cinfo->codec;
779                 codecs->dai_name        = cinfo->codec_dai.name;
780
781                 platform                = dai_link->platforms;
782                 platform->name          = cinfo->platform;
783
784                 card->name              = (cinfo->card) ? cinfo->card : cinfo->name;
785                 dai_link->name          = cinfo->name;
786                 dai_link->stream_name   = cinfo->name;
787                 dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
788                 dai_link->dai_fmt       = cinfo->daifmt;
789                 dai_link->init          = simple_dai_init;
790                 memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
791                                         sizeof(*priv->dai_props->cpu_dai));
792                 memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
793                                         sizeof(*priv->dai_props->codec_dai));
794         }
795
796         snd_soc_card_set_drvdata(card, priv);
797
798         ret = devm_snd_soc_register_card(dev, card);
799         if (ret < 0)
800                 goto err;
801
802         return 0;
803 err:
804         asoc_simple_card_clean_reference(card);
805
806         return ret;
807 }
808
809 static int simple_remove(struct platform_device *pdev)
810 {
811         struct snd_soc_card *card = platform_get_drvdata(pdev);
812
813         return asoc_simple_card_clean_reference(card);
814 }
815
816 static const struct of_device_id simple_of_match[] = {
817         { .compatible = "simple-audio-card", },
818         { .compatible = "simple-scu-audio-card", },
819         {},
820 };
821 MODULE_DEVICE_TABLE(of, simple_of_match);
822
823 static struct platform_driver asoc_simple_card = {
824         .driver = {
825                 .name = "asoc-simple-card",
826                 .pm = &snd_soc_pm_ops,
827                 .of_match_table = simple_of_match,
828         },
829         .probe = simple_probe,
830         .remove = simple_remove,
831 };
832
833 module_platform_driver(asoc_simple_card);
834
835 MODULE_ALIAS("platform:asoc-simple-card");
836 MODULE_LICENSE("GPL v2");
837 MODULE_DESCRIPTION("ASoC Simple Sound Card");
838 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");