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