linux/sound/soc/generic/simple-card-utils.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// simple-card-utils.c
   4//
   5// Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   6
   7#include <linux/clk.h>
   8#include <linux/gpio.h>
   9#include <linux/gpio/consumer.h>
  10#include <linux/module.h>
  11#include <linux/of.h>
  12#include <linux/of_gpio.h>
  13#include <linux/of_graph.h>
  14#include <sound/jack.h>
  15#include <sound/simple_card_utils.h>
  16
  17void asoc_simple_convert_fixup(struct asoc_simple_data *data,
  18                               struct snd_pcm_hw_params *params)
  19{
  20        struct snd_interval *rate = hw_param_interval(params,
  21                                                SNDRV_PCM_HW_PARAM_RATE);
  22        struct snd_interval *channels = hw_param_interval(params,
  23                                                SNDRV_PCM_HW_PARAM_CHANNELS);
  24
  25        if (data->convert_rate)
  26                rate->min =
  27                rate->max = data->convert_rate;
  28
  29        if (data->convert_channels)
  30                channels->min =
  31                channels->max = data->convert_channels;
  32}
  33EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
  34
  35void asoc_simple_parse_convert(struct device_node *np,
  36                               char *prefix,
  37                               struct asoc_simple_data *data)
  38{
  39        char prop[128];
  40
  41        if (!prefix)
  42                prefix = "";
  43
  44        /* sampling rate convert */
  45        snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
  46        of_property_read_u32(np, prop, &data->convert_rate);
  47
  48        /* channels transfer */
  49        snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
  50        of_property_read_u32(np, prop, &data->convert_channels);
  51}
  52EXPORT_SYMBOL_GPL(asoc_simple_parse_convert);
  53
  54int asoc_simple_parse_daifmt(struct device *dev,
  55                             struct device_node *node,
  56                             struct device_node *codec,
  57                             char *prefix,
  58                             unsigned int *retfmt)
  59{
  60        struct device_node *bitclkmaster = NULL;
  61        struct device_node *framemaster = NULL;
  62        unsigned int daifmt;
  63
  64        daifmt = snd_soc_of_parse_daifmt(node, prefix,
  65                                         &bitclkmaster, &framemaster);
  66        daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
  67
  68        if (!bitclkmaster && !framemaster) {
  69                /*
  70                 * No dai-link level and master setting was not found from
  71                 * sound node level, revert back to legacy DT parsing and
  72                 * take the settings from codec node.
  73                 */
  74                dev_dbg(dev, "Revert to legacy daifmt parsing\n");
  75
  76                daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) |
  77                        (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
  78        } else {
  79                if (codec == bitclkmaster)
  80                        daifmt |= (codec == framemaster) ?
  81                                SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
  82                else
  83                        daifmt |= (codec == framemaster) ?
  84                                SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
  85        }
  86
  87        of_node_put(bitclkmaster);
  88        of_node_put(framemaster);
  89
  90        *retfmt = daifmt;
  91
  92        return 0;
  93}
  94EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt);
  95
  96int asoc_simple_set_dailink_name(struct device *dev,
  97                                 struct snd_soc_dai_link *dai_link,
  98                                 const char *fmt, ...)
  99{
 100        va_list ap;
 101        char *name = NULL;
 102        int ret = -ENOMEM;
 103
 104        va_start(ap, fmt);
 105        name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
 106        va_end(ap);
 107
 108        if (name) {
 109                ret = 0;
 110
 111                dai_link->name          = name;
 112                dai_link->stream_name   = name;
 113        }
 114
 115        return ret;
 116}
 117EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name);
 118
 119int asoc_simple_parse_card_name(struct snd_soc_card *card,
 120                                char *prefix)
 121{
 122        int ret;
 123
 124        if (!prefix)
 125                prefix = "";
 126
 127        /* Parse the card name from DT */
 128        ret = snd_soc_of_parse_card_name(card, "label");
 129        if (ret < 0 || !card->name) {
 130                char prop[128];
 131
 132                snprintf(prop, sizeof(prop), "%sname", prefix);
 133                ret = snd_soc_of_parse_card_name(card, prop);
 134                if (ret < 0)
 135                        return ret;
 136        }
 137
 138        if (!card->name && card->dai_link)
 139                card->name = card->dai_link->name;
 140
 141        return 0;
 142}
 143EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name);
 144
 145static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
 146{
 147        if (dai)
 148                return clk_prepare_enable(dai->clk);
 149
 150        return 0;
 151}
 152
 153static void asoc_simple_clk_disable(struct asoc_simple_dai *dai)
 154{
 155        if (dai)
 156                clk_disable_unprepare(dai->clk);
 157}
 158
 159int asoc_simple_parse_clk(struct device *dev,
 160                          struct device_node *node,
 161                          struct asoc_simple_dai *simple_dai,
 162                          struct snd_soc_dai_link_component *dlc)
 163{
 164        struct clk *clk;
 165        u32 val;
 166
 167        /*
 168         * Parse dai->sysclk come from "clocks = <&xxx>"
 169         * (if system has common clock)
 170         *  or "system-clock-frequency = <xxx>"
 171         *  or device's module clock.
 172         */
 173        clk = devm_get_clk_from_child(dev, node, NULL);
 174        if (!IS_ERR(clk)) {
 175                simple_dai->sysclk = clk_get_rate(clk);
 176
 177                simple_dai->clk = clk;
 178        } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
 179                simple_dai->sysclk = val;
 180        } else {
 181                clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
 182                if (!IS_ERR(clk))
 183                        simple_dai->sysclk = clk_get_rate(clk);
 184        }
 185
 186        if (of_property_read_bool(node, "system-clock-direction-out"))
 187                simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
 188
 189        return 0;
 190}
 191EXPORT_SYMBOL_GPL(asoc_simple_parse_clk);
 192
 193int asoc_simple_startup(struct snd_pcm_substream *substream)
 194{
 195        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 196        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 197        struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 198        struct asoc_simple_dai *dai;
 199        int i1, i2, i;
 200        int ret;
 201
 202        for_each_prop_dai_cpu(props, i1, dai) {
 203                ret = asoc_simple_clk_enable(dai);
 204                if (ret)
 205                        goto cpu_err;
 206        }
 207
 208        for_each_prop_dai_codec(props, i2, dai) {
 209                ret = asoc_simple_clk_enable(dai);
 210                if (ret)
 211                        goto codec_err;
 212        }
 213
 214        return 0;
 215
 216codec_err:
 217        for_each_prop_dai_codec(props, i, dai) {
 218                if (i >= i2)
 219                        break;
 220                asoc_simple_clk_disable(dai);
 221        }
 222cpu_err:
 223        for_each_prop_dai_cpu(props, i, dai) {
 224                if (i >= i1)
 225                        break;
 226                asoc_simple_clk_disable(dai);
 227        }
 228        return ret;
 229}
 230EXPORT_SYMBOL_GPL(asoc_simple_startup);
 231
 232void asoc_simple_shutdown(struct snd_pcm_substream *substream)
 233{
 234        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 235        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 236        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 237        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 238        struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 239        struct asoc_simple_dai *dai;
 240        int i;
 241
 242        if (props->mclk_fs) {
 243                snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN);
 244                snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT);
 245        }
 246
 247        for_each_prop_dai_cpu(props, i, dai)
 248                asoc_simple_clk_disable(dai);
 249        for_each_prop_dai_codec(props, i, dai)
 250                asoc_simple_clk_disable(dai);
 251}
 252EXPORT_SYMBOL_GPL(asoc_simple_shutdown);
 253
 254static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
 255                                    unsigned long rate)
 256{
 257        if (!simple_dai)
 258                return 0;
 259
 260        if (!simple_dai->clk)
 261                return 0;
 262
 263        if (clk_get_rate(simple_dai->clk) == rate)
 264                return 0;
 265
 266        return clk_set_rate(simple_dai->clk, rate);
 267}
 268
 269int asoc_simple_hw_params(struct snd_pcm_substream *substream,
 270                          struct snd_pcm_hw_params *params)
 271{
 272        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 273        struct asoc_simple_dai *pdai;
 274        struct snd_soc_dai *sdai;
 275        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 276        struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 277        unsigned int mclk, mclk_fs = 0;
 278        int i, ret;
 279
 280        if (props->mclk_fs)
 281                mclk_fs = props->mclk_fs;
 282
 283        if (mclk_fs) {
 284                mclk = params_rate(params) * mclk_fs;
 285
 286                for_each_prop_dai_codec(props, i, pdai) {
 287                        ret = asoc_simple_set_clk_rate(pdai, mclk);
 288                        if (ret < 0)
 289                                return ret;
 290                }
 291                for_each_prop_dai_cpu(props, i, pdai) {
 292                        ret = asoc_simple_set_clk_rate(pdai, mclk);
 293                        if (ret < 0)
 294                                return ret;
 295                }
 296                for_each_rtd_codec_dais(rtd, i, sdai) {
 297                        ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN);
 298                        if (ret && ret != -ENOTSUPP)
 299                                return ret;
 300                }
 301                for_each_rtd_cpu_dais(rtd, i, sdai) {
 302                        ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT);
 303                        if (ret && ret != -ENOTSUPP)
 304                                return ret;
 305                }
 306        }
 307        return 0;
 308}
 309EXPORT_SYMBOL_GPL(asoc_simple_hw_params);
 310
 311int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 312                                   struct snd_pcm_hw_params *params)
 313{
 314        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 315        struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
 316
 317        asoc_simple_convert_fixup(&dai_props->adata, params);
 318
 319        return 0;
 320}
 321EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup);
 322
 323static int asoc_simple_init_dai(struct snd_soc_dai *dai,
 324                                     struct asoc_simple_dai *simple_dai)
 325{
 326        int ret;
 327
 328        if (!simple_dai)
 329                return 0;
 330
 331        if (simple_dai->sysclk) {
 332                ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
 333                                             simple_dai->clk_direction);
 334                if (ret && ret != -ENOTSUPP) {
 335                        dev_err(dai->dev, "simple-card: set_sysclk error\n");
 336                        return ret;
 337                }
 338        }
 339
 340        if (simple_dai->slots) {
 341                ret = snd_soc_dai_set_tdm_slot(dai,
 342                                               simple_dai->tx_slot_mask,
 343                                               simple_dai->rx_slot_mask,
 344                                               simple_dai->slots,
 345                                               simple_dai->slot_width);
 346                if (ret && ret != -ENOTSUPP) {
 347                        dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
 348                        return ret;
 349                }
 350        }
 351
 352        return 0;
 353}
 354
 355static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd,
 356                                            struct simple_dai_props *dai_props)
 357{
 358        struct snd_soc_dai_link *dai_link = rtd->dai_link;
 359        struct snd_soc_component *component;
 360        struct snd_soc_pcm_stream *params;
 361        struct snd_pcm_hardware hw;
 362        int i, ret, stream;
 363
 364        /* Only codecs should have non_legacy_dai_naming set. */
 365        for_each_rtd_components(rtd, i, component) {
 366                if (!component->driver->non_legacy_dai_naming)
 367                        return 0;
 368        }
 369
 370        /* Assumes the capabilities are the same for all supported streams */
 371        for_each_pcm_streams(stream) {
 372                ret = snd_soc_runtime_calc_hw(rtd, &hw, stream);
 373                if (ret == 0)
 374                        break;
 375        }
 376
 377        if (ret < 0) {
 378                dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
 379                return ret;
 380        }
 381
 382        params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL);
 383        if (!params)
 384                return -ENOMEM;
 385
 386        params->formats = hw.formats;
 387        params->rates = hw.rates;
 388        params->rate_min = hw.rate_min;
 389        params->rate_max = hw.rate_max;
 390        params->channels_min = hw.channels_min;
 391        params->channels_max = hw.channels_max;
 392
 393        dai_link->params = params;
 394        dai_link->num_params = 1;
 395
 396        return 0;
 397}
 398
 399int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
 400{
 401        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 402        struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 403        struct asoc_simple_dai *dai;
 404        int i, ret;
 405
 406        for_each_prop_dai_codec(props, i, dai) {
 407                ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai);
 408                if (ret < 0)
 409                        return ret;
 410        }
 411        for_each_prop_dai_cpu(props, i, dai) {
 412                ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai);
 413                if (ret < 0)
 414                        return ret;
 415        }
 416
 417        ret = asoc_simple_init_dai_link_params(rtd, props);
 418        if (ret < 0)
 419                return ret;
 420
 421        return 0;
 422}
 423EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
 424
 425void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
 426                                       struct snd_soc_dai_link_component *cpus)
 427{
 428        /* Assumes platform == cpu */
 429        if (!platforms->of_node)
 430                platforms->of_node = cpus->of_node;
 431}
 432EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
 433
 434void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
 435                                  int is_single_links)
 436{
 437        /*
 438         * In soc_bind_dai_link() will check cpu name after
 439         * of_node matching if dai_link has cpu_dai_name.
 440         * but, it will never match if name was created by
 441         * fmt_single_name() remove cpu_dai_name if cpu_args
 442         * was 0. See:
 443         *      fmt_single_name()
 444         *      fmt_multiple_name()
 445         */
 446        if (is_single_links)
 447                cpus->dai_name = NULL;
 448}
 449EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
 450
 451int asoc_simple_clean_reference(struct snd_soc_card *card)
 452{
 453        struct snd_soc_dai_link *dai_link;
 454        struct snd_soc_dai_link_component *cpu;
 455        struct snd_soc_dai_link_component *codec;
 456        int i, j;
 457
 458        for_each_card_prelinks(card, i, dai_link) {
 459                for_each_link_cpus(dai_link, j, cpu)
 460                        of_node_put(cpu->of_node);
 461                for_each_link_codecs(dai_link, j, codec)
 462                        of_node_put(codec->of_node);
 463        }
 464        return 0;
 465}
 466EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
 467
 468int asoc_simple_parse_routing(struct snd_soc_card *card,
 469                              char *prefix)
 470{
 471        struct device_node *node = card->dev->of_node;
 472        char prop[128];
 473
 474        if (!prefix)
 475                prefix = "";
 476
 477        snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
 478
 479        if (!of_property_read_bool(node, prop))
 480                return 0;
 481
 482        return snd_soc_of_parse_audio_routing(card, prop);
 483}
 484EXPORT_SYMBOL_GPL(asoc_simple_parse_routing);
 485
 486int asoc_simple_parse_widgets(struct snd_soc_card *card,
 487                              char *prefix)
 488{
 489        struct device_node *node = card->dev->of_node;
 490        char prop[128];
 491
 492        if (!prefix)
 493                prefix = "";
 494
 495        snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
 496
 497        if (of_property_read_bool(node, prop))
 498                return snd_soc_of_parse_audio_simple_widgets(card, prop);
 499
 500        /* no widgets is not error */
 501        return 0;
 502}
 503EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets);
 504
 505int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
 506                                   char *prefix)
 507{
 508        const unsigned int nb_controls_max = 16;
 509        const char **strings, *control_name;
 510        struct snd_kcontrol_new *controls;
 511        struct device *dev = card->dev;
 512        unsigned int i, nb_controls;
 513        char prop[128];
 514        int ret;
 515
 516        if (!prefix)
 517                prefix = "";
 518
 519        snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
 520
 521        if (!of_property_read_bool(dev->of_node, prop))
 522                return 0;
 523
 524        strings = devm_kcalloc(dev, nb_controls_max,
 525                               sizeof(*strings), GFP_KERNEL);
 526        if (!strings)
 527                return -ENOMEM;
 528
 529        ret = of_property_read_string_array(dev->of_node, prop,
 530                                            strings, nb_controls_max);
 531        if (ret < 0)
 532                return ret;
 533
 534        nb_controls = (unsigned int)ret;
 535
 536        controls = devm_kcalloc(dev, nb_controls,
 537                                sizeof(*controls), GFP_KERNEL);
 538        if (!controls)
 539                return -ENOMEM;
 540
 541        for (i = 0; i < nb_controls; i++) {
 542                control_name = devm_kasprintf(dev, GFP_KERNEL,
 543                                              "%s Switch", strings[i]);
 544                if (!control_name)
 545                        return -ENOMEM;
 546
 547                controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 548                controls[i].name = control_name;
 549                controls[i].info = snd_soc_dapm_info_pin_switch;
 550                controls[i].get = snd_soc_dapm_get_pin_switch;
 551                controls[i].put = snd_soc_dapm_put_pin_switch;
 552                controls[i].private_value = (unsigned long)strings[i];
 553        }
 554
 555        card->controls = controls;
 556        card->num_controls = nb_controls;
 557
 558        return 0;
 559}
 560EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
 561
 562int asoc_simple_init_jack(struct snd_soc_card *card,
 563                          struct asoc_simple_jack *sjack,
 564                          int is_hp, char *prefix,
 565                          char *pin)
 566{
 567        struct device *dev = card->dev;
 568        enum of_gpio_flags flags;
 569        char prop[128];
 570        char *pin_name;
 571        char *gpio_name;
 572        int mask;
 573        int det;
 574
 575        if (!prefix)
 576                prefix = "";
 577
 578        sjack->gpio.gpio = -ENOENT;
 579
 580        if (is_hp) {
 581                snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
 582                pin_name        = pin ? pin : "Headphones";
 583                gpio_name       = "Headphone detection";
 584                mask            = SND_JACK_HEADPHONE;
 585        } else {
 586                snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
 587                pin_name        = pin ? pin : "Mic Jack";
 588                gpio_name       = "Mic detection";
 589                mask            = SND_JACK_MICROPHONE;
 590        }
 591
 592        det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
 593        if (det == -EPROBE_DEFER)
 594                return -EPROBE_DEFER;
 595
 596        if (gpio_is_valid(det)) {
 597                sjack->pin.pin          = pin_name;
 598                sjack->pin.mask         = mask;
 599
 600                sjack->gpio.name        = gpio_name;
 601                sjack->gpio.report      = mask;
 602                sjack->gpio.gpio        = det;
 603                sjack->gpio.invert      = !!(flags & OF_GPIO_ACTIVE_LOW);
 604                sjack->gpio.debounce_time = 150;
 605
 606                snd_soc_card_jack_new(card, pin_name, mask,
 607                                      &sjack->jack,
 608                                      &sjack->pin, 1);
 609
 610                snd_soc_jack_add_gpios(&sjack->jack, 1,
 611                                       &sjack->gpio);
 612        }
 613
 614        return 0;
 615}
 616EXPORT_SYMBOL_GPL(asoc_simple_init_jack);
 617
 618int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 619                          struct link_info *li)
 620{
 621        struct snd_soc_card *card = simple_priv_to_card(priv);
 622        struct device *dev = simple_priv_to_dev(priv);
 623        struct snd_soc_dai_link *dai_link;
 624        struct simple_dai_props *dai_props;
 625        struct asoc_simple_dai *dais;
 626        struct snd_soc_dai_link_component *dlcs;
 627        struct snd_soc_codec_conf *cconf = NULL;
 628        int i, dai_num = 0, dlc_num = 0, cnf_num = 0;
 629
 630        dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
 631        dai_link  = devm_kcalloc(dev, li->link, sizeof(*dai_link),  GFP_KERNEL);
 632        if (!dai_props || !dai_link)
 633                return -ENOMEM;
 634
 635        /*
 636         * dais (= CPU+Codec)
 637         * dlcs (= CPU+Codec+Platform)
 638         */
 639        for (i = 0; i < li->link; i++) {
 640                int cc = li->num[i].cpus + li->num[i].codecs;
 641
 642                dai_num += cc;
 643                dlc_num += cc + li->num[i].platforms;
 644
 645                if (!li->num[i].cpus)
 646                        cnf_num += li->num[i].codecs;
 647        }
 648
 649        dais = devm_kcalloc(dev, dai_num, sizeof(*dais),      GFP_KERNEL);
 650        dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dai_props), GFP_KERNEL);
 651        if (!dais || !dlcs)
 652                return -ENOMEM;
 653
 654        if (cnf_num) {
 655                cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL);
 656                if (!cconf)
 657                        return -ENOMEM;
 658        }
 659
 660        dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
 661                li->link, dai_num, cnf_num);
 662
 663        /* dummy CPU/Codec */
 664        priv->dummy.of_node     = NULL;
 665        priv->dummy.dai_name    = "snd-soc-dummy-dai";
 666        priv->dummy.name        = "snd-soc-dummy";
 667
 668        priv->dai_props         = dai_props;
 669        priv->dai_link          = dai_link;
 670        priv->dais              = dais;
 671        priv->dlcs              = dlcs;
 672        priv->codec_conf        = cconf;
 673
 674        card->dai_link          = priv->dai_link;
 675        card->num_links         = li->link;
 676        card->codec_conf        = cconf;
 677        card->num_configs       = cnf_num;
 678
 679        for (i = 0; i < li->link; i++) {
 680                if (li->num[i].cpus) {
 681                        /* Normal CPU */
 682                        dai_props[i].cpus       =
 683                        dai_link[i].cpus        = dlcs;
 684                        dai_props[i].num.cpus   =
 685                        dai_link[i].num_cpus    = li->num[i].cpus;
 686                        dai_props[i].cpu_dai    = dais;
 687
 688                        dlcs += li->num[i].cpus;
 689                        dais += li->num[i].cpus;
 690                } else {
 691                        /* DPCM Be's CPU = dummy */
 692                        dai_props[i].cpus       =
 693                        dai_link[i].cpus        = &priv->dummy;
 694                        dai_props[i].num.cpus   =
 695                        dai_link[i].num_cpus    = 1;
 696                }
 697
 698                if (li->num[i].codecs) {
 699                        /* Normal Codec */
 700                        dai_props[i].codecs     =
 701                        dai_link[i].codecs      = dlcs;
 702                        dai_props[i].num.codecs =
 703                        dai_link[i].num_codecs  = li->num[i].codecs;
 704                        dai_props[i].codec_dai  = dais;
 705
 706                        dlcs += li->num[i].codecs;
 707                        dais += li->num[i].codecs;
 708
 709                        if (!li->num[i].cpus) {
 710                                /* DPCM Be's Codec */
 711                                dai_props[i].codec_conf = cconf;
 712                                cconf += li->num[i].codecs;
 713                        }
 714                } else {
 715                        /* DPCM Fe's Codec = dummy */
 716                        dai_props[i].codecs     =
 717                        dai_link[i].codecs      = &priv->dummy;
 718                        dai_props[i].num.codecs =
 719                        dai_link[i].num_codecs  = 1;
 720                }
 721
 722                if (li->num[i].platforms) {
 723                        /* Have Platform */
 724                        dai_props[i].platforms          =
 725                        dai_link[i].platforms           = dlcs;
 726                        dai_props[i].num.platforms      =
 727                        dai_link[i].num_platforms       = li->num[i].platforms;
 728
 729                        dlcs += li->num[i].platforms;
 730                } else {
 731                        /* Doesn't have Platform */
 732                        dai_props[i].platforms          =
 733                        dai_link[i].platforms           = NULL;
 734                        dai_props[i].num.platforms      =
 735                        dai_link[i].num_platforms       = 0;
 736                }
 737        }
 738
 739        return 0;
 740}
 741EXPORT_SYMBOL_GPL(asoc_simple_init_priv);
 742
 743int asoc_simple_remove(struct platform_device *pdev)
 744{
 745        struct snd_soc_card *card = platform_get_drvdata(pdev);
 746
 747        return asoc_simple_clean_reference(card);
 748}
 749EXPORT_SYMBOL_GPL(asoc_simple_remove);
 750
 751int asoc_graph_card_probe(struct snd_soc_card *card)
 752{
 753        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
 754        int ret;
 755
 756        ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
 757        if (ret < 0)
 758                return ret;
 759
 760        ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
 761        if (ret < 0)
 762                return ret;
 763
 764        return 0;
 765}
 766EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
 767
 768/* Module information */
 769MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 770MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
 771MODULE_LICENSE("GPL v2");
 772