simple-card.c (869858f84a65b646052eff1ec75c1f49e638b62b) simple-card.c (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>

--- 8 unchanged lines hidden (view full) ---

17
18struct 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;
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>

--- 8 unchanged lines hidden (view full) ---

17
18struct 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;
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;
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;
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"

--- 29 unchanged lines hidden (view full) ---

69 asoc_simple_card_clk_disable(dai_props->cpu_dai);
70
71 asoc_simple_card_clk_disable(dai_props->codec_dai);
72}
73
74static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
75 unsigned long rate)
76{
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"

--- 29 unchanged lines hidden (view full) ---

73 asoc_simple_card_clk_disable(dai_props->cpu_dai);
74
75 asoc_simple_card_clk_disable(dai_props->codec_dai);
76}
77
78static 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
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}

--- 61 unchanged lines hidden (view full) ---

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
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}

--- 61 unchanged lines hidden (view full) ---

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
161static 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
175static 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
154static 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);

--- 124 unchanged lines hidden (view full) ---

286
287 card->num_aux_devs = n;
288 return 0;
289}
290
291static int asoc_simple_card_parse_of(struct simple_card_data *priv)
292{
293 struct device *dev = simple_priv_to_dev(priv);
296static 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);

--- 124 unchanged lines hidden (view full) ---

428
429 card->num_aux_devs = n;
430 return 0;
431}
432
433static 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;
294 struct snd_soc_card *card = simple_priv_to_card(priv);
437 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;
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;
299
444
300 if (!node)
445 if (!top)
301 return -EINVAL;
302
446 return -EINVAL;
447
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)
448 ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
449 if (ret < 0)
307 goto card_parse_end;
450 return ret;
308
309 ret = asoc_simple_card_of_parse_routing(card, PREFIX);
310 if (ret < 0)
451
452 ret = asoc_simple_card_of_parse_routing(card, PREFIX);
453 if (ret < 0)
311 goto card_parse_end;
454 return ret;
312
313 /* Factor to mclk, used in hw_params() */
455
456 /* Factor to mclk, used in hw_params() */
314 of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
457 of_property_read_u32(top, PREFIX "mclk-fs", &priv->mclk_fs);
315
458
459 asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
460
316 /* Single/Muti DAI link(s) & New style of DT node */
461 /* 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;
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 }
321
471
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;
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);
329 }
488 }
489 } else {
490 ret = asoc_simple_card_dai_link_of(
491 node, priv,
492 &dai_idx, link_idx++, !loop);
330 }
493 }
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)
494 if (ret < 0)
336 goto card_parse_end;
337 }
495 return ret;
338
496
497 node = of_get_next_child(top, node);
498 } while (loop && node);
499
339 ret = asoc_simple_card_parse_card_name(card, PREFIX);
340 if (ret < 0)
500 ret = asoc_simple_card_parse_card_name(card, PREFIX);
501 if (ret < 0)
341 goto card_parse_end;
502 return ret;
342
503
343 ret = asoc_simple_card_parse_aux_devs(node, priv);
504 ret = asoc_simple_card_parse_aux_devs(top, priv);
344
505
345card_parse_end:
346 of_node_put(dai_link);
347
348 return ret;
349}
350
506 return ret;
507}
508
509static 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
351static 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;

--- 9 unchanged lines hidden (view full) ---

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;
583static 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;

--- 9 unchanged lines hidden (view full) ---

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;
376 int num, ret, i;
608 struct snd_soc_codec_conf *cconf;
609 int lnum = 0, dnum = 0, cnum = 0;
610 int ret, i;
377
611
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
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
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);
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);
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 */
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 */
401 for (i = 0; i < num; i++) {
634 for (i = 0; i < lnum; 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;
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;
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;
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;
416 card->num_links = num;
650 card->num_links = lnum;
651 card->codec_conf = cconf;
652 card->num_configs = cnum;
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);

--- 60 unchanged lines hidden (view full) ---

485{
486 struct snd_soc_card *card = platform_get_drvdata(pdev);
487
488 return asoc_simple_card_clean_reference(card);
489}
490
491static const struct of_device_id asoc_simple_of_match[] = {
492 { .compatible = "simple-audio-card", },
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);

--- 60 unchanged lines hidden (view full) ---

721{
722 struct snd_soc_card *card = platform_get_drvdata(pdev);
723
724 return asoc_simple_card_clean_reference(card);
725}
726
727static const struct of_device_id asoc_simple_of_match[] = {
728 { .compatible = "simple-audio-card", },
729 { .compatible = "simple-scu-audio-card", },
493 {},
494};
495MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
496
497static struct platform_driver asoc_simple_card = {
498 .driver = {
499 .name = "asoc-simple-card",
500 .pm = &snd_soc_pm_ops,

--- 12 unchanged lines hidden ---
730 {},
731};
732MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
733
734static struct platform_driver asoc_simple_card = {
735 .driver = {
736 .name = "asoc-simple-card",
737 .pm = &snd_soc_pm_ops,

--- 12 unchanged lines hidden ---