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