xref: /linux/sound/soc/generic/simple-card.c (revision 869858f84a65b646052eff1ec75c1f49e638b62b)
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 		unsigned int mclk_fs;
26 	} *dai_props;
27 	unsigned int mclk_fs;
28 	struct asoc_simple_jack hp_jack;
29 	struct asoc_simple_jack mic_jack;
30 	struct snd_soc_dai_link *dai_link;
31 	struct asoc_simple_dai *dais;
32 };
33 
34 #define simple_priv_to_card(priv) (&(priv)->snd_card)
35 #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
36 #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
37 #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
38 
39 #define DAI	"sound-dai"
40 #define CELL	"#sound-dai-cells"
41 #define PREFIX	"simple-audio-card,"
42 
43 static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
44 {
45 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
46 	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
47 	struct simple_dai_props *dai_props =
48 		simple_priv_to_props(priv, rtd->num);
49 	int ret;
50 
51 	ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
52 	if (ret)
53 		return ret;
54 
55 	ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
56 	if (ret)
57 		asoc_simple_card_clk_disable(dai_props->cpu_dai);
58 
59 	return ret;
60 }
61 
62 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
63 {
64 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
65 	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
66 	struct simple_dai_props *dai_props =
67 		simple_priv_to_props(priv, rtd->num);
68 
69 	asoc_simple_card_clk_disable(dai_props->cpu_dai);
70 
71 	asoc_simple_card_clk_disable(dai_props->codec_dai);
72 }
73 
74 static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
75 				    unsigned long rate)
76 {
77 	if (!simple_dai->clk)
78 		return 0;
79 
80 	if (clk_get_rate(simple_dai->clk) == rate)
81 		return 0;
82 
83 	return clk_set_rate(simple_dai->clk, rate);
84 }
85 
86 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
87 				      struct snd_pcm_hw_params *params)
88 {
89 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
90 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
91 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
92 	struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
93 	struct simple_dai_props *dai_props =
94 		simple_priv_to_props(priv, rtd->num);
95 	unsigned int mclk, mclk_fs = 0;
96 	int ret = 0;
97 
98 	if (priv->mclk_fs)
99 		mclk_fs = priv->mclk_fs;
100 	else if (dai_props->mclk_fs)
101 		mclk_fs = dai_props->mclk_fs;
102 
103 	if (mclk_fs) {
104 		mclk = params_rate(params) * mclk_fs;
105 
106 		ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
107 		if (ret < 0)
108 			return ret;
109 
110 		ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
111 		if (ret < 0)
112 			return ret;
113 
114 		ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
115 					     SND_SOC_CLOCK_IN);
116 		if (ret && ret != -ENOTSUPP)
117 			goto err;
118 
119 		ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
120 					     SND_SOC_CLOCK_OUT);
121 		if (ret && ret != -ENOTSUPP)
122 			goto err;
123 	}
124 	return 0;
125 err:
126 	return ret;
127 }
128 
129 static const struct snd_soc_ops asoc_simple_card_ops = {
130 	.startup = asoc_simple_card_startup,
131 	.shutdown = asoc_simple_card_shutdown,
132 	.hw_params = asoc_simple_card_hw_params,
133 };
134 
135 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
136 {
137 	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
138 	struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
139 	int ret;
140 
141 	ret = asoc_simple_card_init_dai(rtd->codec_dai,
142 					dai_props->codec_dai);
143 	if (ret < 0)
144 		return ret;
145 
146 	ret = asoc_simple_card_init_dai(rtd->cpu_dai,
147 					dai_props->cpu_dai);
148 	if (ret < 0)
149 		return ret;
150 
151 	return 0;
152 }
153 
154 static int asoc_simple_card_dai_link_of(struct device_node *node,
155 					struct simple_card_data *priv,
156 					int *dai_idx, int link_idx,
157 					bool is_top_level_node)
158 {
159 	struct device *dev = simple_priv_to_dev(priv);
160 	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
161 	struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
162 	struct asoc_simple_dai *cpu_dai;
163 	struct asoc_simple_dai *codec_dai;
164 	struct device_node *cpu = NULL;
165 	struct device_node *plat = NULL;
166 	struct device_node *codec = NULL;
167 	char prop[128];
168 	char *prefix = "";
169 	int ret, single_cpu;
170 
171 	/* For single DAI link & old style of DT node */
172 	if (is_top_level_node)
173 		prefix = PREFIX;
174 
175 	snprintf(prop, sizeof(prop), "%scpu", prefix);
176 	cpu = of_get_child_by_name(node, prop);
177 
178 	if (!cpu) {
179 		ret = -EINVAL;
180 		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
181 		goto dai_link_of_err;
182 	}
183 
184 	snprintf(prop, sizeof(prop), "%splat", prefix);
185 	plat = of_get_child_by_name(node, prop);
186 
187 	snprintf(prop, sizeof(prop), "%scodec", prefix);
188 	codec = of_get_child_by_name(node, prop);
189 
190 	if (!codec) {
191 		ret = -EINVAL;
192 		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
193 		goto dai_link_of_err;
194 	}
195 
196 	cpu_dai			=
197 	dai_props->cpu_dai	= &priv->dais[(*dai_idx)++];
198 	codec_dai		=
199 	dai_props->codec_dai	= &priv->dais[(*dai_idx)++];
200 
201 	ret = asoc_simple_card_parse_daifmt(dev, node, codec,
202 					    prefix, &dai_link->dai_fmt);
203 	if (ret < 0)
204 		goto dai_link_of_err;
205 
206 	of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
207 
208 	ret = asoc_simple_card_parse_cpu(cpu, dai_link,
209 					 DAI, CELL, &single_cpu);
210 	if (ret < 0)
211 		goto dai_link_of_err;
212 
213 	ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
214 	if (ret < 0)
215 		goto dai_link_of_err;
216 
217 	ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
218 	if (ret < 0)
219 		goto dai_link_of_err;
220 
221 	ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
222 	if (ret < 0)
223 		goto dai_link_of_err;
224 
225 	ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
226 	if (ret < 0)
227 		goto dai_link_of_err;
228 
229 	ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
230 	if (ret < 0)
231 		goto dai_link_of_err;
232 
233 	ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
234 	if (ret < 0)
235 		goto dai_link_of_err;
236 
237 	ret = asoc_simple_card_canonicalize_dailink(dai_link);
238 	if (ret < 0)
239 		goto dai_link_of_err;
240 
241 	ret = asoc_simple_card_set_dailink_name(dev, dai_link,
242 						"%s-%s",
243 						dai_link->cpu_dai_name,
244 						dai_link->codecs->dai_name);
245 	if (ret < 0)
246 		goto dai_link_of_err;
247 
248 	dai_link->ops = &asoc_simple_card_ops;
249 	dai_link->init = asoc_simple_card_dai_init;
250 
251 	asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
252 
253 dai_link_of_err:
254 	of_node_put(cpu);
255 	of_node_put(codec);
256 
257 	return ret;
258 }
259 
260 static int asoc_simple_card_parse_aux_devs(struct device_node *node,
261 					   struct simple_card_data *priv)
262 {
263 	struct device *dev = simple_priv_to_dev(priv);
264 	struct device_node *aux_node;
265 	struct snd_soc_card *card = simple_priv_to_card(priv);
266 	int i, n, len;
267 
268 	if (!of_find_property(node, PREFIX "aux-devs", &len))
269 		return 0;		/* Ok to have no aux-devs */
270 
271 	n = len / sizeof(__be32);
272 	if (n <= 0)
273 		return -EINVAL;
274 
275 	card->aux_dev = devm_kcalloc(dev,
276 			n, sizeof(*card->aux_dev), GFP_KERNEL);
277 	if (!card->aux_dev)
278 		return -ENOMEM;
279 
280 	for (i = 0; i < n; i++) {
281 		aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
282 		if (!aux_node)
283 			return -EINVAL;
284 		card->aux_dev[i].codec_of_node = aux_node;
285 	}
286 
287 	card->num_aux_devs = n;
288 	return 0;
289 }
290 
291 static int asoc_simple_card_parse_of(struct simple_card_data *priv)
292 {
293 	struct device *dev = simple_priv_to_dev(priv);
294 	struct snd_soc_card *card = simple_priv_to_card(priv);
295 	struct device_node *dai_link;
296 	struct device_node *node = dev->of_node;
297 	int ret;
298 	int link_idx, dai_idx;
299 
300 	if (!node)
301 		return -EINVAL;
302 
303 	dai_link = of_get_child_by_name(node, PREFIX "dai-link");
304 
305 	ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
306 	if (ret < 0)
307 		goto card_parse_end;
308 
309 	ret = asoc_simple_card_of_parse_routing(card, PREFIX);
310 	if (ret < 0)
311 		goto card_parse_end;
312 
313 	/* Factor to mclk, used in hw_params() */
314 	of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
315 
316 	/* Single/Muti DAI link(s) & New style of DT node */
317 	link_idx = 0;
318 	dai_idx  = 0;
319 	if (dai_link) {
320 		struct device_node *np = NULL;
321 
322 		for_each_child_of_node(node, np) {
323 			dev_dbg(dev, "\tlink %d:\n", link_idx);
324 			ret = asoc_simple_card_dai_link_of(np, priv,
325 						&dai_idx, link_idx++, false);
326 			if (ret < 0) {
327 				of_node_put(np);
328 				goto card_parse_end;
329 			}
330 		}
331 	} else {
332 		/* For single DAI link & old style of DT node */
333 		ret = asoc_simple_card_dai_link_of(node, priv,
334 						&dai_idx, link_idx++, true);
335 		if (ret < 0)
336 			goto card_parse_end;
337 	}
338 
339 	ret = asoc_simple_card_parse_card_name(card, PREFIX);
340 	if (ret < 0)
341 		goto card_parse_end;
342 
343 	ret = asoc_simple_card_parse_aux_devs(node, priv);
344 
345 card_parse_end:
346 	of_node_put(dai_link);
347 
348 	return ret;
349 }
350 
351 static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
352 {
353 	struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
354 	int ret;
355 
356 	ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
357 	if (ret < 0)
358 		return ret;
359 
360 	ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
361 	if (ret < 0)
362 		return ret;
363 
364 	return 0;
365 }
366 
367 static int asoc_simple_card_probe(struct platform_device *pdev)
368 {
369 	struct simple_card_data *priv;
370 	struct snd_soc_dai_link *dai_link;
371 	struct simple_dai_props *dai_props;
372 	struct asoc_simple_dai *dais;
373 	struct device *dev = &pdev->dev;
374 	struct device_node *np = dev->of_node;
375 	struct snd_soc_card *card;
376 	int num, ret, i;
377 
378 	/* Get the number of DAI links */
379 	if (np && of_get_child_by_name(np, PREFIX "dai-link"))
380 		num = of_get_child_count(np);
381 	else
382 		num = 1;
383 
384 	/* Allocate the private data and the DAI link array */
385 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
386 	if (!priv)
387 		return -ENOMEM;
388 
389 	dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
390 	dai_link  = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
391 	dais      = devm_kcalloc(dev, num * 2, sizeof(*dais),      GFP_KERNEL);
392 	if (!dai_props || !dai_link || !dais)
393 		return -ENOMEM;
394 
395 	/*
396 	 * Use snd_soc_dai_link_component instead of legacy style
397 	 * It is codec only. but cpu/platform will be supported in the future.
398 	 * see
399 	 *	soc-core.c :: snd_soc_init_multicodec()
400 	 */
401 	for (i = 0; i < num; i++) {
402 		dai_link[i].codecs	= &dai_props[i].codecs;
403 		dai_link[i].num_codecs	= 1;
404 		dai_link[i].platform	= &dai_props[i].platform;
405 	}
406 
407 	priv->dai_props			= dai_props;
408 	priv->dai_link			= dai_link;
409 	priv->dais			= dais;
410 
411 	/* Init snd_soc_card */
412 	card = simple_priv_to_card(priv);
413 	card->owner		= THIS_MODULE;
414 	card->dev		= dev;
415 	card->dai_link		= priv->dai_link;
416 	card->num_links		= num;
417 	card->probe		= asoc_simple_soc_card_probe;
418 
419 	if (np && of_device_is_available(np)) {
420 
421 		ret = asoc_simple_card_parse_of(priv);
422 		if (ret < 0) {
423 			if (ret != -EPROBE_DEFER)
424 				dev_err(dev, "parse error %d\n", ret);
425 			goto err;
426 		}
427 
428 	} else {
429 		struct asoc_simple_card_info *cinfo;
430 		struct snd_soc_dai_link_component *codecs;
431 		struct snd_soc_dai_link_component *platform;
432 		int dai_idx = 0;
433 
434 		cinfo = dev->platform_data;
435 		if (!cinfo) {
436 			dev_err(dev, "no info for asoc-simple-card\n");
437 			return -EINVAL;
438 		}
439 
440 		if (!cinfo->name ||
441 		    !cinfo->codec_dai.name ||
442 		    !cinfo->codec ||
443 		    !cinfo->platform ||
444 		    !cinfo->cpu_dai.name) {
445 			dev_err(dev, "insufficient asoc_simple_card_info settings\n");
446 			return -EINVAL;
447 		}
448 
449 		dai_props->cpu_dai	= &priv->dais[dai_idx++];
450 		dai_props->codec_dai	= &priv->dais[dai_idx++];
451 
452 		codecs			= dai_link->codecs;
453 		codecs->name		= cinfo->codec;
454 		codecs->dai_name	= cinfo->codec_dai.name;
455 
456 		platform		= dai_link->platform;
457 		platform->name		= cinfo->platform;
458 
459 		card->name		= (cinfo->card) ? cinfo->card : cinfo->name;
460 		dai_link->name		= cinfo->name;
461 		dai_link->stream_name	= cinfo->name;
462 		dai_link->cpu_dai_name	= cinfo->cpu_dai.name;
463 		dai_link->dai_fmt	= cinfo->daifmt;
464 		dai_link->init		= asoc_simple_card_dai_init;
465 		memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
466 					sizeof(*priv->dai_props->cpu_dai));
467 		memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
468 					sizeof(*priv->dai_props->codec_dai));
469 	}
470 
471 	snd_soc_card_set_drvdata(card, priv);
472 
473 	ret = devm_snd_soc_register_card(dev, card);
474 	if (ret < 0)
475 		goto err;
476 
477 	return 0;
478 err:
479 	asoc_simple_card_clean_reference(card);
480 
481 	return ret;
482 }
483 
484 static int asoc_simple_card_remove(struct platform_device *pdev)
485 {
486 	struct snd_soc_card *card = platform_get_drvdata(pdev);
487 
488 	return asoc_simple_card_clean_reference(card);
489 }
490 
491 static const struct of_device_id asoc_simple_of_match[] = {
492 	{ .compatible = "simple-audio-card", },
493 	{},
494 };
495 MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
496 
497 static struct platform_driver asoc_simple_card = {
498 	.driver = {
499 		.name = "asoc-simple-card",
500 		.pm = &snd_soc_pm_ops,
501 		.of_match_table = asoc_simple_of_match,
502 	},
503 	.probe = asoc_simple_card_probe,
504 	.remove = asoc_simple_card_remove,
505 };
506 
507 module_platform_driver(asoc_simple_card);
508 
509 MODULE_ALIAS("platform:asoc-simple-card");
510 MODULE_LICENSE("GPL v2");
511 MODULE_DESCRIPTION("ASoC Simple Sound Card");
512 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
513