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 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; 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" 44 #define CELL "#sound-dai-cells" 45 #define PREFIX "simple-audio-card," 46 47 static int asoc_simple_card_startup(struct snd_pcm_substream *substream) 48 { 49 struct snd_soc_pcm_runtime *rtd = substream->private_data; 50 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 51 struct simple_dai_props *dai_props = 52 simple_priv_to_props(priv, rtd->num); 53 int ret; 54 55 ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); 56 if (ret) 57 return ret; 58 59 ret = asoc_simple_card_clk_enable(dai_props->codec_dai); 60 if (ret) 61 asoc_simple_card_clk_disable(dai_props->cpu_dai); 62 63 return ret; 64 } 65 66 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) 67 { 68 struct snd_soc_pcm_runtime *rtd = substream->private_data; 69 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 70 struct simple_dai_props *dai_props = 71 simple_priv_to_props(priv, rtd->num); 72 73 asoc_simple_card_clk_disable(dai_props->cpu_dai); 74 75 asoc_simple_card_clk_disable(dai_props->codec_dai); 76 } 77 78 static 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 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 } 92 93 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, 94 struct snd_pcm_hw_params *params) 95 { 96 struct snd_soc_pcm_runtime *rtd = substream->private_data; 97 struct snd_soc_dai *codec_dai = rtd->codec_dai; 98 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 99 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 100 struct simple_dai_props *dai_props = 101 simple_priv_to_props(priv, rtd->num); 102 unsigned int mclk, mclk_fs = 0; 103 int ret = 0; 104 105 if (priv->mclk_fs) 106 mclk_fs = priv->mclk_fs; 107 else if (dai_props->mclk_fs) 108 mclk_fs = dai_props->mclk_fs; 109 110 if (mclk_fs) { 111 mclk = params_rate(params) * mclk_fs; 112 113 ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk); 114 if (ret < 0) 115 return ret; 116 117 ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk); 118 if (ret < 0) 119 return ret; 120 121 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 122 SND_SOC_CLOCK_IN); 123 if (ret && ret != -ENOTSUPP) 124 goto err; 125 126 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, 127 SND_SOC_CLOCK_OUT); 128 if (ret && ret != -ENOTSUPP) 129 goto err; 130 } 131 return 0; 132 err: 133 return ret; 134 } 135 136 static const struct snd_soc_ops asoc_simple_card_ops = { 137 .startup = asoc_simple_card_startup, 138 .shutdown = asoc_simple_card_shutdown, 139 .hw_params = asoc_simple_card_hw_params, 140 }; 141 142 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) 143 { 144 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 145 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); 146 int ret; 147 148 ret = asoc_simple_card_init_dai(rtd->codec_dai, 149 dai_props->codec_dai); 150 if (ret < 0) 151 return ret; 152 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 161 static 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 175 static 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 296 static 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); 304 struct asoc_simple_dai *cpu_dai; 305 struct asoc_simple_dai *codec_dai; 306 struct device_node *cpu = NULL; 307 struct device_node *plat = NULL; 308 struct device_node *codec = NULL; 309 char prop[128]; 310 char *prefix = ""; 311 int ret, single_cpu; 312 313 /* For single DAI link & old style of DT node */ 314 if (is_top_level_node) 315 prefix = PREFIX; 316 317 snprintf(prop, sizeof(prop), "%scpu", prefix); 318 cpu = of_get_child_by_name(node, prop); 319 320 if (!cpu) { 321 ret = -EINVAL; 322 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 323 goto dai_link_of_err; 324 } 325 326 snprintf(prop, sizeof(prop), "%splat", prefix); 327 plat = of_get_child_by_name(node, prop); 328 329 snprintf(prop, sizeof(prop), "%scodec", prefix); 330 codec = of_get_child_by_name(node, prop); 331 332 if (!codec) { 333 ret = -EINVAL; 334 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 335 goto dai_link_of_err; 336 } 337 338 cpu_dai = 339 dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; 340 codec_dai = 341 dai_props->codec_dai = &priv->dais[(*dai_idx)++]; 342 343 ret = asoc_simple_card_parse_daifmt(dev, node, codec, 344 prefix, &dai_link->dai_fmt); 345 if (ret < 0) 346 goto dai_link_of_err; 347 348 of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); 349 350 ret = asoc_simple_card_parse_cpu(cpu, dai_link, 351 DAI, CELL, &single_cpu); 352 if (ret < 0) 353 goto dai_link_of_err; 354 355 ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL); 356 if (ret < 0) 357 goto dai_link_of_err; 358 359 ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL); 360 if (ret < 0) 361 goto dai_link_of_err; 362 363 ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai); 364 if (ret < 0) 365 goto dai_link_of_err; 366 367 ret = asoc_simple_card_of_parse_tdm(codec, codec_dai); 368 if (ret < 0) 369 goto dai_link_of_err; 370 371 ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai); 372 if (ret < 0) 373 goto dai_link_of_err; 374 375 ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai); 376 if (ret < 0) 377 goto dai_link_of_err; 378 379 ret = asoc_simple_card_canonicalize_dailink(dai_link); 380 if (ret < 0) 381 goto dai_link_of_err; 382 383 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 384 "%s-%s", 385 dai_link->cpu_dai_name, 386 dai_link->codecs->dai_name); 387 if (ret < 0) 388 goto dai_link_of_err; 389 390 dai_link->ops = &asoc_simple_card_ops; 391 dai_link->init = asoc_simple_card_dai_init; 392 393 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); 394 395 dai_link_of_err: 396 of_node_put(cpu); 397 of_node_put(codec); 398 399 return ret; 400 } 401 402 static int asoc_simple_card_parse_aux_devs(struct device_node *node, 403 struct simple_card_data *priv) 404 { 405 struct device *dev = simple_priv_to_dev(priv); 406 struct device_node *aux_node; 407 struct snd_soc_card *card = simple_priv_to_card(priv); 408 int i, n, len; 409 410 if (!of_find_property(node, PREFIX "aux-devs", &len)) 411 return 0; /* Ok to have no aux-devs */ 412 413 n = len / sizeof(__be32); 414 if (n <= 0) 415 return -EINVAL; 416 417 card->aux_dev = devm_kcalloc(dev, 418 n, sizeof(*card->aux_dev), GFP_KERNEL); 419 if (!card->aux_dev) 420 return -ENOMEM; 421 422 for (i = 0; i < n; i++) { 423 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); 424 if (!aux_node) 425 return -EINVAL; 426 card->aux_dev[i].codec_of_node = aux_node; 427 } 428 429 card->num_aux_devs = n; 430 return 0; 431 } 432 433 static 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; 437 struct snd_soc_card *card = simple_priv_to_card(priv); 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; 444 445 if (!top) 446 return -EINVAL; 447 448 ret = asoc_simple_card_of_parse_widgets(card, PREFIX); 449 if (ret < 0) 450 return ret; 451 452 ret = asoc_simple_card_of_parse_routing(card, PREFIX); 453 if (ret < 0) 454 return ret; 455 456 /* Factor to mclk, used in hw_params() */ 457 of_property_read_u32(top, PREFIX "mclk-fs", &priv->mclk_fs); 458 459 asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata); 460 461 /* Single/Muti DAI link(s) & New style of DT node */ 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 } 471 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); 488 } 489 } else { 490 ret = asoc_simple_card_dai_link_of( 491 node, priv, 492 &dai_idx, link_idx++, !loop); 493 } 494 if (ret < 0) 495 return ret; 496 497 node = of_get_next_child(top, node); 498 } while (loop && node); 499 500 ret = asoc_simple_card_parse_card_name(card, PREFIX); 501 if (ret < 0) 502 return ret; 503 504 ret = asoc_simple_card_parse_aux_devs(top, priv); 505 506 return ret; 507 } 508 509 static 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 583 static 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; 591 592 ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX); 593 if (ret < 0) 594 return ret; 595 596 return 0; 597 } 598 599 static int asoc_simple_card_probe(struct platform_device *pdev) 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; 608 struct snd_soc_codec_conf *cconf; 609 int lnum = 0, dnum = 0, cnum = 0; 610 int ret, i; 611 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 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); 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 */ 634 for (i = 0; i < lnum; i++) { 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; 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; 650 card->num_links = lnum; 651 card->codec_conf = cconf; 652 card->num_configs = cnum; 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); 661 goto err; 662 } 663 664 } else { 665 struct asoc_simple_card_info *cinfo; 666 struct snd_soc_dai_link_component *codecs; 667 struct snd_soc_dai_link_component *platform; 668 int dai_idx = 0; 669 670 cinfo = dev->platform_data; 671 if (!cinfo) { 672 dev_err(dev, "no info for asoc-simple-card\n"); 673 return -EINVAL; 674 } 675 676 if (!cinfo->name || 677 !cinfo->codec_dai.name || 678 !cinfo->codec || 679 !cinfo->platform || 680 !cinfo->cpu_dai.name) { 681 dev_err(dev, "insufficient asoc_simple_card_info settings\n"); 682 return -EINVAL; 683 } 684 685 dai_props->cpu_dai = &priv->dais[dai_idx++]; 686 dai_props->codec_dai = &priv->dais[dai_idx++]; 687 688 codecs = dai_link->codecs; 689 codecs->name = cinfo->codec; 690 codecs->dai_name = cinfo->codec_dai.name; 691 692 platform = dai_link->platform; 693 platform->name = cinfo->platform; 694 695 card->name = (cinfo->card) ? cinfo->card : cinfo->name; 696 dai_link->name = cinfo->name; 697 dai_link->stream_name = cinfo->name; 698 dai_link->cpu_dai_name = cinfo->cpu_dai.name; 699 dai_link->dai_fmt = cinfo->daifmt; 700 dai_link->init = asoc_simple_card_dai_init; 701 memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai, 702 sizeof(*priv->dai_props->cpu_dai)); 703 memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai, 704 sizeof(*priv->dai_props->codec_dai)); 705 } 706 707 snd_soc_card_set_drvdata(card, priv); 708 709 ret = devm_snd_soc_register_card(dev, card); 710 if (ret < 0) 711 goto err; 712 713 return 0; 714 err: 715 asoc_simple_card_clean_reference(card); 716 717 return ret; 718 } 719 720 static int asoc_simple_card_remove(struct platform_device *pdev) 721 { 722 struct snd_soc_card *card = platform_get_drvdata(pdev); 723 724 return asoc_simple_card_clean_reference(card); 725 } 726 727 static const struct of_device_id asoc_simple_of_match[] = { 728 { .compatible = "simple-audio-card", }, 729 { .compatible = "simple-scu-audio-card", }, 730 {}, 731 }; 732 MODULE_DEVICE_TABLE(of, asoc_simple_of_match); 733 734 static struct platform_driver asoc_simple_card = { 735 .driver = { 736 .name = "asoc-simple-card", 737 .pm = &snd_soc_pm_ops, 738 .of_match_table = asoc_simple_of_match, 739 }, 740 .probe = asoc_simple_card_probe, 741 .remove = asoc_simple_card_remove, 742 }; 743 744 module_platform_driver(asoc_simple_card); 745 746 MODULE_ALIAS("platform:asoc-simple-card"); 747 MODULE_LICENSE("GPL v2"); 748 MODULE_DESCRIPTION("ASoC Simple Sound Card"); 749 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 750