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 || asoc_simple_is_convert_required(&adata))) { 397 /* 398 * np 399 * |1(CPU)|0(Codec) li->cpu 400 * CPU |Pass |return 401 * Codec |return|Pass 402 */ 403 if (li->cpu != (np == codec)) 404 ret = func_dpcm(priv, np, codec, li, is_top); 405 /* else normal sound */ 406 } else { 407 /* 408 * np 409 * |1(CPU)|0(Codec) li->cpu 410 * CPU |Pass |return 411 * Codec |return|return 412 */ 413 if (li->cpu && (np != codec)) 414 ret = func_noml(priv, np, codec, li, is_top); 415 } 416 417 if (ret < 0) { 418 of_node_put(codec); 419 of_node_put(np); 420 goto error; 421 } 422 } 423 424 of_node_put(codec); 425 node = of_get_next_child(top, node); 426 } while (!is_top && node); 427 428 error: 429 of_node_put(node); 430 return ret; 431 } 432 433 static int simple_for_each_link(struct asoc_simple_priv *priv, 434 struct link_info *li, 435 int (*func_noml)(struct asoc_simple_priv *priv, 436 struct device_node *np, 437 struct device_node *codec, 438 struct link_info *li, bool is_top), 439 int (*func_dpcm)(struct asoc_simple_priv *priv, 440 struct device_node *np, 441 struct device_node *codec, 442 struct link_info *li, bool is_top)) 443 { 444 int ret; 445 /* 446 * Detect all CPU first, and Detect all Codec 2nd. 447 * 448 * In Normal sound case, all DAIs are detected 449 * as "CPU-Codec". 450 * 451 * In DPCM sound case, 452 * all CPUs are detected as "CPU-dummy", and 453 * all Codecs are detected as "dummy-Codec". 454 * To avoid random sub-device numbering, 455 * detect "dummy-Codec" in last; 456 */ 457 for (li->cpu = 1; li->cpu >= 0; li->cpu--) { 458 ret = __simple_for_each_link(priv, li, func_noml, func_dpcm); 459 if (ret < 0) 460 break; 461 } 462 463 return ret; 464 } 465 466 static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li) 467 { 468 struct snd_soc_card *card = simple_priv_to_card(priv); 469 int ret; 470 471 ret = asoc_simple_parse_widgets(card, PREFIX); 472 if (ret < 0) 473 return ret; 474 475 ret = asoc_simple_parse_routing(card, PREFIX); 476 if (ret < 0) 477 return ret; 478 479 ret = asoc_simple_parse_pin_switches(card, PREFIX); 480 if (ret < 0) 481 return ret; 482 483 /* Single/Muti DAI link(s) & New style of DT node */ 484 memset(li, 0, sizeof(*li)); 485 ret = simple_for_each_link(priv, li, 486 simple_dai_link_of, 487 simple_dai_link_of_dpcm); 488 if (ret < 0) 489 return ret; 490 491 ret = asoc_simple_parse_card_name(card, PREFIX); 492 if (ret < 0) 493 return ret; 494 495 ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); 496 497 return ret; 498 } 499 500 static int simple_count_noml(struct asoc_simple_priv *priv, 501 struct device_node *np, 502 struct device_node *codec, 503 struct link_info *li, bool is_top) 504 { 505 if (li->link >= SNDRV_MAX_LINKS) { 506 struct device *dev = simple_priv_to_dev(priv); 507 508 dev_err(dev, "too many links\n"); 509 return -EINVAL; 510 } 511 512 li->num[li->link].cpus = 1; 513 li->num[li->link].codecs = 1; 514 li->num[li->link].platforms = 1; 515 516 li->link += 1; 517 518 return 0; 519 } 520 521 static int simple_count_dpcm(struct asoc_simple_priv *priv, 522 struct device_node *np, 523 struct device_node *codec, 524 struct link_info *li, bool is_top) 525 { 526 if (li->link >= SNDRV_MAX_LINKS) { 527 struct device *dev = simple_priv_to_dev(priv); 528 529 dev_err(dev, "too many links\n"); 530 return -EINVAL; 531 } 532 533 if (li->cpu) { 534 li->num[li->link].cpus = 1; 535 li->num[li->link].platforms = 1; 536 537 li->link++; /* CPU-dummy */ 538 } else { 539 li->num[li->link].codecs = 1; 540 541 li->link++; /* dummy-Codec */ 542 } 543 544 return 0; 545 } 546 547 static int simple_get_dais_count(struct asoc_simple_priv *priv, 548 struct link_info *li) 549 { 550 struct device *dev = simple_priv_to_dev(priv); 551 struct device_node *top = dev->of_node; 552 553 /* 554 * link_num : number of links. 555 * CPU-Codec / CPU-dummy / dummy-Codec 556 * dais_num : number of DAIs 557 * ccnf_num : number of codec_conf 558 * same number for "dummy-Codec" 559 * 560 * ex1) 561 * CPU0 --- Codec0 link : 5 562 * CPU1 --- Codec1 dais : 7 563 * CPU2 -/ ccnf : 1 564 * CPU3 --- Codec2 565 * 566 * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec 567 * => 7 DAIs = 4xCPU + 3xCodec 568 * => 1 ccnf = 1xdummy-Codec 569 * 570 * ex2) 571 * CPU0 --- Codec0 link : 5 572 * CPU1 --- Codec1 dais : 6 573 * CPU2 -/ ccnf : 1 574 * CPU3 -/ 575 * 576 * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec 577 * => 6 DAIs = 4xCPU + 2xCodec 578 * => 1 ccnf = 1xdummy-Codec 579 * 580 * ex3) 581 * CPU0 --- Codec0 link : 6 582 * CPU1 -/ dais : 6 583 * CPU2 --- Codec1 ccnf : 2 584 * CPU3 -/ 585 * 586 * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec 587 * => 6 DAIs = 4xCPU + 2xCodec 588 * => 2 ccnf = 2xdummy-Codec 589 * 590 * ex4) 591 * CPU0 --- Codec0 (convert-rate) link : 3 592 * CPU1 --- Codec1 dais : 4 593 * ccnf : 1 594 * 595 * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec 596 * => 4 DAIs = 2xCPU + 2xCodec 597 * => 1 ccnf = 1xdummy-Codec 598 */ 599 if (!top) { 600 li->num[0].cpus = 1; 601 li->num[0].codecs = 1; 602 li->num[0].platforms = 1; 603 604 li->link = 1; 605 return 0; 606 } 607 608 return simple_for_each_link(priv, li, 609 simple_count_noml, 610 simple_count_dpcm); 611 } 612 613 static int simple_soc_probe(struct snd_soc_card *card) 614 { 615 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); 616 int ret; 617 618 ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX); 619 if (ret < 0) 620 return ret; 621 622 ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX); 623 if (ret < 0) 624 return ret; 625 626 return 0; 627 } 628 629 static int asoc_simple_probe(struct platform_device *pdev) 630 { 631 struct asoc_simple_priv *priv; 632 struct device *dev = &pdev->dev; 633 struct device_node *np = dev->of_node; 634 struct snd_soc_card *card; 635 struct link_info *li; 636 int ret; 637 638 /* Allocate the private data and the DAI link array */ 639 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 640 if (!priv) 641 return -ENOMEM; 642 643 card = simple_priv_to_card(priv); 644 card->owner = THIS_MODULE; 645 card->dev = dev; 646 card->probe = simple_soc_probe; 647 card->driver_name = "simple-card"; 648 649 li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); 650 if (!li) 651 return -ENOMEM; 652 653 ret = simple_get_dais_count(priv, li); 654 if (ret < 0) 655 return ret; 656 657 if (!li->link) 658 return -EINVAL; 659 660 ret = asoc_simple_init_priv(priv, li); 661 if (ret < 0) 662 return ret; 663 664 if (np && of_device_is_available(np)) { 665 666 ret = simple_parse_of(priv, li); 667 if (ret < 0) { 668 dev_err_probe(dev, ret, "parse error\n"); 669 goto err; 670 } 671 672 } else { 673 struct asoc_simple_card_info *cinfo; 674 struct snd_soc_dai_link_component *cpus; 675 struct snd_soc_dai_link_component *codecs; 676 struct snd_soc_dai_link_component *platform; 677 struct snd_soc_dai_link *dai_link = priv->dai_link; 678 struct simple_dai_props *dai_props = priv->dai_props; 679 680 cinfo = dev->platform_data; 681 if (!cinfo) { 682 dev_err(dev, "no info for asoc-simple-card\n"); 683 return -EINVAL; 684 } 685 686 if (!cinfo->name || 687 !cinfo->codec_dai.name || 688 !cinfo->codec || 689 !cinfo->platform || 690 !cinfo->cpu_dai.name) { 691 dev_err(dev, "insufficient asoc_simple_card_info settings\n"); 692 return -EINVAL; 693 } 694 695 cpus = dai_link->cpus; 696 cpus->dai_name = cinfo->cpu_dai.name; 697 698 codecs = dai_link->codecs; 699 codecs->name = cinfo->codec; 700 codecs->dai_name = cinfo->codec_dai.name; 701 702 platform = dai_link->platforms; 703 platform->name = cinfo->platform; 704 705 card->name = (cinfo->card) ? cinfo->card : cinfo->name; 706 dai_link->name = cinfo->name; 707 dai_link->stream_name = cinfo->name; 708 dai_link->dai_fmt = cinfo->daifmt; 709 dai_link->init = asoc_simple_dai_init; 710 memcpy(dai_props->cpu_dai, &cinfo->cpu_dai, 711 sizeof(*dai_props->cpu_dai)); 712 memcpy(dai_props->codec_dai, &cinfo->codec_dai, 713 sizeof(*dai_props->codec_dai)); 714 } 715 716 snd_soc_card_set_drvdata(card, priv); 717 718 asoc_simple_debug_info(priv); 719 720 ret = devm_snd_soc_register_card(dev, card); 721 if (ret < 0) 722 goto err; 723 724 devm_kfree(dev, li); 725 return 0; 726 err: 727 asoc_simple_clean_reference(card); 728 729 return ret; 730 } 731 732 static const struct of_device_id simple_of_match[] = { 733 { .compatible = "simple-audio-card", }, 734 { .compatible = "simple-scu-audio-card", 735 .data = (void *)DPCM_SELECTABLE }, 736 {}, 737 }; 738 MODULE_DEVICE_TABLE(of, simple_of_match); 739 740 static struct platform_driver asoc_simple_card = { 741 .driver = { 742 .name = "asoc-simple-card", 743 .pm = &snd_soc_pm_ops, 744 .of_match_table = simple_of_match, 745 }, 746 .probe = asoc_simple_probe, 747 .remove = asoc_simple_remove, 748 }; 749 750 module_platform_driver(asoc_simple_card); 751 752 MODULE_ALIAS("platform:asoc-simple-card"); 753 MODULE_LICENSE("GPL v2"); 754 MODULE_DESCRIPTION("ASoC Simple Sound Card"); 755 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 756