xref: /openbmc/linux/sound/soc/generic/simple-card.c (revision d003d772)
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>");
852