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