linux/sound/soc/generic/audio-graph-card2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// ASoC Audio Graph Card2 support
   4//
   5// Copyright (C) 2020 Renesas Electronics Corp.
   6// Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   7//
   8// based on ${LINUX}/sound/soc/generic/audio-graph-card.c
   9#include <linux/clk.h>
  10#include <linux/device.h>
  11#include <linux/gpio/consumer.h>
  12#include <linux/module.h>
  13#include <linux/of.h>
  14#include <linux/of_graph.h>
  15#include <linux/platform_device.h>
  16#include <linux/string.h>
  17#include <sound/graph_card.h>
  18
  19/************************************
  20        daifmt
  21 ************************************
  22        ports {
  23                format = "left_j";
  24                port@0 {
  25                        bitclock-master;
  26                        sample0: endpoint@0 {
  27                                frame-master;
  28                        };
  29                        sample1: endpoint@1 {
  30                                format = "i2s";
  31                        };
  32                };
  33                ...
  34        };
  35
  36 You can set daifmt at ports/port/endpoint.
  37 It uses *latest* format, and *share* master settings.
  38 In above case,
  39        sample0: left_j, bitclock-master, frame-master
  40        sample1: i2s,    bitclock-master
  41
  42 If there was no settings, *Codec* will be
  43 bitclock/frame provider as default.
  44 see
  45        graph_parse_daifmt().
  46
  47 "format" property is no longer needed on DT if both CPU/Codec drivers are
  48 supporting snd_soc_dai_ops :: .auto_selectable_formats.
  49 see
  50        snd_soc_runtime_get_dai_fmt()
  51
  52        sample driver
  53                linux/sound/soc/renesas/rcar/core.c
  54                linux/sound/soc/codecs/ak4613.c
  55                linux/sound/soc/codecs/pcm3168a.c
  56                linux/sound/soc/soc-utils.c
  57                linux/sound/soc/generic/test-component.c
  58
  59 ************************************
  60        Normal Audio-Graph
  61 ************************************
  62
  63 CPU <---> Codec
  64
  65 sound {
  66        compatible = "audio-graph-card2";
  67        links = <&cpu>;
  68 };
  69
  70 CPU {
  71        cpu: port {
  72                bitclock-master;
  73                frame-master;
  74                cpu_ep: endpoint { remote-endpoint = <&codec_ep>; }; };
  75 };
  76
  77 Codec {
  78        port {  codec_ep: endpoint { remote-endpoint = <&cpu_ep>; }; };
  79 };
  80
  81 ************************************
  82        Multi-CPU/Codec
  83 ************************************
  84
  85It has link connection part (= X,x) and list part (= A,B,a,b).
  86"links" is connection part of CPU side (= @).
  87
  88        +----+          +---+
  89 CPU1 --|A  X| <-@----> |x a|-- Codec1
  90 CPU2 --|B   |          |  b|-- Codec2
  91        +----+          +---+
  92
  93 sound {
  94        compatible = "audio-graph-card2";
  95
  96(@)     links = <&mcpu>;
  97
  98        multi {
  99                ports@0 {
 100(@)             mcpu:   port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>;  }; };   // (X) to pair
 101                        port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>;     }; };   // (A) Multi Element
 102                        port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>;     }; };   // (B) Multi Element
 103                };
 104                ports@1 {
 105                        port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>;  }; };   // (x) to pair
 106                        port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };   // (a) Multi Element
 107                        port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };   // (b) Multi Element
 108                };
 109        };
 110 };
 111
 112 CPU {
 113        ports {
 114                bitclock-master;
 115                frame-master;
 116                port@0 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; };
 117                port@1 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; };
 118        };
 119 };
 120
 121 Codec {
 122        ports {
 123                port@0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; };
 124                port@1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; };
 125        };
 126 };
 127
 128 ************************************
 129        DPCM
 130 ************************************
 131
 132                DSP
 133           ************
 134 PCM0 <--> * fe0  be0 * <--> DAI0: Codec Headset
 135 PCM1 <--> * fe1  be1 * <--> DAI1: Codec Speakers
 136 PCM2 <--> * fe2  be2 * <--> DAI2: MODEM
 137 PCM3 <--> * fe3  be3 * <--> DAI3: BT
 138           *      be4 * <--> DAI4: DMIC
 139           *      be5 * <--> DAI5: FM
 140           ************
 141
 142 sound {
 143        compatible = "audio-graph-card2";
 144
 145        // indicate routing
 146        routing = "xxx Playback", "xxx Playback",
 147                  "xxx Playback", "xxx Playback",
 148                  "xxx Playback", "xxx Playback";
 149
 150        // indicate all Front-End, Back-End
 151        links = <&fe0, &fe1, ...,
 152                 &be0, &be1, ...>;
 153
 154        dpcm {
 155                // Front-End
 156                ports@0 {
 157                        fe0: port@0 { fe0_ep: endpoint { remote-endpoint = <&pcm0_ep>; }; };
 158                        fe1: port@1 { fe1_ep: endpoint { remote-endpoint = <&pcm1_ep>; }; };
 159                        ...
 160                };
 161                // Back-End
 162                ports@1 {
 163                        be0: port@0 { be0_ep: endpoint { remote-endpoint = <&dai0_ep>; }; };
 164                        be1: port@1 { be1_ep: endpoint { remote-endpoint = <&dai1_ep>; }; };
 165                        ...
 166                };
 167        };
 168 };
 169
 170 CPU {
 171        ports {
 172                bitclock-master;
 173                frame-master;
 174                port@0 { pcm0_ep: endpoint { remote-endpoint = <&fe0_ep>; }; };
 175                port@1 { pcm1_ep: endpoint { remote-endpoint = <&fe1_ep>; }; };
 176                ...
 177        };
 178 };
 179
 180 Codec {
 181        ports {
 182                port@0 { dai0_ep: endpoint { remote-endpoint = <&be0_ep>; }; };
 183                port@1 { dai1_ep: endpoint { remote-endpoint = <&be1_ep>; }; };
 184                ...
 185        };
 186 };
 187
 188 ************************************
 189        Codec to Codec
 190 ************************************
 191
 192 +--+
 193 |  |<-- Codec0 <- IN
 194 |  |--> Codec1 -> OUT
 195 +--+
 196
 197 sound {
 198        compatible = "audio-graph-card2";
 199
 200        routing = "OUT" ,"DAI1 Playback",
 201                  "DAI0 Capture", "IN";
 202
 203        links = <&c2c>;
 204
 205        codec2codec {
 206                ports {
 207                        rate = <48000>;
 208                c2c:    port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec0_ep>; }; };
 209                        port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
 210        };
 211 };
 212
 213 Codec {
 214        ports {
 215                port@0 {
 216                        bitclock-master;
 217                        frame-master;
 218                         codec0_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; };
 219                port@1 { codec1_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; };
 220        };
 221 };
 222
 223*/
 224
 225enum graph_type {
 226        GRAPH_NORMAL,
 227        GRAPH_DPCM,
 228        GRAPH_C2C,
 229
 230        GRAPH_MULTI,    /* don't use ! Use this only in __graph_get_type() */
 231};
 232
 233#define GRAPH_NODENAME_MULTI    "multi"
 234#define GRAPH_NODENAME_DPCM     "dpcm"
 235#define GRAPH_NODENAME_C2C      "codec2codec"
 236
 237#define graph_ret(priv, ret) _graph_ret(priv, __func__, ret)
 238static inline int _graph_ret(struct simple_util_priv *priv,
 239                               const char *func, int ret)
 240{
 241        return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func);
 242}
 243
 244#define ep_to_port(ep)  of_get_parent(ep)
 245static struct device_node *port_to_ports(struct device_node *port)
 246{
 247        struct device_node *ports = of_get_parent(port);
 248
 249        if (!of_node_name_eq(ports, "ports")) {
 250                of_node_put(ports);
 251                return NULL;
 252        }
 253        return ports;
 254}
 255
 256static enum graph_type __graph_get_type(struct device_node *lnk)
 257{
 258        struct device_node *np, *parent_np;
 259        enum graph_type ret;
 260
 261        /*
 262         * target {
 263         *      ports {
 264         * =>           lnk:    port@0 { ... };
 265         *                      port@1 { ... };
 266         *      };
 267         * };
 268         */
 269        np = of_get_parent(lnk);
 270        if (of_node_name_eq(np, "ports")) {
 271                parent_np = of_get_parent(np);
 272                of_node_put(np);
 273                np = parent_np;
 274        }
 275
 276        if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) {
 277                ret = GRAPH_MULTI;
 278                fw_devlink_purge_absent_suppliers(&np->fwnode);
 279                goto out_put;
 280        }
 281
 282        if (of_node_name_eq(np, GRAPH_NODENAME_DPCM)) {
 283                ret = GRAPH_DPCM;
 284                fw_devlink_purge_absent_suppliers(&np->fwnode);
 285                goto out_put;
 286        }
 287
 288        if (of_node_name_eq(np, GRAPH_NODENAME_C2C)) {
 289                ret = GRAPH_C2C;
 290                fw_devlink_purge_absent_suppliers(&np->fwnode);
 291                goto out_put;
 292        }
 293
 294        ret = GRAPH_NORMAL;
 295
 296out_put:
 297        of_node_put(np);
 298        return ret;
 299
 300}
 301
 302static enum graph_type graph_get_type(struct simple_util_priv *priv,
 303                                      struct device_node *lnk)
 304{
 305        enum graph_type type = __graph_get_type(lnk);
 306
 307        /* GRAPH_MULTI here means GRAPH_NORMAL */
 308        if (type == GRAPH_MULTI)
 309                type = GRAPH_NORMAL;
 310
 311#ifdef DEBUG
 312        {
 313                struct device *dev = simple_priv_to_dev(priv);
 314                const char *str = "Normal";
 315
 316                switch (type) {
 317                case GRAPH_DPCM:
 318                        if (graph_util_is_ports0(lnk))
 319                                str = "DPCM Front-End";
 320                        else
 321                                str = "DPCM Back-End";
 322                        break;
 323                case GRAPH_C2C:
 324                        str = "Codec2Codec";
 325                        break;
 326                default:
 327                        break;
 328                }
 329
 330                dev_dbg(dev, "%pOF (%s)", lnk, str);
 331        }
 332#endif
 333        return type;
 334}
 335
 336static int graph_lnk_is_multi(struct device_node *lnk)
 337{
 338        return __graph_get_type(lnk) == GRAPH_MULTI;
 339}
 340
 341static struct device_node *graph_get_next_multi_ep(struct device_node **port, int idx)
 342{
 343        struct device_node *ports __free(device_node) = port_to_ports(*port);
 344        struct device_node *rep = NULL;
 345
 346        /*
 347         * multi {
 348         *      ports {
 349         * =>   lnk:    port@0 { ...               }; // to pair
 350         *              port@1 { ep { ... = rep0 } }; // Multi Element
 351         *              port@2 { ep { ... = rep1 } }; // Multi Element
 352         *              ...
 353         *      };
 354         * };
 355         *
 356         * xxx {
 357         *      port@0 { rep0 };
 358         *      port@1 { rep1 };
 359         * };
 360         */
 361
 362        /*
 363         * Don't use of_graph_get_next_port() here
 364         *
 365         * In overlay case, "port" are not necessarily in order. So we need to use
 366         * of_graph_get_port_by_id() instead
 367         */
 368        of_node_put(*port);
 369
 370        *port = of_graph_get_port_by_id(ports, idx);
 371        if (*port) {
 372                struct device_node *ep __free(device_node) = of_graph_get_next_port_endpoint(*port, NULL);
 373
 374                rep = of_graph_get_remote_endpoint(ep);
 375        }
 376
 377        return rep;
 378}
 379
 380static const struct snd_soc_ops graph_ops = {
 381        .startup        = simple_util_startup,
 382        .shutdown       = simple_util_shutdown,
 383        .hw_params      = simple_util_hw_params,
 384};
 385
 386static void graph_parse_convert(struct device_node *ep,
 387                                struct simple_dai_props *props)
 388{
 389        struct device_node *port  __free(device_node) = ep_to_port(ep);
 390        struct device_node *ports __free(device_node) = port_to_ports(port);
 391        struct simple_util_data *adata = &props->adata;
 392
 393        simple_util_parse_convert(ports, NULL, adata);
 394        simple_util_parse_convert(port, NULL, adata);
 395        simple_util_parse_convert(ep,   NULL, adata);
 396}
 397
 398static int __graph_parse_node(struct simple_util_priv *priv,
 399                              enum graph_type gtype,
 400                              struct device_node *ep,
 401                              struct link_info *li,
 402                              int is_cpu, int idx)
 403{
 404        struct device *dev = simple_priv_to_dev(priv);
 405        struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
 406        struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
 407        struct snd_soc_dai_link_component *dlc;
 408        struct simple_util_dai *dai;
 409        int ret, is_single_links = 0;
 410
 411        if (is_cpu) {
 412                dlc = snd_soc_link_to_cpu(dai_link, idx);
 413                dai = simple_props_to_dai_cpu(dai_props, idx);
 414        } else {
 415                dlc = snd_soc_link_to_codec(dai_link, idx);
 416                dai = simple_props_to_dai_codec(dai_props, idx);
 417        }
 418
 419        ret = graph_util_parse_dai(priv, ep, dlc, &is_single_links);
 420        if (ret < 0)
 421                goto end;
 422
 423        ret = simple_util_parse_tdm(ep, dai);
 424        if (ret < 0)
 425                goto end;
 426
 427        ret = simple_util_parse_tdm_width_map(priv, ep, dai);
 428        if (ret < 0)
 429                goto end;
 430
 431        ret = simple_util_parse_clk(dev, ep, dai, dlc);
 432        if (ret < 0)
 433                goto end;
 434
 435        /*
 436         * set DAI Name
 437         */
 438        if (!dai_link->name) {
 439                struct snd_soc_dai_link_component *cpus = dlc;
 440                struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx);
 441                char *cpu_multi   = "";
 442                char *codec_multi = "";
 443
 444                if (dai_link->num_cpus > 1)
 445                        cpu_multi = "_multi";
 446                if (dai_link->num_codecs > 1)
 447                        codec_multi = "_multi";
 448
 449                switch (gtype) {
 450                case GRAPH_NORMAL:
 451                        /* run is_cpu only. see audio_graph2_link_normal() */
 452                        if (is_cpu)
 453                                simple_util_set_dailink_name(priv, dai_link, "%s%s-%s%s",
 454                                                               cpus->dai_name,   cpu_multi,
 455                                                             codecs->dai_name, codec_multi);
 456                        break;
 457                case GRAPH_DPCM:
 458                        if (is_cpu)
 459                                simple_util_set_dailink_name(priv, dai_link, "fe.%pOFP.%s%s",
 460                                                cpus->of_node, cpus->dai_name, cpu_multi);
 461                        else
 462                                simple_util_set_dailink_name(priv, dai_link, "be.%pOFP.%s%s",
 463                                                codecs->of_node, codecs->dai_name, codec_multi);
 464                        break;
 465                case GRAPH_C2C:
 466                        /* run is_cpu only. see audio_graph2_link_c2c() */
 467                        if (is_cpu)
 468                                simple_util_set_dailink_name(priv, dai_link, "c2c.%s%s-%s%s",
 469                                                             cpus->dai_name,   cpu_multi,
 470                                                             codecs->dai_name, codec_multi);
 471                        break;
 472                default:
 473                        break;
 474                }
 475        }
 476
 477        /*
 478         * Check "prefix" from top node
 479         * if DPCM-BE case
 480         */
 481        if (!is_cpu && gtype == GRAPH_DPCM) {
 482                struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx);
 483                struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, idx);
 484                struct device_node *rport  __free(device_node) = ep_to_port(ep);
 485                struct device_node *rports __free(device_node) = port_to_ports(rport);
 486
 487                snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix");
 488                snd_soc_of_parse_node_prefix(rport,  cconf, codecs->of_node, "prefix");
 489        }
 490
 491        if (is_cpu) {
 492                struct snd_soc_dai_link_component *cpus = dlc;
 493                struct snd_soc_dai_link_component *platforms = snd_soc_link_to_platform(dai_link, idx);
 494
 495                simple_util_canonicalize_cpu(cpus, is_single_links);
 496                simple_util_canonicalize_platform(platforms, cpus);
 497        }
 498end:
 499        return graph_ret(priv, ret);
 500}
 501
 502static int graph_parse_node_multi_nm(struct simple_util_priv *priv,
 503                                     struct snd_soc_dai_link *dai_link,
 504                                     int *nm_idx, int cpu_idx,
 505                                     struct device_node *mcpu_port)
 506{
 507        /*
 508         *              +---+           +---+
 509         *              |  X|<-@------->|x  |
 510         *              |   |           |   |
 511         *      cpu0 <--|A 1|<--------->|4 a|-> codec0
 512         *      cpu1 <--|B 2|<-----+--->|5 b|-> codec1
 513         *      cpu2 <--|C 3|<----/     +---+
 514         *              +---+
 515         *
 516         * multi {
 517         *      ports {
 518         *              port@0 { mcpu_top_ep    {...  = mcodec_ep;      }; };   // (X) to pair
 519         * <mcpu_port>  port@1 { mcpu0_ep       { ... = cpu0_ep;        };      // (A) Multi Element
 520         *                       mcpu0_ep_0     { ... = mcodec0_ep_0;   }; };   // (1) connected Codec
 521         *              port@2 { mcpu1_ep       { ... = cpu1_ep;        };      // (B) Multi Element
 522         *                       mcpu1_ep_0     { ... = mcodec1_ep_0;   }; };   // (2) connected Codec
 523         *              port@3 { mcpu2_ep       { ... = cpu2_ep;        };      // (C) Multi Element
 524         *                       mcpu2_ep_0     { ... = mcodec1_ep_1;   }; };   // (3) connected Codec
 525         *      };
 526         *
 527         *      ports {
 528         *              port@0 { mcodec_top_ep  {...  = mcpu_ep;        }; };   // (x) to pair
 529         * <mcodec_port>port@1 { mcodec0_ep     { ... = codec0_ep;      };      // (a) Multi Element
 530         *                       mcodec0_ep_0   { ... = mcpu0_ep_0;     }; };   // (4) connected CPU
 531         *              port@2 { mcodec1_ep     { ... = codec1_ep;      };      // (b) Multi Element
 532         *                       mcodec1_ep_0   { ... = mcpu1_ep_0;     };      // (5) connected CPU
 533         *                       mcodec1_ep_1   { ... = mcpu2_ep_0;     }; };   // (5) connected CPU
 534         *      };
 535         * };
 536         */
 537        struct device_node *mcpu_ep             __free(device_node) = of_graph_get_next_port_endpoint(mcpu_port, NULL);
 538        struct device_node *mcpu_ports          __free(device_node) = port_to_ports(mcpu_port);
 539        struct device_node *mcpu_port_top       __free(device_node) = of_graph_get_next_port(mcpu_ports, NULL);
 540        struct device_node *mcpu_ep_top         __free(device_node) = of_graph_get_next_port_endpoint(mcpu_port_top, NULL);
 541        struct device_node *mcodec_ep_top       __free(device_node) = of_graph_get_remote_endpoint(mcpu_ep_top);
 542        struct device_node *mcodec_port_top     __free(device_node) = ep_to_port(mcodec_ep_top);
 543        struct device_node *mcodec_ports        __free(device_node) = port_to_ports(mcodec_port_top);
 544        int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
 545        int ret = -EINVAL;
 546
 547        if (cpu_idx > dai_link->num_cpus)
 548                goto end;
 549
 550        for_each_of_graph_port_endpoint(mcpu_port, mcpu_ep_n) {
 551                int codec_idx = 0;
 552
 553                /* ignore 1st ep which is for element */
 554                if (mcpu_ep_n == mcpu_ep)
 555                        continue;
 556
 557                if (*nm_idx > nm_max)
 558                        break;
 559
 560                struct device_node *mcodec_ep_n __free(device_node) = of_graph_get_remote_endpoint(mcpu_ep_n);
 561                struct device_node *mcodec_port __free(device_node) = ep_to_port(mcodec_ep_n);
 562
 563                ret = -EINVAL;
 564                if (mcodec_ports != port_to_ports(mcodec_port))
 565                        break;
 566
 567                for_each_of_graph_port(mcodec_ports, mcodec_port_i) {
 568
 569                        /* ignore 1st port which is for pair connection */
 570                        if (mcodec_port_top == mcodec_port_i)
 571                                continue;
 572
 573                        if (codec_idx > dai_link->num_codecs)
 574                                break;
 575
 576                        if (mcodec_port_i == mcodec_port) {
 577                                dai_link->ch_maps[*nm_idx].cpu   = cpu_idx;
 578                                dai_link->ch_maps[*nm_idx].codec = codec_idx;
 579
 580                                (*nm_idx)++;
 581                                ret = 0;
 582                                break;
 583                        }
 584                        codec_idx++;
 585                }
 586                if (ret < 0)
 587                        break;
 588        }
 589end:
 590        return graph_ret(priv, ret);
 591}
 592
 593static int graph_parse_node_multi(struct simple_util_priv *priv,
 594                                  enum graph_type gtype,
 595                                  struct device_node *port,
 596                                  struct link_info *li, int is_cpu)
 597{
 598        struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
 599        struct device *dev = simple_priv_to_dev(priv);
 600        int ret = -ENOMEM;
 601        int nm_idx = 0;
 602        int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
 603
 604        /*
 605         * create ch_maps if CPU:Codec = N:M
 606         * DPCM is out of scope
 607         */
 608        if (gtype != GRAPH_DPCM && !dai_link->ch_maps &&
 609            dai_link->num_cpus > 1 && dai_link->num_codecs > 1 &&
 610            dai_link->num_cpus != dai_link->num_codecs) {
 611
 612                dai_link->ch_maps = devm_kcalloc(dev, nm_max,
 613                                        sizeof(struct snd_soc_dai_link_ch_map), GFP_KERNEL);
 614                if (!dai_link->ch_maps)
 615                        goto multi_err;
 616        }
 617
 618        for (int idx = 0;; idx++) {
 619                /*
 620                 * multi {
 621                 *      ports {
 622                 * <port>       port@0 { ...                        }; // to pair
 623                 *              port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element
 624                 *              port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element
 625                 *      };
 626                 * };
 627                 *
 628                 * cpu {
 629                 *      ports {
 630                 * <ep>         port@0 { cpu1_ep   { ... = mcpu1_ep };};
 631                 *      };
 632                 * };
 633                 */
 634                struct device_node *ep __free(device_node) = graph_get_next_multi_ep(&port, idx + 1);
 635                if (!ep)
 636                        break;
 637
 638                ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, idx);
 639                if (ret < 0)
 640                        goto multi_err;
 641
 642                /* CPU:Codec = N:M */
 643                if (is_cpu && dai_link->ch_maps) {
 644                        ret = graph_parse_node_multi_nm(priv, dai_link, &nm_idx, idx, port);
 645                        if (ret < 0)
 646                                goto multi_err;
 647                }
 648        }
 649
 650        if (is_cpu && dai_link->ch_maps && (nm_idx != nm_max))
 651                ret = -EINVAL;
 652
 653multi_err:
 654        return graph_ret(priv, ret);
 655}
 656
 657static int graph_parse_node_single(struct simple_util_priv *priv,
 658                                   enum graph_type gtype,
 659                                   struct device_node *ep,
 660                                   struct link_info *li, int is_cpu)
 661{
 662        return graph_ret(priv, __graph_parse_node(priv, gtype, ep, li, is_cpu, 0));
 663}
 664
 665static int graph_parse_node(struct simple_util_priv *priv,
 666                            enum graph_type gtype,
 667                            struct device_node *ep,
 668                            struct link_info *li, int is_cpu)
 669{
 670        struct device_node *port __free(device_node) = ep_to_port(ep);
 671        int ret;
 672
 673        if (graph_lnk_is_multi(port))
 674                ret = graph_parse_node_multi(priv, gtype, port, li, is_cpu);
 675        else
 676                ret = graph_parse_node_single(priv, gtype, ep, li, is_cpu);
 677
 678        return graph_ret(priv, ret);
 679}
 680
 681static void graph_parse_daifmt(struct device_node *node, unsigned int *daifmt)
 682{
 683        unsigned int fmt;
 684
 685        if (!node)
 686                return;
 687
 688        /*
 689         * see also above "daifmt" explanation
 690         * and samples.
 691         */
 692
 693        /*
 694         *      ports {
 695         * (A)
 696         *              port {
 697         * (B)
 698         *                      endpoint {
 699         * (C)
 700         *                      };
 701         *              };
 702         *      };
 703         * };
 704         */
 705
 706#define update_daifmt(name)                                     \
 707        if (!(*daifmt & SND_SOC_DAIFMT_##name##_MASK) &&        \
 708                 (fmt & SND_SOC_DAIFMT_##name##_MASK))          \
 709                *daifmt |= fmt & SND_SOC_DAIFMT_##name##_MASK
 710
 711        /*
 712         * format
 713         *
 714         * This function is called by (C) -> (B) -> (A) order.
 715         * Set if applicable part was not yet set.
 716         */
 717        fmt = snd_soc_daifmt_parse_format(node, NULL);
 718        update_daifmt(FORMAT);
 719        update_daifmt(CLOCK);
 720        update_daifmt(INV);
 721}
 722
 723static unsigned int graph_parse_bitframe(struct device_node *ep)
 724{
 725        struct device_node *port  __free(device_node) = ep_to_port(ep);
 726        struct device_node *ports __free(device_node) = port_to_ports(port);
 727
 728        return  snd_soc_daifmt_clock_provider_from_bitmap(
 729                        snd_soc_daifmt_parse_clock_provider_as_bitmap(ep,    NULL) |
 730                        snd_soc_daifmt_parse_clock_provider_as_bitmap(port,  NULL) |
 731                        snd_soc_daifmt_parse_clock_provider_as_bitmap(ports, NULL));
 732}
 733
 734static void graph_link_init(struct simple_util_priv *priv,
 735                            struct device_node *lnk,
 736                            struct device_node *ep_cpu,
 737                            struct device_node *ep_codec,
 738                            struct link_info *li,
 739                            int is_cpu_node)
 740{
 741        struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
 742        struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
 743        struct device_node *port_cpu = ep_to_port(ep_cpu);
 744        struct device_node *port_codec = ep_to_port(ep_codec);
 745        struct device_node *multi_cpu_port = NULL, *multi_codec_port = NULL;
 746        struct snd_soc_dai_link_component *dlc;
 747        unsigned int daifmt = 0;
 748        bool playback_only = 0, capture_only = 0;
 749        enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
 750        enum snd_soc_trigger_order trigger_stop  = SND_SOC_TRIGGER_ORDER_DEFAULT;
 751        int multi_cpu_port_idx = 1, multi_codec_port_idx = 1;
 752        int i;
 753
 754        if (graph_lnk_is_multi(port_cpu)) {
 755                multi_cpu_port = port_cpu;
 756                ep_cpu = graph_get_next_multi_ep(&multi_cpu_port, multi_cpu_port_idx++);
 757                of_node_put(port_cpu);
 758                port_cpu = ep_to_port(ep_cpu);
 759        } else {
 760                of_node_get(ep_cpu);
 761        }
 762        struct device_node *ports_cpu __free(device_node) = port_to_ports(port_cpu);
 763
 764        if (graph_lnk_is_multi(port_codec)) {
 765                multi_codec_port = port_codec;
 766                ep_codec = graph_get_next_multi_ep(&multi_codec_port, multi_codec_port_idx++);
 767                of_node_put(port_codec);
 768                port_codec = ep_to_port(ep_codec);
 769        } else {
 770                of_node_get(ep_codec);
 771        }
 772        struct device_node *ports_codec __free(device_node) = port_to_ports(port_codec);
 773
 774        graph_parse_daifmt(ep_cpu,      &daifmt);
 775        graph_parse_daifmt(ep_codec,    &daifmt);
 776        graph_parse_daifmt(port_cpu,    &daifmt);
 777        graph_parse_daifmt(port_codec,  &daifmt);
 778        graph_parse_daifmt(ports_cpu,   &daifmt);
 779        graph_parse_daifmt(ports_codec, &daifmt);
 780        graph_parse_daifmt(lnk,         &daifmt);
 781
 782        graph_util_parse_link_direction(lnk,            &playback_only, &capture_only);
 783        graph_util_parse_link_direction(ports_cpu,      &playback_only, &capture_only);
 784        graph_util_parse_link_direction(ports_codec,    &playback_only, &capture_only);
 785        graph_util_parse_link_direction(port_cpu,       &playback_only, &capture_only);
 786        graph_util_parse_link_direction(port_codec,     &playback_only, &capture_only);
 787        graph_util_parse_link_direction(ep_cpu,         &playback_only, &capture_only);
 788        graph_util_parse_link_direction(ep_codec,       &playback_only, &capture_only);
 789
 790        of_property_read_u32(lnk,               "mclk-fs", &dai_props->mclk_fs);
 791        of_property_read_u32(ports_cpu,         "mclk-fs", &dai_props->mclk_fs);
 792        of_property_read_u32(ports_codec,       "mclk-fs", &dai_props->mclk_fs);
 793        of_property_read_u32(port_cpu,          "mclk-fs", &dai_props->mclk_fs);
 794        of_property_read_u32(port_codec,        "mclk-fs", &dai_props->mclk_fs);
 795        of_property_read_u32(ep_cpu,            "mclk-fs", &dai_props->mclk_fs);
 796        of_property_read_u32(ep_codec,          "mclk-fs", &dai_props->mclk_fs);
 797
 798        graph_util_parse_trigger_order(priv, lnk,               &trigger_start, &trigger_stop);
 799        graph_util_parse_trigger_order(priv, ports_cpu,         &trigger_start, &trigger_stop);
 800        graph_util_parse_trigger_order(priv, ports_codec,       &trigger_start, &trigger_stop);
 801        graph_util_parse_trigger_order(priv, port_cpu,          &trigger_start, &trigger_stop);
 802        graph_util_parse_trigger_order(priv, port_cpu,          &trigger_start, &trigger_stop);
 803        graph_util_parse_trigger_order(priv, ep_cpu,            &trigger_start, &trigger_stop);
 804        graph_util_parse_trigger_order(priv, ep_codec,          &trigger_start, &trigger_stop);
 805
 806        for_each_link_cpus(dai_link, i, dlc) {
 807                dlc->ext_fmt = graph_parse_bitframe(ep_cpu);
 808
 809                if (multi_cpu_port)
 810                        ep_cpu = graph_get_next_multi_ep(&multi_cpu_port, multi_cpu_port_idx++);
 811        }
 812
 813        for_each_link_codecs(dai_link, i, dlc) {
 814                dlc->ext_fmt = graph_parse_bitframe(ep_codec);
 815
 816                if (multi_codec_port)
 817                        ep_codec = graph_get_next_multi_ep(&multi_codec_port, multi_codec_port_idx++);
 818        }
 819
 820        /*** Don't use port_cpu / port_codec after here ***/
 821
 822        dai_link->playback_only = playback_only;
 823        dai_link->capture_only  = capture_only;
 824
 825        dai_link->trigger_start = trigger_start;
 826        dai_link->trigger_stop  = trigger_stop;
 827
 828        dai_link->dai_fmt       = daifmt;
 829        dai_link->init          = simple_util_dai_init;
 830        dai_link->ops           = &graph_ops;
 831        if (priv->ops)
 832                dai_link->ops   = priv->ops;
 833
 834        of_node_put(port_cpu);
 835        of_node_put(port_codec);
 836        of_node_put(ep_cpu);
 837        of_node_put(ep_codec);
 838}
 839
 840int audio_graph2_link_normal(struct simple_util_priv *priv,
 841                             struct device_node *lnk,
 842                             struct link_info *li)
 843{
 844        struct device_node *cpu_port = lnk;
 845        struct device_node *cpu_ep      __free(device_node) = of_graph_get_next_port_endpoint(cpu_port, NULL);
 846        struct device_node *codec_ep    __free(device_node) = of_graph_get_remote_endpoint(cpu_ep);
 847        int ret;
 848
 849        /*
 850         * call Codec first.
 851         * see
 852         *      __graph_parse_node() :: DAI Naming
 853         */
 854        ret = graph_parse_node(priv, GRAPH_NORMAL, codec_ep, li, 0);
 855        if (ret < 0)
 856                goto end;
 857
 858        /*
 859         * call CPU, and set DAI Name
 860         */
 861        ret = graph_parse_node(priv, GRAPH_NORMAL, cpu_ep, li, 1);
 862        if (ret < 0)
 863                goto end;
 864
 865        graph_link_init(priv, lnk, cpu_ep, codec_ep, li, 1);
 866
 867end:
 868        return graph_ret(priv, ret);
 869}
 870EXPORT_SYMBOL_GPL(audio_graph2_link_normal);
 871
 872int audio_graph2_link_dpcm(struct simple_util_priv *priv,
 873                           struct device_node *lnk,
 874                           struct link_info *li)
 875{
 876        struct device_node *ep  __free(device_node) = of_graph_get_next_port_endpoint(lnk, NULL);
 877        struct device_node *rep __free(device_node) = of_graph_get_remote_endpoint(ep);
 878        struct device_node *cpu_ep = NULL;
 879        struct device_node *codec_ep = NULL;
 880        struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
 881        struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
 882        int is_cpu = graph_util_is_ports0(lnk);
 883        int ret;
 884
 885        if (is_cpu) {
 886                cpu_ep = rep;
 887
 888                /*
 889                 * dpcm {
 890                 *      // Front-End
 891                 *      ports@0 {
 892                 * =>           lnk: port@0 { ep: { ... = rep }; };
 893                 *               ...
 894                 *      };
 895                 *      // Back-End
 896                 *      ports@0 {
 897                 *               ...
 898                 *      };
 899                 * };
 900                 *
 901                 * CPU {
 902                 *      rports: ports {
 903                 *              rport: port@0 { rep: { ... = ep } };
 904                 *      }
 905                 * }
 906                 */
 907                /*
 908                 * setup CPU here, Codec is already set as dummy.
 909                 * see
 910                 *      simple_util_init_priv()
 911                 */
 912                dai_link->dynamic               = 1;
 913                dai_link->dpcm_merged_format    = 1;
 914
 915                ret = graph_parse_node(priv, GRAPH_DPCM, cpu_ep, li, 1);
 916                if (ret)
 917                        return ret;
 918
 919        } else {
 920                codec_ep = rep;
 921
 922                /*
 923                 * dpcm {
 924                 *      // Front-End
 925                 *      ports@0 {
 926                 *               ...
 927                 *      };
 928                 *      // Back-End
 929                 *      ports@0 {
 930                 * =>           lnk: port@0 { ep: { ... = rep; }; };
 931                 *               ...
 932                 *      };
 933                 * };
 934                 *
 935                 * Codec {
 936                 *      rports: ports {
 937                 *              rport: port@0 { rep: { ... = ep; }; };
 938                 *      }
 939                 * }
 940                 */
 941                /*
 942                 * setup Codec here, CPU is already set as dummy.
 943                 * see
 944                 *      simple_util_init_priv()
 945                 */
 946
 947                /* BE settings */
 948                dai_link->no_pcm                = 1;
 949                dai_link->be_hw_params_fixup    = simple_util_be_hw_params_fixup;
 950
 951                ret = graph_parse_node(priv, GRAPH_DPCM, codec_ep, li, 0);
 952                if (ret < 0)
 953                        return ret;
 954        }
 955
 956        graph_parse_convert(ep,  dai_props); /* at node of <dpcm> */
 957        graph_parse_convert(rep, dai_props); /* at node of <CPU/Codec> */
 958
 959        graph_link_init(priv, lnk, cpu_ep, codec_ep, li, is_cpu);
 960
 961        return graph_ret(priv, ret);
 962}
 963EXPORT_SYMBOL_GPL(audio_graph2_link_dpcm);
 964
 965int audio_graph2_link_c2c(struct simple_util_priv *priv,
 966                          struct device_node *lnk,
 967                          struct link_info *li)
 968{
 969        struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
 970        struct device_node *port0 = lnk;
 971        struct device_node *ports __free(device_node) = port_to_ports(port0);
 972        struct device_node *port1 __free(device_node) = of_graph_get_next_port(ports, port0);
 973        u32 val = 0;
 974        int ret = -EINVAL;
 975
 976        /*
 977         * codec2codec {
 978         *      ports {
 979         *              rate = <48000>;
 980         * =>   lnk:    port@0 { c2c0_ep: { ... = codec0_ep; }; };
 981         *              port@1 { c2c1_ep: { ... = codec1_ep; }; };
 982         *      };
 983         * };
 984         *
 985         * Codec {
 986         *      ports {
 987         *              port@0 { codec0_ep: ... }; };
 988         *              port@1 { codec1_ep: ... }; };
 989         *      };
 990         * };
 991         */
 992
 993        /*
 994         * Card2 can use original Codec2Codec settings if DT has.
 995         * It will use default settings if no settings on DT.
 996         * see
 997         *      simple_util_init_for_codec2codec()
 998         *
 999         * Add more settings here if needed
1000         */
1001        of_property_read_u32(ports, "rate", &val);
1002        if (val) {
1003                struct device *dev = simple_priv_to_dev(priv);
1004                struct snd_soc_pcm_stream *c2c_conf;
1005
1006                c2c_conf = devm_kzalloc(dev, sizeof(*c2c_conf), GFP_KERNEL);
1007                if (!c2c_conf) {
1008                        /*
1009                         * Clang doesn't allow to use "goto end" before calling __free(),
1010                         * because it bypasses the initialization. Use graph_ret() directly.
1011                         */
1012                        return graph_ret(priv, -ENOMEM);
1013                }
1014
1015                c2c_conf->formats       = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */
1016                c2c_conf->rates         = SNDRV_PCM_RATE_8000_384000;
1017                c2c_conf->rate_min      =
1018                c2c_conf->rate_max      = val;
1019                c2c_conf->channels_min  =
1020                c2c_conf->channels_max  = 2; /* update ME */
1021
1022                dai_link->c2c_params            = c2c_conf;
1023                dai_link->num_c2c_params        = 1;
1024        }
1025
1026        struct device_node *ep0 __free(device_node) = of_graph_get_next_port_endpoint(port0, NULL);
1027        struct device_node *ep1 __free(device_node) = of_graph_get_next_port_endpoint(port1, NULL);
1028
1029        struct device_node *codec0_ep __free(device_node) = of_graph_get_remote_endpoint(ep0);
1030        struct device_node *codec1_ep __free(device_node) = of_graph_get_remote_endpoint(ep1);
1031
1032        /*
1033         * call Codec first.
1034         * see
1035         *      __graph_parse_node() :: DAI Naming
1036         */
1037        ret = graph_parse_node(priv, GRAPH_C2C, codec1_ep, li, 0);
1038        if (ret < 0)
1039                goto end;
1040
1041        /*
1042         * call CPU, and set DAI Name
1043         */
1044        ret = graph_parse_node(priv, GRAPH_C2C, codec0_ep, li, 1);
1045        if (ret < 0)
1046                goto end;
1047
1048        graph_link_init(priv, lnk, codec0_ep, codec1_ep, li, 1);
1049end:
1050        return graph_ret(priv, ret);
1051}
1052EXPORT_SYMBOL_GPL(audio_graph2_link_c2c);
1053
1054static int graph_link(struct simple_util_priv *priv,
1055                      struct graph2_custom_hooks *hooks,
1056                      enum graph_type gtype,
1057                      struct device_node *lnk,
1058                      struct link_info *li)
1059{
1060        struct device *dev = simple_priv_to_dev(priv);
1061        GRAPH2_CUSTOM func = NULL;
1062        int ret = -EINVAL;
1063
1064        switch (gtype) {
1065        case GRAPH_NORMAL:
1066                if (hooks && hooks->custom_normal)
1067                        func = hooks->custom_normal;
1068                else
1069                        func = audio_graph2_link_normal;
1070                break;
1071        case GRAPH_DPCM:
1072                if (hooks && hooks->custom_dpcm)
1073                        func = hooks->custom_dpcm;
1074                else
1075                        func = audio_graph2_link_dpcm;
1076                break;
1077        case GRAPH_C2C:
1078                if (hooks && hooks->custom_c2c)
1079                        func = hooks->custom_c2c;
1080                else
1081                        func = audio_graph2_link_c2c;
1082                break;
1083        default:
1084                break;
1085        }
1086
1087        if (!func) {
1088                dev_err(dev, "non supported gtype (%d)\n", gtype);
1089                goto err;
1090        }
1091
1092        ret = func(priv, lnk, li);
1093        if (ret < 0)
1094                goto err;
1095
1096        li->link++;
1097err:
1098        return graph_ret(priv, ret);
1099}
1100
1101static int graph_counter(struct device_node *lnk)
1102{
1103        /*
1104         * Multi CPU / Codec
1105         *
1106         * multi {
1107         *      ports {
1108         * =>           lnk:    port@0 { ... }; // to pair
1109         *                      port@1 { ... }; // Multi Element
1110         *                      port@2 { ... }; // Multi Element
1111         *                      ...
1112         *      };
1113         * };
1114         *
1115         * ignore first lnk part
1116         */
1117        if (graph_lnk_is_multi(lnk)) {
1118                struct device_node *ports = port_to_ports(lnk);
1119
1120                /*
1121                 * CPU/Codec = N:M case has many endpoints.
1122                 * We can't use of_graph_get_endpoint_count() here
1123                 */
1124                return of_graph_get_port_count(ports) - 1;
1125        }
1126        /*
1127         * Single CPU / Codec
1128         */
1129        else
1130                return 1;
1131}
1132
1133static int graph_count_normal(struct simple_util_priv *priv,
1134                              struct device_node *lnk,
1135                              struct link_info *li)
1136{
1137        struct device_node *cpu_port = lnk;
1138        struct device_node *cpu_ep      __free(device_node) = of_graph_get_next_port_endpoint(cpu_port, NULL);
1139        struct device_node *codec_port  __free(device_node) = of_graph_get_remote_port(cpu_ep);
1140
1141        /*
1142         *      CPU {
1143         * =>           lnk: port { endpoint { .. }; };
1144         *      };
1145         */
1146        /*
1147         * DON'T REMOVE platforms
1148         * see
1149         *      simple-card.c :: simple_count_noml()
1150         */
1151        li->num[li->link].cpus          =
1152        li->num[li->link].platforms     = graph_counter(cpu_port);
1153
1154        li->num[li->link].codecs        = graph_counter(codec_port);
1155
1156        return 0;
1157}
1158
1159static int graph_count_dpcm(struct simple_util_priv *priv,
1160                            struct device_node *lnk,
1161                            struct link_info *li)
1162{
1163        struct device_node *ep          __free(device_node) = of_graph_get_next_port_endpoint(lnk, NULL);
1164        struct device_node *rport       __free(device_node) = of_graph_get_remote_port(ep);
1165
1166        /*
1167         * dpcm {
1168         *      // Front-End
1169         *      ports@0 {
1170         * =>           lnk: port@0 { endpoint { ... }; };
1171         *               ...
1172         *      };
1173         *      // Back-End
1174         *      ports@1 {
1175         * =>           lnk: port@0 { endpoint { ... }; };
1176         *               ...
1177         *      };
1178         * };
1179         */
1180
1181        if (graph_util_is_ports0(lnk)) {
1182                /*
1183                 * DON'T REMOVE platforms
1184                 * see
1185                 *      simple-card.c :: simple_count_noml()
1186                 */
1187                li->num[li->link].cpus          = graph_counter(rport); /* FE */
1188                li->num[li->link].platforms     = graph_counter(rport);
1189        } else {
1190                li->num[li->link].codecs        = graph_counter(rport); /* BE */
1191        }
1192
1193        return 0;
1194}
1195
1196static int graph_count_c2c(struct simple_util_priv *priv,
1197                           struct device_node *lnk,
1198                           struct link_info *li)
1199{
1200        struct device_node *ports       __free(device_node) = port_to_ports(lnk);
1201        struct device_node *port0       = of_node_get(lnk);
1202        struct device_node *port1       = of_node_get(of_graph_get_next_port(ports, of_node_get(port0)));
1203        struct device_node *ep0         __free(device_node) = of_graph_get_next_port_endpoint(port0, NULL);
1204        struct device_node *ep1         __free(device_node) = of_graph_get_next_port_endpoint(port1, NULL);
1205        struct device_node *codec0      __free(device_node) = of_graph_get_remote_port(ep0);
1206        struct device_node *codec1      __free(device_node) = of_graph_get_remote_port(ep1);
1207
1208        /*
1209         * codec2codec {
1210         *      ports {
1211         * =>   lnk:    port@0 { endpoint { ... }; };
1212         *              port@1 { endpoint { ... }; };
1213         *      };
1214         * };
1215         */
1216        /*
1217         * DON'T REMOVE platforms
1218         * see
1219         *      simple-card.c :: simple_count_noml()
1220         */
1221        li->num[li->link].cpus          =
1222        li->num[li->link].platforms     = graph_counter(codec0);
1223
1224        li->num[li->link].codecs        = graph_counter(codec1);
1225
1226        return 0;
1227}
1228
1229static int graph_count(struct simple_util_priv *priv,
1230                       struct graph2_custom_hooks *hooks,
1231                       enum graph_type gtype,
1232                       struct device_node *lnk,
1233                       struct link_info *li)
1234{
1235        struct device *dev = simple_priv_to_dev(priv);
1236        GRAPH2_CUSTOM func = NULL;
1237        int ret = -EINVAL;
1238
1239        if (li->link >= SNDRV_MAX_LINKS) {
1240                dev_err(dev, "too many links\n");
1241                return ret;
1242        }
1243
1244        switch (gtype) {
1245        case GRAPH_NORMAL:
1246                func = graph_count_normal;
1247                break;
1248        case GRAPH_DPCM:
1249                func = graph_count_dpcm;
1250                break;
1251        case GRAPH_C2C:
1252                func = graph_count_c2c;
1253                break;
1254        default:
1255                break;
1256        }
1257
1258        if (!func) {
1259                dev_err(dev, "non supported gtype (%d)\n", gtype);
1260                goto err;
1261        }
1262
1263        ret = func(priv, lnk, li);
1264        if (ret < 0)
1265                goto err;
1266
1267        li->link++;
1268err:
1269        return graph_ret(priv, ret);
1270}
1271
1272static int graph_for_each_link(struct simple_util_priv *priv,
1273                               struct graph2_custom_hooks *hooks,
1274                               struct link_info *li,
1275                               int (*func)(struct simple_util_priv *priv,
1276                                           struct graph2_custom_hooks *hooks,
1277                                           enum graph_type gtype,
1278                                           struct device_node *lnk,
1279                                           struct link_info *li))
1280{
1281        struct of_phandle_iterator it;
1282        struct device *dev = simple_priv_to_dev(priv);
1283        struct device_node *node = dev->of_node;
1284        struct device_node *lnk;
1285        enum graph_type gtype;
1286        int rc, ret = 0;
1287
1288        /* loop for all listed CPU port */
1289        of_for_each_phandle(&it, rc, node, "links", NULL, 0) {
1290                lnk = it.node;
1291
1292                gtype = graph_get_type(priv, lnk);
1293
1294                ret = func(priv, hooks, gtype, lnk, li);
1295                if (ret < 0)
1296                        break;
1297        }
1298
1299        return graph_ret(priv, ret);
1300}
1301
1302int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
1303                          struct graph2_custom_hooks *hooks)
1304{
1305        struct snd_soc_card *card = simple_priv_to_card(priv);
1306        int ret;
1307
1308        struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
1309        if (!li)
1310                return -ENOMEM;
1311
1312        card->probe     = graph_util_card_probe;
1313        card->owner     = THIS_MODULE;
1314        card->dev       = dev;
1315
1316        if ((hooks) && (hooks)->hook_pre) {
1317                ret = (hooks)->hook_pre(priv);
1318                if (ret < 0)
1319                        goto err;
1320        }
1321
1322        ret = graph_for_each_link(priv, hooks, li, graph_count);
1323        if (!li->link)
1324                ret = -EINVAL;
1325        if (ret < 0)
1326                goto err;
1327
1328        ret = simple_util_init_priv(priv, li);
1329        if (ret < 0)
1330                goto err;
1331
1332        priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
1333        if (IS_ERR(priv->pa_gpio)) {
1334                ret = PTR_ERR(priv->pa_gpio);
1335                dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
1336                goto err;
1337        }
1338
1339        ret = simple_util_parse_widgets(card, NULL);
1340        if (ret < 0)
1341                goto err;
1342
1343        ret = simple_util_parse_routing(card, NULL);
1344        if (ret < 0)
1345                goto err;
1346
1347        memset(li, 0, sizeof(*li));
1348        ret = graph_for_each_link(priv, hooks, li, graph_link);
1349        if (ret < 0)
1350                goto err;
1351
1352        ret = simple_util_parse_card_name(priv, NULL);
1353        if (ret < 0)
1354                goto err;
1355
1356        snd_soc_card_set_drvdata(card, priv);
1357
1358        if ((hooks) && (hooks)->hook_post) {
1359                ret = (hooks)->hook_post(priv);
1360                if (ret < 0)
1361                        goto err;
1362        }
1363
1364        simple_util_debug_info(priv);
1365
1366        ret = snd_soc_of_parse_aux_devs(card, "aux-devs");
1367        if (ret < 0)
1368                goto err;
1369
1370        ret = devm_snd_soc_register_card(dev, card);
1371err:
1372        if (ret < 0)
1373                dev_err_probe(dev, ret, "parse error\n");
1374
1375        return graph_ret(priv, ret);
1376}
1377EXPORT_SYMBOL_GPL(audio_graph2_parse_of);
1378
1379static int graph_probe(struct platform_device *pdev)
1380{
1381        struct simple_util_priv *priv;
1382        struct device *dev = &pdev->dev;
1383
1384        /* Allocate the private data and the DAI link array */
1385        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1386        if (!priv)
1387                return -ENOMEM;
1388
1389        return audio_graph2_parse_of(priv, dev, NULL);
1390}
1391
1392static const struct of_device_id graph_of_match[] = {
1393        { .compatible = "audio-graph-card2", },
1394        {},
1395};
1396MODULE_DEVICE_TABLE(of, graph_of_match);
1397
1398static struct platform_driver graph_card = {
1399        .driver = {
1400                .name = "asoc-audio-graph-card2",
1401                .pm = &snd_soc_pm_ops,
1402                .of_match_table = graph_of_match,
1403        },
1404        .probe  = graph_probe,
1405        .remove = simple_util_remove,
1406};
1407module_platform_driver(graph_card);
1408
1409MODULE_ALIAS("platform:asoc-audio-graph-card2");
1410MODULE_LICENSE("GPL v2");
1411MODULE_DESCRIPTION("ASoC Audio Graph Card2");
1412MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
1413