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