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 struct asoc_simple_jack hp_jack; 30 struct asoc_simple_jack mic_jack; 31 struct snd_soc_dai_link *dai_link; 32 struct asoc_simple_dai *dais; 33 struct snd_soc_codec_conf *codec_conf; 34 }; 35 36 #define simple_priv_to_card(priv) (&(priv)->snd_card) 37 #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) 38 #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) 39 #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) 40 41 #define DAI "sound-dai" 42 #define CELL "#sound-dai-cells" 43 #define PREFIX "simple-audio-card," 44 45 static int asoc_simple_card_startup(struct snd_pcm_substream *substream) 46 { 47 struct snd_soc_pcm_runtime *rtd = substream->private_data; 48 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 49 struct simple_dai_props *dai_props = 50 simple_priv_to_props(priv, rtd->num); 51 int ret; 52 53 ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); 54 if (ret) 55 return ret; 56 57 ret = asoc_simple_card_clk_enable(dai_props->codec_dai); 58 if (ret) 59 asoc_simple_card_clk_disable(dai_props->cpu_dai); 60 61 return ret; 62 } 63 64 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) 65 { 66 struct snd_soc_pcm_runtime *rtd = substream->private_data; 67 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 68 struct simple_dai_props *dai_props = 69 simple_priv_to_props(priv, rtd->num); 70 71 asoc_simple_card_clk_disable(dai_props->cpu_dai); 72 73 asoc_simple_card_clk_disable(dai_props->codec_dai); 74 } 75 76 static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, 77 unsigned long rate) 78 { 79 if (!simple_dai) 80 return 0; 81 82 if (!simple_dai->clk) 83 return 0; 84 85 if (clk_get_rate(simple_dai->clk) == rate) 86 return 0; 87 88 return clk_set_rate(simple_dai->clk, rate); 89 } 90 91 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, 92 struct snd_pcm_hw_params *params) 93 { 94 struct snd_soc_pcm_runtime *rtd = substream->private_data; 95 struct snd_soc_dai *codec_dai = rtd->codec_dai; 96 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 97 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 98 struct simple_dai_props *dai_props = 99 simple_priv_to_props(priv, rtd->num); 100 unsigned int mclk, mclk_fs = 0; 101 int ret = 0; 102 103 if (dai_props->mclk_fs) 104 mclk_fs = dai_props->mclk_fs; 105 106 if (mclk_fs) { 107 mclk = params_rate(params) * mclk_fs; 108 109 ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk); 110 if (ret < 0) 111 return ret; 112 113 ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk); 114 if (ret < 0) 115 return ret; 116 117 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 118 SND_SOC_CLOCK_IN); 119 if (ret && ret != -ENOTSUPP) 120 goto err; 121 122 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, 123 SND_SOC_CLOCK_OUT); 124 if (ret && ret != -ENOTSUPP) 125 goto err; 126 } 127 return 0; 128 err: 129 return ret; 130 } 131 132 static const struct snd_soc_ops asoc_simple_card_ops = { 133 .startup = asoc_simple_card_startup, 134 .shutdown = asoc_simple_card_shutdown, 135 .hw_params = asoc_simple_card_hw_params, 136 }; 137 138 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) 139 { 140 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 141 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); 142 int ret; 143 144 ret = asoc_simple_card_init_dai(rtd->codec_dai, 145 dai_props->codec_dai); 146 if (ret < 0) 147 return ret; 148 149 ret = asoc_simple_card_init_dai(rtd->cpu_dai, 150 dai_props->cpu_dai); 151 if (ret < 0) 152 return ret; 153 154 return 0; 155 } 156 157 static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 158 struct snd_pcm_hw_params *params) 159 { 160 struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); 161 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); 162 163 asoc_simple_card_convert_fixup(&dai_props->adata, params); 164 165 return 0; 166 } 167 168 static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, 169 struct device_node *node, 170 struct device_node *np, 171 struct device_node *codec, 172 struct simple_card_data *priv, 173 int *dai_idx, int link_idx, 174 int *conf_idx, int is_fe, 175 bool is_top_level_node) 176 { 177 struct device *dev = simple_priv_to_dev(priv); 178 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); 179 struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); 180 struct asoc_simple_dai *dai; 181 struct snd_soc_dai_link_component *codecs = dai_link->codecs; 182 183 char prop[128]; 184 char *prefix = ""; 185 int ret; 186 187 /* For single DAI link & old style of DT node */ 188 if (is_top_level_node) 189 prefix = PREFIX; 190 191 if (is_fe) { 192 int is_single_links = 0; 193 194 /* BE is dummy */ 195 codecs->of_node = NULL; 196 codecs->dai_name = "snd-soc-dummy-dai"; 197 codecs->name = "snd-soc-dummy"; 198 199 /* FE settings */ 200 dai_link->dynamic = 1; 201 dai_link->dpcm_merged_format = 1; 202 203 dai = 204 dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; 205 206 ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, 207 &is_single_links); 208 if (ret) 209 return ret; 210 211 ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai); 212 if (ret < 0) 213 return ret; 214 215 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 216 "fe.%s", 217 dai_link->cpu_dai_name); 218 if (ret < 0) 219 return ret; 220 221 asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); 222 } else { 223 struct snd_soc_codec_conf *cconf; 224 225 /* FE is dummy */ 226 dai_link->cpu_of_node = NULL; 227 dai_link->cpu_dai_name = "snd-soc-dummy-dai"; 228 dai_link->cpu_name = "snd-soc-dummy"; 229 230 /* BE settings */ 231 dai_link->no_pcm = 1; 232 dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; 233 234 dai = 235 dai_props->codec_dai = &priv->dais[(*dai_idx)++]; 236 237 cconf = 238 dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; 239 240 ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); 241 if (ret < 0) 242 return ret; 243 244 ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai); 245 if (ret < 0) 246 return ret; 247 248 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 249 "be.%s", 250 codecs->dai_name); 251 if (ret < 0) 252 return ret; 253 254 /* check "prefix" from top node */ 255 snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, 256 PREFIX "prefix"); 257 snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node, 258 "prefix"); 259 snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node, 260 "prefix"); 261 } 262 263 asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata); 264 asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata); 265 asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata); 266 267 ret = asoc_simple_card_of_parse_tdm(np, dai); 268 if (ret) 269 return ret; 270 271 ret = asoc_simple_card_canonicalize_dailink(dai_link); 272 if (ret < 0) 273 return ret; 274 275 snprintf(prop, sizeof(prop), "%smclk-fs", prefix); 276 of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); 277 of_property_read_u32(node, prop, &dai_props->mclk_fs); 278 of_property_read_u32(np, prop, &dai_props->mclk_fs); 279 280 ret = asoc_simple_card_parse_daifmt(dev, node, codec, 281 prefix, &dai_link->dai_fmt); 282 if (ret < 0) 283 return ret; 284 285 dai_link->dpcm_playback = 1; 286 dai_link->dpcm_capture = 1; 287 dai_link->ops = &asoc_simple_card_ops; 288 dai_link->init = asoc_simple_card_dai_init; 289 290 return 0; 291 } 292 293 static int asoc_simple_card_dai_link_of(struct device_node *top, 294 struct device_node *node, 295 struct simple_card_data *priv, 296 int *dai_idx, int link_idx, 297 bool is_top_level_node) 298 { 299 struct device *dev = simple_priv_to_dev(priv); 300 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); 301 struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); 302 struct asoc_simple_dai *cpu_dai; 303 struct asoc_simple_dai *codec_dai; 304 struct device_node *cpu = NULL; 305 struct device_node *plat = NULL; 306 struct device_node *codec = NULL; 307 char prop[128]; 308 char *prefix = ""; 309 int ret, single_cpu; 310 311 /* For single DAI link & old style of DT node */ 312 if (is_top_level_node) 313 prefix = PREFIX; 314 315 snprintf(prop, sizeof(prop), "%scpu", prefix); 316 cpu = of_get_child_by_name(node, prop); 317 318 if (!cpu) { 319 ret = -EINVAL; 320 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 321 goto dai_link_of_err; 322 } 323 324 snprintf(prop, sizeof(prop), "%splat", prefix); 325 plat = of_get_child_by_name(node, prop); 326 327 snprintf(prop, sizeof(prop), "%scodec", prefix); 328 codec = of_get_child_by_name(node, prop); 329 330 if (!codec) { 331 ret = -EINVAL; 332 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); 333 goto dai_link_of_err; 334 } 335 336 cpu_dai = 337 dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; 338 codec_dai = 339 dai_props->codec_dai = &priv->dais[(*dai_idx)++]; 340 341 ret = asoc_simple_card_parse_daifmt(dev, node, codec, 342 prefix, &dai_link->dai_fmt); 343 if (ret < 0) 344 goto dai_link_of_err; 345 346 snprintf(prop, sizeof(prop), "%smclk-fs", prefix); 347 of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); 348 of_property_read_u32(node, prop, &dai_props->mclk_fs); 349 of_property_read_u32(cpu, prop, &dai_props->mclk_fs); 350 of_property_read_u32(codec, prop, &dai_props->mclk_fs); 351 352 ret = asoc_simple_card_parse_cpu(cpu, dai_link, 353 DAI, CELL, &single_cpu); 354 if (ret < 0) 355 goto dai_link_of_err; 356 357 ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL); 358 if (ret < 0) 359 goto dai_link_of_err; 360 361 ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL); 362 if (ret < 0) 363 goto dai_link_of_err; 364 365 ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai); 366 if (ret < 0) 367 goto dai_link_of_err; 368 369 ret = asoc_simple_card_of_parse_tdm(codec, codec_dai); 370 if (ret < 0) 371 goto dai_link_of_err; 372 373 ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai); 374 if (ret < 0) 375 goto dai_link_of_err; 376 377 ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai); 378 if (ret < 0) 379 goto dai_link_of_err; 380 381 ret = asoc_simple_card_canonicalize_dailink(dai_link); 382 if (ret < 0) 383 goto dai_link_of_err; 384 385 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 386 "%s-%s", 387 dai_link->cpu_dai_name, 388 dai_link->codecs->dai_name); 389 if (ret < 0) 390 goto dai_link_of_err; 391 392 dai_link->ops = &asoc_simple_card_ops; 393 dai_link->init = asoc_simple_card_dai_init; 394 395 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); 396 397 dai_link_of_err: 398 of_node_put(cpu); 399 of_node_put(codec); 400 401 return ret; 402 } 403 404 static int asoc_simple_card_parse_aux_devs(struct device_node *node, 405 struct simple_card_data *priv) 406 { 407 struct device *dev = simple_priv_to_dev(priv); 408 struct device_node *aux_node; 409 struct snd_soc_card *card = simple_priv_to_card(priv); 410 int i, n, len; 411 412 if (!of_find_property(node, PREFIX "aux-devs", &len)) 413 return 0; /* Ok to have no aux-devs */ 414 415 n = len / sizeof(__be32); 416 if (n <= 0) 417 return -EINVAL; 418 419 card->aux_dev = devm_kcalloc(dev, 420 n, sizeof(*card->aux_dev), GFP_KERNEL); 421 if (!card->aux_dev) 422 return -ENOMEM; 423 424 for (i = 0; i < n; i++) { 425 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); 426 if (!aux_node) 427 return -EINVAL; 428 card->aux_dev[i].codec_of_node = aux_node; 429 } 430 431 card->num_aux_devs = n; 432 return 0; 433 } 434 435 static int asoc_simple_card_parse_of(struct simple_card_data *priv) 436 { 437 struct device *dev = simple_priv_to_dev(priv); 438 struct device_node *top = dev->of_node; 439 struct snd_soc_card *card = simple_priv_to_card(priv); 440 struct device_node *node; 441 struct device_node *np; 442 struct device_node *codec; 443 bool is_fe; 444 int ret, loop; 445 int dai_idx, link_idx, conf_idx; 446 447 if (!top) 448 return -EINVAL; 449 450 ret = asoc_simple_card_of_parse_widgets(card, PREFIX); 451 if (ret < 0) 452 return ret; 453 454 ret = asoc_simple_card_of_parse_routing(card, PREFIX); 455 if (ret < 0) 456 return ret; 457 458 /* Single/Muti DAI link(s) & New style of DT node */ 459 loop = 1; 460 link_idx = 0; 461 dai_idx = 0; 462 conf_idx = 0; 463 node = of_get_child_by_name(top, PREFIX "dai-link"); 464 if (!node) { 465 node = dev->of_node; 466 loop = 0; 467 } 468 469 do { 470 /* DPCM */ 471 if (of_get_child_count(node) > 2) { 472 for_each_child_of_node(node, np) { 473 codec = of_get_child_by_name(node, 474 loop ? "codec" : 475 PREFIX "codec"); 476 if (!codec) 477 return -ENODEV; 478 479 is_fe = (np != codec); 480 481 ret = asoc_simple_card_dai_link_of_dpcm( 482 top, node, np, codec, priv, 483 &dai_idx, link_idx++, &conf_idx, 484 is_fe, !loop); 485 } 486 } else { 487 ret = asoc_simple_card_dai_link_of( 488 top, node, priv, 489 &dai_idx, link_idx++, !loop); 490 } 491 if (ret < 0) 492 return ret; 493 494 node = of_get_next_child(top, node); 495 } while (loop && node); 496 497 ret = asoc_simple_card_parse_card_name(card, PREFIX); 498 if (ret < 0) 499 return ret; 500 501 ret = asoc_simple_card_parse_aux_devs(top, priv); 502 503 return ret; 504 } 505 506 static void asoc_simple_card_get_dais_count(struct device *dev, 507 int *link_num, 508 int *dais_num, 509 int *ccnf_num) 510 { 511 struct device_node *top = dev->of_node; 512 struct device_node *node; 513 int loop; 514 int num; 515 516 /* 517 * link_num : number of links. 518 * CPU-Codec / CPU-dummy / dummy-Codec 519 * dais_num : number of DAIs 520 * ccnf_num : number of codec_conf 521 * same number for "dummy-Codec" 522 * 523 * ex1) 524 * CPU0 --- Codec0 link : 5 525 * CPU1 --- Codec1 dais : 7 526 * CPU2 -/ ccnf : 1 527 * CPU3 --- Codec2 528 * 529 * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec 530 * => 7 DAIs = 4xCPU + 3xCodec 531 * => 1 ccnf = 1xdummy-Codec 532 * 533 * ex2) 534 * CPU0 --- Codec0 link : 5 535 * CPU1 --- Codec1 dais : 6 536 * CPU2 -/ ccnf : 1 537 * CPU3 -/ 538 * 539 * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec 540 * => 6 DAIs = 4xCPU + 2xCodec 541 * => 1 ccnf = 1xdummy-Codec 542 * 543 * ex3) 544 * CPU0 --- Codec0 link : 6 545 * CPU1 -/ dais : 6 546 * CPU2 --- Codec1 ccnf : 2 547 * CPU3 -/ 548 * 549 * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec 550 * => 6 DAIs = 4xCPU + 2xCodec 551 * => 2 ccnf = 2xdummy-Codec 552 */ 553 if (!top) { 554 (*link_num) = 1; 555 (*dais_num) = 2; 556 (*ccnf_num) = 0; 557 return; 558 } 559 560 loop = 1; 561 node = of_get_child_by_name(top, PREFIX "dai-link"); 562 if (!node) { 563 node = top; 564 loop = 0; 565 } 566 567 do { 568 num = of_get_child_count(node); 569 (*dais_num) += num; 570 if (num > 2) { 571 (*link_num) += num; 572 (*ccnf_num)++; 573 } else { 574 (*link_num)++; 575 } 576 node = of_get_next_child(top, node); 577 } while (loop && node); 578 } 579 580 static int asoc_simple_soc_card_probe(struct snd_soc_card *card) 581 { 582 struct simple_card_data *priv = snd_soc_card_get_drvdata(card); 583 int ret; 584 585 ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX); 586 if (ret < 0) 587 return ret; 588 589 ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX); 590 if (ret < 0) 591 return ret; 592 593 return 0; 594 } 595 596 static int asoc_simple_card_probe(struct platform_device *pdev) 597 { 598 struct simple_card_data *priv; 599 struct snd_soc_dai_link *dai_link; 600 struct simple_dai_props *dai_props; 601 struct asoc_simple_dai *dais; 602 struct device *dev = &pdev->dev; 603 struct device_node *np = dev->of_node; 604 struct snd_soc_card *card; 605 struct snd_soc_codec_conf *cconf; 606 int lnum = 0, dnum = 0, cnum = 0; 607 int ret, i; 608 609 /* Allocate the private data and the DAI link array */ 610 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 611 if (!priv) 612 return -ENOMEM; 613 614 asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); 615 if (!lnum || !dnum) 616 return -EINVAL; 617 618 dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); 619 dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); 620 dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); 621 cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); 622 if (!dai_props || !dai_link || !dais) 623 return -ENOMEM; 624 625 /* 626 * Use snd_soc_dai_link_component instead of legacy style 627 * It is codec only. but cpu/platform will be supported in the future. 628 * see 629 * soc-core.c :: snd_soc_init_multicodec() 630 */ 631 for (i = 0; i < lnum; i++) { 632 dai_link[i].codecs = &dai_props[i].codecs; 633 dai_link[i].num_codecs = 1; 634 dai_link[i].platform = &dai_props[i].platform; 635 } 636 637 priv->dai_props = dai_props; 638 priv->dai_link = dai_link; 639 priv->dais = dais; 640 priv->codec_conf = cconf; 641 642 /* Init snd_soc_card */ 643 card = simple_priv_to_card(priv); 644 card->owner = THIS_MODULE; 645 card->dev = dev; 646 card->dai_link = priv->dai_link; 647 card->num_links = lnum; 648 card->codec_conf = cconf; 649 card->num_configs = cnum; 650 card->probe = asoc_simple_soc_card_probe; 651 652 if (np && of_device_is_available(np)) { 653 654 ret = asoc_simple_card_parse_of(priv); 655 if (ret < 0) { 656 if (ret != -EPROBE_DEFER) 657 dev_err(dev, "parse error %d\n", ret); 658 goto err; 659 } 660 661 } else { 662 struct asoc_simple_card_info *cinfo; 663 struct snd_soc_dai_link_component *codecs; 664 struct snd_soc_dai_link_component *platform; 665 int dai_idx = 0; 666 667 cinfo = dev->platform_data; 668 if (!cinfo) { 669 dev_err(dev, "no info for asoc-simple-card\n"); 670 return -EINVAL; 671 } 672 673 if (!cinfo->name || 674 !cinfo->codec_dai.name || 675 !cinfo->codec || 676 !cinfo->platform || 677 !cinfo->cpu_dai.name) { 678 dev_err(dev, "insufficient asoc_simple_card_info settings\n"); 679 return -EINVAL; 680 } 681 682 dai_props->cpu_dai = &priv->dais[dai_idx++]; 683 dai_props->codec_dai = &priv->dais[dai_idx++]; 684 685 codecs = dai_link->codecs; 686 codecs->name = cinfo->codec; 687 codecs->dai_name = cinfo->codec_dai.name; 688 689 platform = dai_link->platform; 690 platform->name = cinfo->platform; 691 692 card->name = (cinfo->card) ? cinfo->card : cinfo->name; 693 dai_link->name = cinfo->name; 694 dai_link->stream_name = cinfo->name; 695 dai_link->cpu_dai_name = cinfo->cpu_dai.name; 696 dai_link->dai_fmt = cinfo->daifmt; 697 dai_link->init = asoc_simple_card_dai_init; 698 memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai, 699 sizeof(*priv->dai_props->cpu_dai)); 700 memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai, 701 sizeof(*priv->dai_props->codec_dai)); 702 } 703 704 snd_soc_card_set_drvdata(card, priv); 705 706 ret = devm_snd_soc_register_card(dev, card); 707 if (ret < 0) 708 goto err; 709 710 return 0; 711 err: 712 asoc_simple_card_clean_reference(card); 713 714 return ret; 715 } 716 717 static int asoc_simple_card_remove(struct platform_device *pdev) 718 { 719 struct snd_soc_card *card = platform_get_drvdata(pdev); 720 721 return asoc_simple_card_clean_reference(card); 722 } 723 724 static const struct of_device_id asoc_simple_of_match[] = { 725 { .compatible = "simple-audio-card", }, 726 { .compatible = "simple-scu-audio-card", }, 727 {}, 728 }; 729 MODULE_DEVICE_TABLE(of, asoc_simple_of_match); 730 731 static struct platform_driver asoc_simple_card = { 732 .driver = { 733 .name = "asoc-simple-card", 734 .pm = &snd_soc_pm_ops, 735 .of_match_table = asoc_simple_of_match, 736 }, 737 .probe = asoc_simple_card_probe, 738 .remove = asoc_simple_card_remove, 739 }; 740 741 module_platform_driver(asoc_simple_card); 742 743 MODULE_ALIAS("platform:asoc-simple-card"); 744 MODULE_LICENSE("GPL v2"); 745 MODULE_DESCRIPTION("ASoC Simple Sound Card"); 746 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 747