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