Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // ASoC simple sound card support
0004 //
0005 // Copyright (C) 2012 Renesas Solutions Corp.
0006 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
0007 
0008 #include <linux/clk.h>
0009 #include <linux/device.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_device.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/string.h>
0015 #include <sound/simple_card.h>
0016 #include <sound/soc-dai.h>
0017 #include <sound/soc.h>
0018 
0019 #define DPCM_SELECTABLE 1
0020 
0021 #define DAI "sound-dai"
0022 #define CELL    "#sound-dai-cells"
0023 #define PREFIX  "simple-audio-card,"
0024 
0025 static const struct snd_soc_ops simple_ops = {
0026     .startup    = asoc_simple_startup,
0027     .shutdown   = asoc_simple_shutdown,
0028     .hw_params  = asoc_simple_hw_params,
0029 };
0030 
0031 static int asoc_simple_parse_platform(struct device_node *node,
0032                       struct snd_soc_dai_link_component *dlc)
0033 {
0034     struct of_phandle_args args;
0035     int ret;
0036 
0037     if (!node)
0038         return 0;
0039 
0040     /*
0041      * Get node via "sound-dai = <&phandle port>"
0042      * it will be used as xxx_of_node on soc_bind_dai_link()
0043      */
0044     ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
0045     if (ret)
0046         return ret;
0047 
0048     /* dai_name is not required and may not exist for plat component */
0049 
0050     dlc->of_node = args.np;
0051 
0052     return 0;
0053 }
0054 
0055 static int asoc_simple_parse_dai(struct device_node *node,
0056                  struct snd_soc_dai_link_component *dlc,
0057                  int *is_single_link)
0058 {
0059     struct of_phandle_args args;
0060     int ret;
0061 
0062     if (!node)
0063         return 0;
0064 
0065     /*
0066      * Get node via "sound-dai = <&phandle port>"
0067      * it will be used as xxx_of_node on soc_bind_dai_link()
0068      */
0069     ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
0070     if (ret)
0071         return ret;
0072 
0073     /*
0074      * FIXME
0075      *
0076      * Here, dlc->dai_name is pointer to CPU/Codec DAI name.
0077      * If user unbinded CPU or Codec driver, but not for Sound Card,
0078      * dlc->dai_name is keeping unbinded CPU or Codec
0079      * driver's pointer.
0080      *
0081      * If user re-bind CPU or Codec driver again, ALSA SoC will try
0082      * to rebind Card via snd_soc_try_rebind_card(), but because of
0083      * above reason, it might can't bind Sound Card.
0084      * Because Sound Card is pointing to released dai_name pointer.
0085      *
0086      * To avoid this rebind Card issue,
0087      * 1) It needs to alloc memory to keep dai_name eventhough
0088      *    CPU or Codec driver was unbinded, or
0089      * 2) user need to rebind Sound Card everytime
0090      *    if he unbinded CPU or Codec.
0091      */
0092     ret = snd_soc_of_get_dai_name(node, &dlc->dai_name);
0093     if (ret < 0)
0094         return ret;
0095 
0096     dlc->of_node = args.np;
0097 
0098     if (is_single_link)
0099         *is_single_link = !args.args_count;
0100 
0101     return 0;
0102 }
0103 
0104 static void simple_parse_convert(struct device *dev,
0105                  struct device_node *np,
0106                  struct asoc_simple_data *adata)
0107 {
0108     struct device_node *top = dev->of_node;
0109     struct device_node *node = of_get_parent(np);
0110 
0111     asoc_simple_parse_convert(top,  PREFIX, adata);
0112     asoc_simple_parse_convert(node, PREFIX, adata);
0113     asoc_simple_parse_convert(node, NULL,   adata);
0114     asoc_simple_parse_convert(np,   NULL,   adata);
0115 
0116     of_node_put(node);
0117 }
0118 
0119 static void simple_parse_mclk_fs(struct device_node *top,
0120                  struct device_node *np,
0121                  struct simple_dai_props *props,
0122                  char *prefix)
0123 {
0124     struct device_node *node = of_get_parent(np);
0125     char prop[128];
0126 
0127     snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX);
0128     of_property_read_u32(top,   prop, &props->mclk_fs);
0129 
0130     snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
0131     of_property_read_u32(node,  prop, &props->mclk_fs);
0132     of_property_read_u32(np,    prop, &props->mclk_fs);
0133 
0134     of_node_put(node);
0135 }
0136 
0137 static int simple_parse_node(struct asoc_simple_priv *priv,
0138                  struct device_node *np,
0139                  struct link_info *li,
0140                  char *prefix,
0141                  int *cpu)
0142 {
0143     struct device *dev = simple_priv_to_dev(priv);
0144     struct device_node *top = dev->of_node;
0145     struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
0146     struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
0147     struct snd_soc_dai_link_component *dlc;
0148     struct asoc_simple_dai *dai;
0149     int ret;
0150 
0151     if (cpu) {
0152         dlc = asoc_link_to_cpu(dai_link, 0);
0153         dai = simple_props_to_dai_cpu(dai_props, 0);
0154     } else {
0155         dlc = asoc_link_to_codec(dai_link, 0);
0156         dai = simple_props_to_dai_codec(dai_props, 0);
0157     }
0158 
0159     simple_parse_mclk_fs(top, np, dai_props, prefix);
0160 
0161     ret = asoc_simple_parse_dai(np, dlc, cpu);
0162     if (ret)
0163         return ret;
0164 
0165     ret = asoc_simple_parse_clk(dev, np, dai, dlc);
0166     if (ret)
0167         return ret;
0168 
0169     ret = asoc_simple_parse_tdm(np, dai);
0170     if (ret)
0171         return ret;
0172 
0173     return 0;
0174 }
0175 
0176 static int simple_link_init(struct asoc_simple_priv *priv,
0177                 struct device_node *node,
0178                 struct device_node *codec,
0179                 struct link_info *li,
0180                 char *prefix, char *name)
0181 {
0182     struct device *dev = simple_priv_to_dev(priv);
0183     struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
0184     int ret;
0185 
0186     ret = asoc_simple_parse_daifmt(dev, node, codec,
0187                        prefix, &dai_link->dai_fmt);
0188     if (ret < 0)
0189         return 0;
0190 
0191     dai_link->init          = asoc_simple_dai_init;
0192     dai_link->ops           = &simple_ops;
0193 
0194     return asoc_simple_set_dailink_name(dev, dai_link, name);
0195 }
0196 
0197 static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
0198                    struct device_node *np,
0199                    struct device_node *codec,
0200                    struct link_info *li,
0201                    bool is_top)
0202 {
0203     struct device *dev = simple_priv_to_dev(priv);
0204     struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
0205     struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
0206     struct device_node *top = dev->of_node;
0207     struct device_node *node = of_get_parent(np);
0208     char *prefix = "";
0209     char dai_name[64];
0210     int ret;
0211 
0212     dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
0213 
0214     /* For single DAI link & old style of DT node */
0215     if (is_top)
0216         prefix = PREFIX;
0217 
0218     if (li->cpu) {
0219         struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
0220         struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
0221         int is_single_links = 0;
0222 
0223         /* Codec is dummy */
0224 
0225         /* FE settings */
0226         dai_link->dynamic       = 1;
0227         dai_link->dpcm_merged_format    = 1;
0228 
0229         ret = simple_parse_node(priv, np, li, prefix, &is_single_links);
0230         if (ret < 0)
0231             goto out_put_node;
0232 
0233         snprintf(dai_name, sizeof(dai_name), "fe.%s", cpus->dai_name);
0234 
0235         asoc_simple_canonicalize_cpu(cpus, is_single_links);
0236         asoc_simple_canonicalize_platform(platforms, cpus);
0237     } else {
0238         struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
0239         struct snd_soc_codec_conf *cconf;
0240 
0241         /* CPU is dummy */
0242 
0243         /* BE settings */
0244         dai_link->no_pcm        = 1;
0245         dai_link->be_hw_params_fixup    = asoc_simple_be_hw_params_fixup;
0246 
0247         cconf   = simple_props_to_codec_conf(dai_props, 0);
0248 
0249         ret = simple_parse_node(priv, np, li, prefix, NULL);
0250         if (ret < 0)
0251             goto out_put_node;
0252 
0253         snprintf(dai_name, sizeof(dai_name), "be.%s", codecs->dai_name);
0254 
0255         /* check "prefix" from top node */
0256         snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
0257                           PREFIX "prefix");
0258         snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
0259                          "prefix");
0260         snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
0261                          "prefix");
0262     }
0263 
0264     simple_parse_convert(dev, np, &dai_props->adata);
0265 
0266     snd_soc_dai_link_set_capabilities(dai_link);
0267 
0268     ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
0269 
0270 out_put_node:
0271     li->link++;
0272 
0273     of_node_put(node);
0274     return ret;
0275 }
0276 
0277 static int simple_dai_link_of(struct asoc_simple_priv *priv,
0278                   struct device_node *np,
0279                   struct device_node *codec,
0280                   struct link_info *li,
0281                   bool is_top)
0282 {
0283     struct device *dev = simple_priv_to_dev(priv);
0284     struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
0285     struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
0286     struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
0287     struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
0288     struct device_node *cpu = NULL;
0289     struct device_node *node = NULL;
0290     struct device_node *plat = NULL;
0291     char dai_name[64];
0292     char prop[128];
0293     char *prefix = "";
0294     int ret, single_cpu = 0;
0295 
0296     cpu  = np;
0297     node = of_get_parent(np);
0298 
0299     dev_dbg(dev, "link_of (%pOF)\n", node);
0300 
0301     /* For single DAI link & old style of DT node */
0302     if (is_top)
0303         prefix = PREFIX;
0304 
0305     snprintf(prop, sizeof(prop), "%splat", prefix);
0306     plat = of_get_child_by_name(node, prop);
0307 
0308     ret = simple_parse_node(priv, cpu, li, prefix, &single_cpu);
0309     if (ret < 0)
0310         goto dai_link_of_err;
0311 
0312     ret = simple_parse_node(priv, codec, li, prefix, NULL);
0313     if (ret < 0)
0314         goto dai_link_of_err;
0315 
0316     ret = asoc_simple_parse_platform(plat, platforms);
0317     if (ret < 0)
0318         goto dai_link_of_err;
0319 
0320     snprintf(dai_name, sizeof(dai_name),
0321          "%s-%s", cpus->dai_name, codecs->dai_name);
0322 
0323     asoc_simple_canonicalize_cpu(cpus, single_cpu);
0324     asoc_simple_canonicalize_platform(platforms, cpus);
0325 
0326     ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
0327 
0328 dai_link_of_err:
0329     of_node_put(plat);
0330     of_node_put(node);
0331 
0332     li->link++;
0333 
0334     return ret;
0335 }
0336 
0337 static int __simple_for_each_link(struct asoc_simple_priv *priv,
0338             struct link_info *li,
0339             int (*func_noml)(struct asoc_simple_priv *priv,
0340                      struct device_node *np,
0341                      struct device_node *codec,
0342                      struct link_info *li, bool is_top),
0343             int (*func_dpcm)(struct asoc_simple_priv *priv,
0344                      struct device_node *np,
0345                      struct device_node *codec,
0346                      struct link_info *li, bool is_top))
0347 {
0348     struct device *dev = simple_priv_to_dev(priv);
0349     struct device_node *top = dev->of_node;
0350     struct device_node *node;
0351     uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
0352     bool is_top = 0;
0353     int ret = 0;
0354 
0355     /* Check if it has dai-link */
0356     node = of_get_child_by_name(top, PREFIX "dai-link");
0357     if (!node) {
0358         node = of_node_get(top);
0359         is_top = 1;
0360     }
0361 
0362     /* loop for all dai-link */
0363     do {
0364         struct asoc_simple_data adata;
0365         struct device_node *codec;
0366         struct device_node *plat;
0367         struct device_node *np;
0368         int num = of_get_child_count(node);
0369 
0370         /* get codec */
0371         codec = of_get_child_by_name(node, is_top ?
0372                          PREFIX "codec" : "codec");
0373         if (!codec) {
0374             ret = -ENODEV;
0375             goto error;
0376         }
0377         /* get platform */
0378         plat = of_get_child_by_name(node, is_top ?
0379                         PREFIX "plat" : "plat");
0380 
0381         /* get convert-xxx property */
0382         memset(&adata, 0, sizeof(adata));
0383         for_each_child_of_node(node, np)
0384             simple_parse_convert(dev, np, &adata);
0385 
0386         /* loop for all CPU/Codec node */
0387         for_each_child_of_node(node, np) {
0388             if (plat == np)
0389                 continue;
0390             /*
0391              * It is DPCM
0392              * if it has many CPUs,
0393              * or has convert-xxx property
0394              */
0395             if (dpcm_selectable &&
0396                 (num > 2 ||
0397                  adata.convert_rate || adata.convert_channels)) {
0398                 /*
0399                  * np
0400                  *   |1(CPU)|0(Codec)  li->cpu
0401                  * CPU   |Pass  |return
0402                  * Codec |return|Pass
0403                  */
0404                 if (li->cpu != (np == codec))
0405                     ret = func_dpcm(priv, np, codec, li, is_top);
0406             /* else normal sound */
0407             } else {
0408                 /*
0409                  * np
0410                  *   |1(CPU)|0(Codec)  li->cpu
0411                  * CPU   |Pass  |return
0412                  * Codec |return|return
0413                  */
0414                 if (li->cpu && (np != codec))
0415                     ret = func_noml(priv, np, codec, li, is_top);
0416             }
0417 
0418             if (ret < 0) {
0419                 of_node_put(codec);
0420                 of_node_put(np);
0421                 goto error;
0422             }
0423         }
0424 
0425         of_node_put(codec);
0426         node = of_get_next_child(top, node);
0427     } while (!is_top && node);
0428 
0429  error:
0430     of_node_put(node);
0431     return ret;
0432 }
0433 
0434 static int simple_for_each_link(struct asoc_simple_priv *priv,
0435                 struct link_info *li,
0436                 int (*func_noml)(struct asoc_simple_priv *priv,
0437                          struct device_node *np,
0438                          struct device_node *codec,
0439                          struct link_info *li, bool is_top),
0440                 int (*func_dpcm)(struct asoc_simple_priv *priv,
0441                          struct device_node *np,
0442                          struct device_node *codec,
0443                          struct link_info *li, bool is_top))
0444 {
0445     int ret;
0446     /*
0447      * Detect all CPU first, and Detect all Codec 2nd.
0448      *
0449      * In Normal sound case, all DAIs are detected
0450      * as "CPU-Codec".
0451      *
0452      * In DPCM sound case,
0453      * all CPUs   are detected as "CPU-dummy", and
0454      * all Codecs are detected as "dummy-Codec".
0455      * To avoid random sub-device numbering,
0456      * detect "dummy-Codec" in last;
0457      */
0458     for (li->cpu = 1; li->cpu >= 0; li->cpu--) {
0459         ret = __simple_for_each_link(priv, li, func_noml, func_dpcm);
0460         if (ret < 0)
0461             break;
0462     }
0463 
0464     return ret;
0465 }
0466 
0467 static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
0468 {
0469     struct snd_soc_card *card = simple_priv_to_card(priv);
0470     int ret;
0471 
0472     ret = asoc_simple_parse_widgets(card, PREFIX);
0473     if (ret < 0)
0474         return ret;
0475 
0476     ret = asoc_simple_parse_routing(card, PREFIX);
0477     if (ret < 0)
0478         return ret;
0479 
0480     ret = asoc_simple_parse_pin_switches(card, PREFIX);
0481     if (ret < 0)
0482         return ret;
0483 
0484     /* Single/Muti DAI link(s) & New style of DT node */
0485     memset(li, 0, sizeof(*li));
0486     ret = simple_for_each_link(priv, li,
0487                    simple_dai_link_of,
0488                    simple_dai_link_of_dpcm);
0489     if (ret < 0)
0490         return ret;
0491 
0492     ret = asoc_simple_parse_card_name(card, PREFIX);
0493     if (ret < 0)
0494         return ret;
0495 
0496     ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
0497 
0498     return ret;
0499 }
0500 
0501 static int simple_count_noml(struct asoc_simple_priv *priv,
0502                  struct device_node *np,
0503                  struct device_node *codec,
0504                  struct link_info *li, bool is_top)
0505 {
0506     if (li->link >= SNDRV_MAX_LINKS) {
0507         struct device *dev = simple_priv_to_dev(priv);
0508 
0509         dev_err(dev, "too many links\n");
0510         return -EINVAL;
0511     }
0512 
0513     li->num[li->link].cpus      = 1;
0514     li->num[li->link].codecs    = 1;
0515     li->num[li->link].platforms = 1;
0516 
0517     li->link += 1;
0518 
0519     return 0;
0520 }
0521 
0522 static int simple_count_dpcm(struct asoc_simple_priv *priv,
0523                  struct device_node *np,
0524                  struct device_node *codec,
0525                  struct link_info *li, bool is_top)
0526 {
0527     if (li->link >= SNDRV_MAX_LINKS) {
0528         struct device *dev = simple_priv_to_dev(priv);
0529 
0530         dev_err(dev, "too many links\n");
0531         return -EINVAL;
0532     }
0533 
0534     if (li->cpu) {
0535         li->num[li->link].cpus      = 1;
0536         li->num[li->link].platforms = 1;
0537 
0538         li->link++; /* CPU-dummy */
0539     } else {
0540         li->num[li->link].codecs    = 1;
0541 
0542         li->link++; /* dummy-Codec */
0543     }
0544 
0545     return 0;
0546 }
0547 
0548 static int simple_get_dais_count(struct asoc_simple_priv *priv,
0549                  struct link_info *li)
0550 {
0551     struct device *dev = simple_priv_to_dev(priv);
0552     struct device_node *top = dev->of_node;
0553 
0554     /*
0555      * link_num :   number of links.
0556      *      CPU-Codec / CPU-dummy / dummy-Codec
0557      * dais_num :   number of DAIs
0558      * ccnf_num :   number of codec_conf
0559      *      same number for "dummy-Codec"
0560      *
0561      * ex1)
0562      * CPU0 --- Codec0  link : 5
0563      * CPU1 --- Codec1  dais : 7
0564      * CPU2 -/      ccnf : 1
0565      * CPU3 --- Codec2
0566      *
0567      *  => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
0568      *  => 7 DAIs  = 4xCPU + 3xCodec
0569      *  => 1 ccnf  = 1xdummy-Codec
0570      *
0571      * ex2)
0572      * CPU0 --- Codec0  link : 5
0573      * CPU1 --- Codec1  dais : 6
0574      * CPU2 -/      ccnf : 1
0575      * CPU3 -/
0576      *
0577      *  => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
0578      *  => 6 DAIs  = 4xCPU + 2xCodec
0579      *  => 1 ccnf  = 1xdummy-Codec
0580      *
0581      * ex3)
0582      * CPU0 --- Codec0  link : 6
0583      * CPU1 -/      dais : 6
0584      * CPU2 --- Codec1  ccnf : 2
0585      * CPU3 -/
0586      *
0587      *  => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
0588      *  => 6 DAIs  = 4xCPU + 2xCodec
0589      *  => 2 ccnf  = 2xdummy-Codec
0590      *
0591      * ex4)
0592      * CPU0 --- Codec0 (convert-rate)   link : 3
0593      * CPU1 --- Codec1          dais : 4
0594      *                  ccnf : 1
0595      *
0596      *  => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
0597      *  => 4 DAIs  = 2xCPU + 2xCodec
0598      *  => 1 ccnf  = 1xdummy-Codec
0599      */
0600     if (!top) {
0601         li->num[0].cpus     = 1;
0602         li->num[0].codecs   = 1;
0603         li->num[0].platforms    = 1;
0604 
0605         li->link = 1;
0606         return 0;
0607     }
0608 
0609     return simple_for_each_link(priv, li,
0610                     simple_count_noml,
0611                     simple_count_dpcm);
0612 }
0613 
0614 static int simple_soc_probe(struct snd_soc_card *card)
0615 {
0616     struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
0617     int ret;
0618 
0619     ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
0620     if (ret < 0)
0621         return ret;
0622 
0623     ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
0624     if (ret < 0)
0625         return ret;
0626 
0627     return 0;
0628 }
0629 
0630 static int asoc_simple_probe(struct platform_device *pdev)
0631 {
0632     struct asoc_simple_priv *priv;
0633     struct device *dev = &pdev->dev;
0634     struct device_node *np = dev->of_node;
0635     struct snd_soc_card *card;
0636     struct link_info *li;
0637     int ret;
0638 
0639     /* Allocate the private data and the DAI link array */
0640     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0641     if (!priv)
0642         return -ENOMEM;
0643 
0644     card = simple_priv_to_card(priv);
0645     card->owner     = THIS_MODULE;
0646     card->dev       = dev;
0647     card->probe     = simple_soc_probe;
0648     card->driver_name       = "simple-card";
0649 
0650     li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
0651     if (!li)
0652         return -ENOMEM;
0653 
0654     ret = simple_get_dais_count(priv, li);
0655     if (ret < 0)
0656         return ret;
0657 
0658     if (!li->link)
0659         return -EINVAL;
0660 
0661     ret = asoc_simple_init_priv(priv, li);
0662     if (ret < 0)
0663         return ret;
0664 
0665     if (np && of_device_is_available(np)) {
0666 
0667         ret = simple_parse_of(priv, li);
0668         if (ret < 0) {
0669             dev_err_probe(dev, ret, "parse error\n");
0670             goto err;
0671         }
0672 
0673     } else {
0674         struct asoc_simple_card_info *cinfo;
0675         struct snd_soc_dai_link_component *cpus;
0676         struct snd_soc_dai_link_component *codecs;
0677         struct snd_soc_dai_link_component *platform;
0678         struct snd_soc_dai_link *dai_link = priv->dai_link;
0679         struct simple_dai_props *dai_props = priv->dai_props;
0680 
0681         cinfo = dev->platform_data;
0682         if (!cinfo) {
0683             dev_err(dev, "no info for asoc-simple-card\n");
0684             return -EINVAL;
0685         }
0686 
0687         if (!cinfo->name ||
0688             !cinfo->codec_dai.name ||
0689             !cinfo->codec ||
0690             !cinfo->platform ||
0691             !cinfo->cpu_dai.name) {
0692             dev_err(dev, "insufficient asoc_simple_card_info settings\n");
0693             return -EINVAL;
0694         }
0695 
0696         cpus            = dai_link->cpus;
0697         cpus->dai_name      = cinfo->cpu_dai.name;
0698 
0699         codecs          = dai_link->codecs;
0700         codecs->name        = cinfo->codec;
0701         codecs->dai_name    = cinfo->codec_dai.name;
0702 
0703         platform        = dai_link->platforms;
0704         platform->name      = cinfo->platform;
0705 
0706         card->name      = (cinfo->card) ? cinfo->card : cinfo->name;
0707         dai_link->name      = cinfo->name;
0708         dai_link->stream_name   = cinfo->name;
0709         dai_link->dai_fmt   = cinfo->daifmt;
0710         dai_link->init      = asoc_simple_dai_init;
0711         memcpy(dai_props->cpu_dai, &cinfo->cpu_dai,
0712                     sizeof(*dai_props->cpu_dai));
0713         memcpy(dai_props->codec_dai, &cinfo->codec_dai,
0714                     sizeof(*dai_props->codec_dai));
0715     }
0716 
0717     snd_soc_card_set_drvdata(card, priv);
0718 
0719     asoc_simple_debug_info(priv);
0720 
0721     ret = devm_snd_soc_register_card(dev, card);
0722     if (ret < 0)
0723         goto err;
0724 
0725     devm_kfree(dev, li);
0726     return 0;
0727 err:
0728     asoc_simple_clean_reference(card);
0729 
0730     return ret;
0731 }
0732 
0733 static const struct of_device_id simple_of_match[] = {
0734     { .compatible = "simple-audio-card", },
0735     { .compatible = "simple-scu-audio-card",
0736       .data = (void *)DPCM_SELECTABLE },
0737     {},
0738 };
0739 MODULE_DEVICE_TABLE(of, simple_of_match);
0740 
0741 static struct platform_driver asoc_simple_card = {
0742     .driver = {
0743         .name = "asoc-simple-card",
0744         .pm = &snd_soc_pm_ops,
0745         .of_match_table = simple_of_match,
0746     },
0747     .probe = asoc_simple_probe,
0748     .remove = asoc_simple_remove,
0749 };
0750 
0751 module_platform_driver(asoc_simple_card);
0752 
0753 MODULE_ALIAS("platform:asoc-simple-card");
0754 MODULE_LICENSE("GPL v2");
0755 MODULE_DESCRIPTION("ASoC Simple Sound Card");
0756 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");