xref: /linux/sound/soc/generic/simple-card.c (revision 1f2367a39f17bd553a75e179a747f9b257bc9478)
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(plat);
425 	of_node_put(node);
426 
427 	return ret;
428 }
429 
430 static int simple_for_each_link(struct simple_priv *priv,
431 			struct link_info *li,
432 			int (*func_noml)(struct simple_priv *priv,
433 					 struct device_node *np,
434 					 struct device_node *codec,
435 					 struct link_info *li, bool is_top),
436 			int (*func_dpcm)(struct simple_priv *priv,
437 					 struct device_node *np,
438 					 struct device_node *codec,
439 					 struct link_info *li, bool is_top))
440 {
441 	struct device *dev = simple_priv_to_dev(priv);
442 	struct device_node *top = dev->of_node;
443 	struct device_node *node;
444 	bool is_top = 0;
445 	int ret = 0;
446 
447 	/* Check if it has dai-link */
448 	node = of_get_child_by_name(top, PREFIX "dai-link");
449 	if (!node) {
450 		node = of_node_get(top);
451 		is_top = 1;
452 	}
453 
454 	/* loop for all dai-link */
455 	do {
456 		struct asoc_simple_card_data adata;
457 		struct device_node *codec;
458 		struct device_node *np;
459 		int num = of_get_child_count(node);
460 
461 		/* get codec */
462 		codec = of_get_child_by_name(node, is_top ?
463 					     PREFIX "codec" : "codec");
464 		if (!codec) {
465 			ret = -ENODEV;
466 			goto error;
467 		}
468 
469 		of_node_put(codec);
470 
471 		/* get convert-xxx property */
472 		memset(&adata, 0, sizeof(adata));
473 		for_each_child_of_node(node, np)
474 			simple_get_conversion(dev, np, &adata);
475 
476 		/* loop for all CPU/Codec node */
477 		for_each_child_of_node(node, np) {
478 			/*
479 			 * It is DPCM
480 			 * if it has many CPUs,
481 			 * or has convert-xxx property
482 			 */
483 			if (num > 2 ||
484 			    adata.convert_rate || adata.convert_channels)
485 				ret = func_dpcm(priv, np, codec, li, is_top);
486 			/* else normal sound */
487 			else
488 				ret = func_noml(priv, np, codec, li, is_top);
489 
490 			if (ret < 0) {
491 				of_node_put(np);
492 				goto error;
493 			}
494 		}
495 
496 		node = of_get_next_child(top, node);
497 	} while (!is_top && node);
498 
499  error:
500 	of_node_put(node);
501 	return ret;
502 }
503 
504 static int simple_parse_aux_devs(struct device_node *node,
505 				 struct simple_priv *priv)
506 {
507 	struct device *dev = simple_priv_to_dev(priv);
508 	struct device_node *aux_node;
509 	struct snd_soc_card *card = simple_priv_to_card(priv);
510 	int i, n, len;
511 
512 	if (!of_find_property(node, PREFIX "aux-devs", &len))
513 		return 0;		/* Ok to have no aux-devs */
514 
515 	n = len / sizeof(__be32);
516 	if (n <= 0)
517 		return -EINVAL;
518 
519 	card->aux_dev = devm_kcalloc(dev,
520 			n, sizeof(*card->aux_dev), GFP_KERNEL);
521 	if (!card->aux_dev)
522 		return -ENOMEM;
523 
524 	for (i = 0; i < n; i++) {
525 		aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
526 		if (!aux_node)
527 			return -EINVAL;
528 		card->aux_dev[i].codec_of_node = aux_node;
529 	}
530 
531 	card->num_aux_devs = n;
532 	return 0;
533 }
534 
535 static int simple_parse_of(struct simple_priv *priv)
536 {
537 	struct device *dev = simple_priv_to_dev(priv);
538 	struct device_node *top = dev->of_node;
539 	struct snd_soc_card *card = simple_priv_to_card(priv);
540 	struct link_info li;
541 	int ret;
542 
543 	if (!top)
544 		return -EINVAL;
545 
546 	ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
547 	if (ret < 0)
548 		return ret;
549 
550 	ret = asoc_simple_card_of_parse_routing(card, PREFIX);
551 	if (ret < 0)
552 		return ret;
553 
554 	/* Single/Muti DAI link(s) & New style of DT node */
555 	memset(&li, 0, sizeof(li));
556 	for (li.cpu = 1; li.cpu >= 0; li.cpu--) {
557 		/*
558 		 * Detect all CPU first, and Detect all Codec 2nd.
559 		 *
560 		 * In Normal sound case, all DAIs are detected
561 		 * as "CPU-Codec".
562 		 *
563 		 * In DPCM sound case,
564 		 * all CPUs   are detected as "CPU-dummy", and
565 		 * all Codecs are detected as "dummy-Codec".
566 		 * To avoid random sub-device numbering,
567 		 * detect "dummy-Codec" in last;
568 		 */
569 		ret = simple_for_each_link(priv, &li,
570 					   simple_dai_link_of,
571 					   simple_dai_link_of_dpcm);
572 		if (ret < 0)
573 			return ret;
574 	}
575 
576 	ret = asoc_simple_card_parse_card_name(card, PREFIX);
577 	if (ret < 0)
578 		return ret;
579 
580 	ret = simple_parse_aux_devs(top, priv);
581 
582 	return ret;
583 }
584 
585 static int simple_count_noml(struct simple_priv *priv,
586 			     struct device_node *np,
587 			     struct device_node *codec,
588 			     struct link_info *li, bool is_top)
589 {
590 	li->dais++; /* CPU or Codec */
591 	if (np != codec)
592 		li->link++; /* CPU-Codec */
593 
594 	return 0;
595 }
596 
597 static int simple_count_dpcm(struct simple_priv *priv,
598 			     struct device_node *np,
599 			     struct device_node *codec,
600 			     struct link_info *li, bool is_top)
601 {
602 	li->dais++; /* CPU or Codec */
603 	li->link++; /* CPU-dummy or dummy-Codec */
604 	if (np == codec)
605 		li->conf++;
606 
607 	return 0;
608 }
609 
610 static void simple_get_dais_count(struct simple_priv *priv,
611 				  struct link_info *li)
612 {
613 	struct device *dev = simple_priv_to_dev(priv);
614 	struct device_node *top = dev->of_node;
615 
616 	/*
617 	 * link_num :	number of links.
618 	 *		CPU-Codec / CPU-dummy / dummy-Codec
619 	 * dais_num :	number of DAIs
620 	 * ccnf_num :	number of codec_conf
621 	 *		same number for "dummy-Codec"
622 	 *
623 	 * ex1)
624 	 * CPU0 --- Codec0	link : 5
625 	 * CPU1 --- Codec1	dais : 7
626 	 * CPU2 -/		ccnf : 1
627 	 * CPU3 --- Codec2
628 	 *
629 	 *	=> 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
630 	 *	=> 7 DAIs  = 4xCPU + 3xCodec
631 	 *	=> 1 ccnf  = 1xdummy-Codec
632 	 *
633 	 * ex2)
634 	 * CPU0 --- Codec0	link : 5
635 	 * CPU1 --- Codec1	dais : 6
636 	 * CPU2 -/		ccnf : 1
637 	 * CPU3 -/
638 	 *
639 	 *	=> 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
640 	 *	=> 6 DAIs  = 4xCPU + 2xCodec
641 	 *	=> 1 ccnf  = 1xdummy-Codec
642 	 *
643 	 * ex3)
644 	 * CPU0 --- Codec0	link : 6
645 	 * CPU1 -/		dais : 6
646 	 * CPU2 --- Codec1	ccnf : 2
647 	 * CPU3 -/
648 	 *
649 	 *	=> 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
650 	 *	=> 6 DAIs  = 4xCPU + 2xCodec
651 	 *	=> 2 ccnf  = 2xdummy-Codec
652 	 *
653 	 * ex4)
654 	 * CPU0 --- Codec0 (convert-rate)	link : 3
655 	 * CPU1 --- Codec1			dais : 4
656 	 *					ccnf : 1
657 	 *
658 	 *	=> 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
659 	 *	=> 4 DAIs  = 2xCPU + 2xCodec
660 	 *	=> 1 ccnf  = 1xdummy-Codec
661 	 */
662 	if (!top) {
663 		li->link = 1;
664 		li->dais = 2;
665 		li->conf = 0;
666 		return;
667 	}
668 
669 	simple_for_each_link(priv, li,
670 			     simple_count_noml,
671 			     simple_count_dpcm);
672 
673 	dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
674 		li->link, li->dais, li->conf);
675 }
676 
677 static int simple_soc_probe(struct snd_soc_card *card)
678 {
679 	struct simple_priv *priv = snd_soc_card_get_drvdata(card);
680 	int ret;
681 
682 	ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
683 	if (ret < 0)
684 		return ret;
685 
686 	ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
687 	if (ret < 0)
688 		return ret;
689 
690 	return 0;
691 }
692 
693 static int simple_probe(struct platform_device *pdev)
694 {
695 	struct simple_priv *priv;
696 	struct snd_soc_dai_link *dai_link;
697 	struct simple_dai_props *dai_props;
698 	struct asoc_simple_dai *dais;
699 	struct device *dev = &pdev->dev;
700 	struct device_node *np = dev->of_node;
701 	struct snd_soc_card *card;
702 	struct snd_soc_codec_conf *cconf;
703 	struct link_info li;
704 	int ret, i;
705 
706 	/* Allocate the private data and the DAI link array */
707 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
708 	if (!priv)
709 		return -ENOMEM;
710 
711 	card = simple_priv_to_card(priv);
712 	card->owner		= THIS_MODULE;
713 	card->dev		= dev;
714 	card->probe		= simple_soc_probe;
715 
716 	memset(&li, 0, sizeof(li));
717 	simple_get_dais_count(priv, &li);
718 	if (!li.link || !li.dais)
719 		return -EINVAL;
720 
721 	dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL);
722 	dai_link  = devm_kcalloc(dev, li.link, sizeof(*dai_link),  GFP_KERNEL);
723 	dais      = devm_kcalloc(dev, li.dais, sizeof(*dais),      GFP_KERNEL);
724 	cconf     = devm_kcalloc(dev, li.conf, sizeof(*cconf),     GFP_KERNEL);
725 	if (!dai_props || !dai_link || !dais)
726 		return -ENOMEM;
727 
728 	/*
729 	 * Use snd_soc_dai_link_component instead of legacy style
730 	 * It is codec only. but cpu/platform will be supported in the future.
731 	 * see
732 	 *	soc-core.c :: snd_soc_init_multicodec()
733 	 */
734 	for (i = 0; i < li.link; i++) {
735 		dai_link[i].codecs	= &dai_props[i].codecs;
736 		dai_link[i].num_codecs	= 1;
737 		dai_link[i].platforms	= &dai_props[i].platforms;
738 		dai_link[i].num_platforms = 1;
739 	}
740 
741 	priv->dai_props		= dai_props;
742 	priv->dai_link		= dai_link;
743 	priv->dais		= dais;
744 	priv->codec_conf	= cconf;
745 
746 	card->dai_link		= priv->dai_link;
747 	card->num_links		= li.link;
748 	card->codec_conf	= cconf;
749 	card->num_configs	= li.conf;
750 
751 	if (np && of_device_is_available(np)) {
752 
753 		ret = simple_parse_of(priv);
754 		if (ret < 0) {
755 			if (ret != -EPROBE_DEFER)
756 				dev_err(dev, "parse error %d\n", ret);
757 			goto err;
758 		}
759 
760 	} else {
761 		struct asoc_simple_card_info *cinfo;
762 		struct snd_soc_dai_link_component *codecs;
763 		struct snd_soc_dai_link_component *platform;
764 		int dai_idx = 0;
765 
766 		cinfo = dev->platform_data;
767 		if (!cinfo) {
768 			dev_err(dev, "no info for asoc-simple-card\n");
769 			return -EINVAL;
770 		}
771 
772 		if (!cinfo->name ||
773 		    !cinfo->codec_dai.name ||
774 		    !cinfo->codec ||
775 		    !cinfo->platform ||
776 		    !cinfo->cpu_dai.name) {
777 			dev_err(dev, "insufficient asoc_simple_card_info settings\n");
778 			return -EINVAL;
779 		}
780 
781 		dai_props->cpu_dai	= &priv->dais[dai_idx++];
782 		dai_props->codec_dai	= &priv->dais[dai_idx++];
783 
784 		codecs			= dai_link->codecs;
785 		codecs->name		= cinfo->codec;
786 		codecs->dai_name	= cinfo->codec_dai.name;
787 
788 		platform		= dai_link->platforms;
789 		platform->name		= cinfo->platform;
790 
791 		card->name		= (cinfo->card) ? cinfo->card : cinfo->name;
792 		dai_link->name		= cinfo->name;
793 		dai_link->stream_name	= cinfo->name;
794 		dai_link->cpu_dai_name	= cinfo->cpu_dai.name;
795 		dai_link->dai_fmt	= cinfo->daifmt;
796 		dai_link->init		= simple_dai_init;
797 		memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
798 					sizeof(*priv->dai_props->cpu_dai));
799 		memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
800 					sizeof(*priv->dai_props->codec_dai));
801 	}
802 
803 	snd_soc_card_set_drvdata(card, priv);
804 
805 	ret = devm_snd_soc_register_card(dev, card);
806 	if (ret < 0)
807 		goto err;
808 
809 	return 0;
810 err:
811 	asoc_simple_card_clean_reference(card);
812 
813 	return ret;
814 }
815 
816 static int simple_remove(struct platform_device *pdev)
817 {
818 	struct snd_soc_card *card = platform_get_drvdata(pdev);
819 
820 	return asoc_simple_card_clean_reference(card);
821 }
822 
823 static const struct of_device_id simple_of_match[] = {
824 	{ .compatible = "simple-audio-card", },
825 	{ .compatible = "simple-scu-audio-card", },
826 	{},
827 };
828 MODULE_DEVICE_TABLE(of, simple_of_match);
829 
830 static struct platform_driver asoc_simple_card = {
831 	.driver = {
832 		.name = "asoc-simple-card",
833 		.pm = &snd_soc_pm_ops,
834 		.of_match_table = simple_of_match,
835 	},
836 	.probe = simple_probe,
837 	.remove = simple_remove,
838 };
839 
840 module_platform_driver(asoc_simple_card);
841 
842 MODULE_ALIAS("platform:asoc-simple-card");
843 MODULE_LICENSE("GPL v2");
844 MODULE_DESCRIPTION("ASoC Simple Sound Card");
845 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
846