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