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/of_device.h> 13 #include <linux/platform_device.h> 14 #include <linux/string.h> 15 #include <sound/simple_card.h> 16 #include <sound/soc-dai.h> 17 #include <sound/soc.h> 18 19 #define DPCM_SELECTABLE 1 20 21 #define DAI "sound-dai" 22 #define CELL "#sound-dai-cells" 23 #define PREFIX "simple-audio-card," 24 25 static const struct snd_soc_ops simple_ops = { 26 .startup = asoc_simple_startup, 27 .shutdown = asoc_simple_shutdown, 28 .hw_params = asoc_simple_hw_params, 29 }; 30 31 static int asoc_simple_parse_platform(struct device_node *node, 32 struct snd_soc_dai_link_component *dlc) 33 { 34 struct of_phandle_args args; 35 int ret; 36 37 if (!node) 38 return 0; 39 40 /* 41 * Get node via "sound-dai = <&phandle port>" 42 * it will be used as xxx_of_node on soc_bind_dai_link() 43 */ 44 ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args); 45 if (ret) 46 return ret; 47 48 /* dai_name is not required and may not exist for plat component */ 49 50 dlc->of_node = args.np; 51 52 return 0; 53 } 54 55 static int asoc_simple_parse_dai(struct device_node *node, 56 struct snd_soc_dai_link_component *dlc, 57 int *is_single_link) 58 { 59 struct of_phandle_args args; 60 int ret; 61 62 if (!node) 63 return 0; 64 65 /* 66 * Get node via "sound-dai = <&phandle port>" 67 * it will be used as xxx_of_node on soc_bind_dai_link() 68 */ 69 ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args); 70 if (ret) 71 return ret; 72 73 /* 74 * FIXME 75 * 76 * Here, dlc->dai_name is pointer to CPU/Codec DAI name. 77 * If user unbinded CPU or Codec driver, but not for Sound Card, 78 * dlc->dai_name is keeping unbinded CPU or Codec 79 * driver's pointer. 80 * 81 * If user re-bind CPU or Codec driver again, ALSA SoC will try 82 * to rebind Card via snd_soc_try_rebind_card(), but because of 83 * above reason, it might can't bind Sound Card. 84 * Because Sound Card is pointing to released dai_name pointer. 85 * 86 * To avoid this rebind Card issue, 87 * 1) It needs to alloc memory to keep dai_name eventhough 88 * CPU or Codec driver was unbinded, or 89 * 2) user need to rebind Sound Card everytime 90 * if he unbinded CPU or Codec. 91 */ 92 ret = snd_soc_of_get_dai_name(node, &dlc->dai_name); 93 if (ret < 0) 94 return ret; 95 96 dlc->of_node = args.np; 97 98 if (is_single_link) 99 *is_single_link = !args.args_count; 100 101 return 0; 102 } 103 104 static void simple_parse_convert(struct device *dev, 105 struct device_node *np, 106 struct asoc_simple_data *adata) 107 { 108 struct device_node *top = dev->of_node; 109 struct device_node *node = of_get_parent(np); 110 111 asoc_simple_parse_convert(top, PREFIX, adata); 112 asoc_simple_parse_convert(node, PREFIX, adata); 113 asoc_simple_parse_convert(node, NULL, adata); 114 asoc_simple_parse_convert(np, NULL, adata); 115 116 of_node_put(node); 117 } 118 119 static void simple_parse_mclk_fs(struct device_node *top, 120 struct device_node *np, 121 struct simple_dai_props *props, 122 char *prefix) 123 { 124 struct device_node *node = of_get_parent(np); 125 char prop[128]; 126 127 snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX); 128 of_property_read_u32(top, prop, &props->mclk_fs); 129 130 snprintf(prop, sizeof(prop), "%smclk-fs", prefix); 131 of_property_read_u32(node, prop, &props->mclk_fs); 132 of_property_read_u32(np, prop, &props->mclk_fs); 133 134 of_node_put(node); 135 } 136 137 static int simple_parse_node(struct asoc_simple_priv *priv, 138 struct device_node *np, 139 struct link_info *li, 140 char *prefix, 141 int *cpu) 142 { 143 struct device *dev = simple_priv_to_dev(priv); 144 struct device_node *top = dev->of_node; 145 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); 146 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); 147 struct snd_soc_dai_link_component *dlc; 148 struct asoc_simple_dai *dai; 149 int ret; 150 151 if (cpu) { 152 dlc = asoc_link_to_cpu(dai_link, 0); 153 dai = simple_props_to_dai_cpu(dai_props, 0); 154 } else { 155 dlc = asoc_link_to_codec(dai_link, 0); 156 dai = simple_props_to_dai_codec(dai_props, 0); 157 } 158 159 simple_parse_mclk_fs(top, np, dai_props, prefix); 160 161 ret = asoc_simple_parse_dai(np, dlc, cpu); 162 if (ret) 163 return ret; 164 165 ret = asoc_simple_parse_clk(dev, np, dai, dlc); 166 if (ret) 167 return ret; 168 169 ret = asoc_simple_parse_tdm(np, dai); 170 if (ret) 171 return ret; 172 173 return 0; 174 } 175 176 static int simple_link_init(struct asoc_simple_priv *priv, 177 struct device_node *node, 178 struct device_node *codec, 179 struct link_info *li, 180 char *prefix, char *name) 181 { 182 struct device *dev = simple_priv_to_dev(priv); 183 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); 184 int ret; 185 186 ret = asoc_simple_parse_daifmt(dev, node, codec, 187 prefix, &dai_link->dai_fmt); 188 if (ret < 0) 189 return 0; 190 191 dai_link->init = asoc_simple_dai_init; 192 dai_link->ops = &simple_ops; 193 194 return asoc_simple_set_dailink_name(dev, dai_link, name); 195 } 196 197 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, 198 struct device_node *np, 199 struct device_node *codec, 200 struct link_info *li, 201 bool is_top) 202 { 203 struct device *dev = simple_priv_to_dev(priv); 204 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); 205 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); 206 struct device_node *top = dev->of_node; 207 struct device_node *node = of_get_parent(np); 208 char *prefix = ""; 209 char dai_name[64]; 210 int ret; 211 212 dev_dbg(dev, "link_of DPCM (%pOF)\n", np); 213 214 /* For single DAI link & old style of DT node */ 215 if (is_top) 216 prefix = PREFIX; 217 218 if (li->cpu) { 219 struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); 220 struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); 221 int is_single_links = 0; 222 223 /* Codec is dummy */ 224 225 /* FE settings */ 226 dai_link->dynamic = 1; 227 dai_link->dpcm_merged_format = 1; 228 229 ret = simple_parse_node(priv, np, li, prefix, &is_single_links); 230 if (ret < 0) 231 goto out_put_node; 232 233 snprintf(dai_name, sizeof(dai_name), "fe.%s", cpus->dai_name); 234 235 asoc_simple_canonicalize_cpu(cpus, is_single_links); 236 asoc_simple_canonicalize_platform(platforms, cpus); 237 } else { 238 struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); 239 struct snd_soc_codec_conf *cconf; 240 241 /* CPU is dummy */ 242 243 /* BE settings */ 244 dai_link->no_pcm = 1; 245 dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; 246 247 cconf = simple_props_to_codec_conf(dai_props, 0); 248 249 ret = simple_parse_node(priv, np, li, prefix, NULL); 250 if (ret < 0) 251 goto out_put_node; 252 253 snprintf(dai_name, sizeof(dai_name), "be.%s", codecs->dai_name); 254 255 /* check "prefix" from top node */ 256 snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, 257 PREFIX "prefix"); 258 snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node, 259 "prefix"); 260 snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node, 261 "prefix"); 262 } 263 264 simple_parse_convert(dev, np, &dai_props->adata); 265 266 snd_soc_dai_link_set_capabilities(dai_link); 267 268 ret = simple_link_init(priv, node, codec, li, prefix, dai_name); 269 270 out_put_node: 271 li->link++; 272 273 of_node_put(node); 274 return ret; 275 } 276 277 static int simple_dai_link_of(struct asoc_simple_priv *priv, 278 struct device_node *np, 279 struct device_node *codec, 280 struct link_info *li, 281 bool is_top) 282 { 283 struct device *dev = simple_priv_to_dev(priv); 284 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); 285 struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); 286 struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); 287 struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); 288 struct device_node *cpu = NULL; 289 struct device_node *node = NULL; 290 struct device_node *plat = NULL; 291 char dai_name[64]; 292 char prop[128]; 293 char *prefix = ""; 294 int ret, single_cpu = 0; 295 296 cpu = np; 297 node = of_get_parent(np); 298 299 dev_dbg(dev, "link_of (%pOF)\n", node); 300 301 /* For single DAI link & old style of DT node */ 302 if (is_top) 303 prefix = PREFIX; 304 305 snprintf(prop, sizeof(prop), "%splat", prefix); 306 plat = of_get_child_by_name(node, prop); 307 308 ret = simple_parse_node(priv, cpu, li, prefix, &single_cpu); 309 if (ret < 0) 310 goto dai_link_of_err; 311 312 ret = simple_parse_node(priv, codec, li, prefix, NULL); 313 if (ret < 0) 314 goto dai_link_of_err; 315 316 ret = asoc_simple_parse_platform(plat, platforms); 317 if (ret < 0) 318 goto dai_link_of_err; 319 320 snprintf(dai_name, sizeof(dai_name), 321 "%s-%s", cpus->dai_name, codecs->dai_name); 322 323 asoc_simple_canonicalize_cpu(cpus, single_cpu); 324 asoc_simple_canonicalize_platform(platforms, cpus); 325 326 ret = simple_link_init(priv, node, codec, li, prefix, dai_name); 327 328 dai_link_of_err: 329 of_node_put(plat); 330 of_node_put(node); 331 332 li->link++; 333 334 return ret; 335 } 336 337 static int __simple_for_each_link(struct asoc_simple_priv *priv, 338 struct link_info *li, 339 int (*func_noml)(struct asoc_simple_priv *priv, 340 struct device_node *np, 341 struct device_node *codec, 342 struct link_info *li, bool is_top), 343 int (*func_dpcm)(struct asoc_simple_priv *priv, 344 struct device_node *np, 345 struct device_node *codec, 346 struct link_info *li, bool is_top)) 347 { 348 struct device *dev = simple_priv_to_dev(priv); 349 struct device_node *top = dev->of_node; 350 struct device_node *node; 351 uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev); 352 bool is_top = 0; 353 int ret = 0; 354 355 /* Check if it has dai-link */ 356 node = of_get_child_by_name(top, PREFIX "dai-link"); 357 if (!node) { 358 node = of_node_get(top); 359 is_top = 1; 360 } 361 362 /* loop for all dai-link */ 363 do { 364 struct asoc_simple_data adata; 365 struct device_node *codec; 366 struct device_node *plat; 367 struct device_node *np; 368 int num = of_get_child_count(node); 369 370 /* get codec */ 371 codec = of_get_child_by_name(node, is_top ? 372 PREFIX "codec" : "codec"); 373 if (!codec) { 374 ret = -ENODEV; 375 goto error; 376 } 377 /* get platform */ 378 plat = of_get_child_by_name(node, is_top ? 379 PREFIX "plat" : "plat"); 380 381 /* get convert-xxx property */ 382 memset(&adata, 0, sizeof(adata)); 383 for_each_child_of_node(node, np) 384 simple_parse_convert(dev, np, &adata); 385 386 /* loop for all CPU/Codec node */ 387 for_each_child_of_node(node, np) { 388 if (plat == np) 389 continue; 390 /* 391 * It is DPCM 392 * if it has many CPUs, 393 * or has convert-xxx property 394 */ 395 if (dpcm_selectable && 396 (num > 2 || 397 adata.convert_rate || adata.convert_channels)) { 398 /* 399 * np 400 * |1(CPU)|0(Codec) li->cpu 401 * CPU |Pass |return 402 * Codec |return|Pass 403 */ 404 if (li->cpu != (np == codec)) 405 ret = func_dpcm(priv, np, codec, li, is_top); 406 /* else normal sound */ 407 } else { 408 /* 409 * np 410 * |1(CPU)|0(Codec) li->cpu 411 * CPU |Pass |return 412 * Codec |return|return 413 */ 414 if (li->cpu && (np != codec)) 415 ret = func_noml(priv, np, codec, li, is_top); 416 } 417 418 if (ret < 0) { 419 of_node_put(codec); 420 of_node_put(np); 421 goto error; 422 } 423 } 424 425 of_node_put(codec); 426 node = of_get_next_child(top, node); 427 } while (!is_top && node); 428 429 error: 430 of_node_put(node); 431 return ret; 432 } 433 434 static int simple_for_each_link(struct asoc_simple_priv *priv, 435 struct link_info *li, 436 int (*func_noml)(struct asoc_simple_priv *priv, 437 struct device_node *np, 438 struct device_node *codec, 439 struct link_info *li, bool is_top), 440 int (*func_dpcm)(struct asoc_simple_priv *priv, 441 struct device_node *np, 442 struct device_node *codec, 443 struct link_info *li, bool is_top)) 444 { 445 int ret; 446 /* 447 * Detect all CPU first, and Detect all Codec 2nd. 448 * 449 * In Normal sound case, all DAIs are detected 450 * as "CPU-Codec". 451 * 452 * In DPCM sound case, 453 * all CPUs are detected as "CPU-dummy", and 454 * all Codecs are detected as "dummy-Codec". 455 * To avoid random sub-device numbering, 456 * detect "dummy-Codec" in last; 457 */ 458 for (li->cpu = 1; li->cpu >= 0; li->cpu--) { 459 ret = __simple_for_each_link(priv, li, func_noml, func_dpcm); 460 if (ret < 0) 461 break; 462 } 463 464 return ret; 465 } 466 467 static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li) 468 { 469 struct snd_soc_card *card = simple_priv_to_card(priv); 470 int ret; 471 472 ret = asoc_simple_parse_widgets(card, PREFIX); 473 if (ret < 0) 474 return ret; 475 476 ret = asoc_simple_parse_routing(card, PREFIX); 477 if (ret < 0) 478 return ret; 479 480 ret = asoc_simple_parse_pin_switches(card, PREFIX); 481 if (ret < 0) 482 return ret; 483 484 /* Single/Muti DAI link(s) & New style of DT node */ 485 memset(li, 0, sizeof(*li)); 486 ret = simple_for_each_link(priv, li, 487 simple_dai_link_of, 488 simple_dai_link_of_dpcm); 489 if (ret < 0) 490 return ret; 491 492 ret = asoc_simple_parse_card_name(card, PREFIX); 493 if (ret < 0) 494 return ret; 495 496 ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); 497 498 return ret; 499 } 500 501 static int simple_count_noml(struct asoc_simple_priv *priv, 502 struct device_node *np, 503 struct device_node *codec, 504 struct link_info *li, bool is_top) 505 { 506 if (li->link >= SNDRV_MAX_LINKS) { 507 struct device *dev = simple_priv_to_dev(priv); 508 509 dev_err(dev, "too many links\n"); 510 return -EINVAL; 511 } 512 513 li->num[li->link].cpus = 1; 514 li->num[li->link].codecs = 1; 515 li->num[li->link].platforms = 1; 516 517 li->link += 1; 518 519 return 0; 520 } 521 522 static int simple_count_dpcm(struct asoc_simple_priv *priv, 523 struct device_node *np, 524 struct device_node *codec, 525 struct link_info *li, bool is_top) 526 { 527 if (li->link >= SNDRV_MAX_LINKS) { 528 struct device *dev = simple_priv_to_dev(priv); 529 530 dev_err(dev, "too many links\n"); 531 return -EINVAL; 532 } 533 534 if (li->cpu) { 535 li->num[li->link].cpus = 1; 536 li->num[li->link].platforms = 1; 537 538 li->link++; /* CPU-dummy */ 539 } else { 540 li->num[li->link].codecs = 1; 541 542 li->link++; /* dummy-Codec */ 543 } 544 545 return 0; 546 } 547 548 static int simple_get_dais_count(struct asoc_simple_priv *priv, 549 struct link_info *li) 550 { 551 struct device *dev = simple_priv_to_dev(priv); 552 struct device_node *top = dev->of_node; 553 554 /* 555 * link_num : number of links. 556 * CPU-Codec / CPU-dummy / dummy-Codec 557 * dais_num : number of DAIs 558 * ccnf_num : number of codec_conf 559 * same number for "dummy-Codec" 560 * 561 * ex1) 562 * CPU0 --- Codec0 link : 5 563 * CPU1 --- Codec1 dais : 7 564 * CPU2 -/ ccnf : 1 565 * CPU3 --- Codec2 566 * 567 * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec 568 * => 7 DAIs = 4xCPU + 3xCodec 569 * => 1 ccnf = 1xdummy-Codec 570 * 571 * ex2) 572 * CPU0 --- Codec0 link : 5 573 * CPU1 --- Codec1 dais : 6 574 * CPU2 -/ ccnf : 1 575 * CPU3 -/ 576 * 577 * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec 578 * => 6 DAIs = 4xCPU + 2xCodec 579 * => 1 ccnf = 1xdummy-Codec 580 * 581 * ex3) 582 * CPU0 --- Codec0 link : 6 583 * CPU1 -/ dais : 6 584 * CPU2 --- Codec1 ccnf : 2 585 * CPU3 -/ 586 * 587 * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec 588 * => 6 DAIs = 4xCPU + 2xCodec 589 * => 2 ccnf = 2xdummy-Codec 590 * 591 * ex4) 592 * CPU0 --- Codec0 (convert-rate) link : 3 593 * CPU1 --- Codec1 dais : 4 594 * ccnf : 1 595 * 596 * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec 597 * => 4 DAIs = 2xCPU + 2xCodec 598 * => 1 ccnf = 1xdummy-Codec 599 */ 600 if (!top) { 601 li->num[0].cpus = 1; 602 li->num[0].codecs = 1; 603 li->num[0].platforms = 1; 604 605 li->link = 1; 606 return 0; 607 } 608 609 return simple_for_each_link(priv, li, 610 simple_count_noml, 611 simple_count_dpcm); 612 } 613 614 static int simple_soc_probe(struct snd_soc_card *card) 615 { 616 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); 617 int ret; 618 619 ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX); 620 if (ret < 0) 621 return ret; 622 623 ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX); 624 if (ret < 0) 625 return ret; 626 627 return 0; 628 } 629 630 static int asoc_simple_probe(struct platform_device *pdev) 631 { 632 struct asoc_simple_priv *priv; 633 struct device *dev = &pdev->dev; 634 struct device_node *np = dev->of_node; 635 struct snd_soc_card *card; 636 struct link_info *li; 637 int ret; 638 639 /* Allocate the private data and the DAI link array */ 640 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 641 if (!priv) 642 return -ENOMEM; 643 644 card = simple_priv_to_card(priv); 645 card->owner = THIS_MODULE; 646 card->dev = dev; 647 card->probe = simple_soc_probe; 648 card->driver_name = "simple-card"; 649 650 li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); 651 if (!li) 652 return -ENOMEM; 653 654 ret = simple_get_dais_count(priv, li); 655 if (ret < 0) 656 return ret; 657 658 if (!li->link) 659 return -EINVAL; 660 661 ret = asoc_simple_init_priv(priv, li); 662 if (ret < 0) 663 return ret; 664 665 if (np && of_device_is_available(np)) { 666 667 ret = simple_parse_of(priv, li); 668 if (ret < 0) { 669 dev_err_probe(dev, ret, "parse error\n"); 670 goto err; 671 } 672 673 } else { 674 struct asoc_simple_card_info *cinfo; 675 struct snd_soc_dai_link_component *cpus; 676 struct snd_soc_dai_link_component *codecs; 677 struct snd_soc_dai_link_component *platform; 678 struct snd_soc_dai_link *dai_link = priv->dai_link; 679 struct simple_dai_props *dai_props = priv->dai_props; 680 681 cinfo = dev->platform_data; 682 if (!cinfo) { 683 dev_err(dev, "no info for asoc-simple-card\n"); 684 return -EINVAL; 685 } 686 687 if (!cinfo->name || 688 !cinfo->codec_dai.name || 689 !cinfo->codec || 690 !cinfo->platform || 691 !cinfo->cpu_dai.name) { 692 dev_err(dev, "insufficient asoc_simple_card_info settings\n"); 693 return -EINVAL; 694 } 695 696 cpus = dai_link->cpus; 697 cpus->dai_name = cinfo->cpu_dai.name; 698 699 codecs = dai_link->codecs; 700 codecs->name = cinfo->codec; 701 codecs->dai_name = cinfo->codec_dai.name; 702 703 platform = dai_link->platforms; 704 platform->name = cinfo->platform; 705 706 card->name = (cinfo->card) ? cinfo->card : cinfo->name; 707 dai_link->name = cinfo->name; 708 dai_link->stream_name = cinfo->name; 709 dai_link->dai_fmt = cinfo->daifmt; 710 dai_link->init = asoc_simple_dai_init; 711 memcpy(dai_props->cpu_dai, &cinfo->cpu_dai, 712 sizeof(*dai_props->cpu_dai)); 713 memcpy(dai_props->codec_dai, &cinfo->codec_dai, 714 sizeof(*dai_props->codec_dai)); 715 } 716 717 snd_soc_card_set_drvdata(card, priv); 718 719 asoc_simple_debug_info(priv); 720 721 ret = devm_snd_soc_register_card(dev, card); 722 if (ret < 0) 723 goto err; 724 725 devm_kfree(dev, li); 726 return 0; 727 err: 728 asoc_simple_clean_reference(card); 729 730 return ret; 731 } 732 733 static const struct of_device_id simple_of_match[] = { 734 { .compatible = "simple-audio-card", }, 735 { .compatible = "simple-scu-audio-card", 736 .data = (void *)DPCM_SELECTABLE }, 737 {}, 738 }; 739 MODULE_DEVICE_TABLE(of, simple_of_match); 740 741 static struct platform_driver asoc_simple_card = { 742 .driver = { 743 .name = "asoc-simple-card", 744 .pm = &snd_soc_pm_ops, 745 .of_match_table = simple_of_match, 746 }, 747 .probe = asoc_simple_probe, 748 .remove = asoc_simple_remove, 749 }; 750 751 module_platform_driver(asoc_simple_card); 752 753 MODULE_ALIAS("platform:asoc-simple-card"); 754 MODULE_LICENSE("GPL v2"); 755 MODULE_DESCRIPTION("ASoC Simple Sound Card"); 756 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 757