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