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/pcm_params.h>
  16#include <sound/simple_card_utils.h>
  17
  18void asoc_simple_convert_fixup(struct asoc_simple_data *data,
  19                               struct snd_pcm_hw_params *params)
  20{
  21        struct snd_interval *rate = hw_param_interval(params,
  22                                                SNDRV_PCM_HW_PARAM_RATE);
  23        struct snd_interval *channels = hw_param_interval(params,
  24                                                SNDRV_PCM_HW_PARAM_CHANNELS);
  25
  26        if (data->convert_rate)
  27                rate->min =
  28                rate->max = data->convert_rate;
  29
  30        if (data->convert_channels)
  31                channels->min =
  32                channels->max = data->convert_channels;
  33}
  34EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
  35
  36void asoc_simple_parse_convert(struct device_node *np,
  37                               char *prefix,
  38                               struct asoc_simple_data *data)
  39{
  40        char prop[128];
  41
  42        if (!prefix)
  43                prefix = "";
  44
  45        /* sampling rate convert */
  46        snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
  47        of_property_read_u32(np, prop, &data->convert_rate);
  48
  49        /* channels transfer */
  50        snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
  51        of_property_read_u32(np, prop, &data->convert_channels);
  52}
  53EXPORT_SYMBOL_GPL(asoc_simple_parse_convert);
  54
  55int asoc_simple_parse_daifmt(struct device *dev,
  56                             struct device_node *node,
  57                             struct device_node *codec,
  58                             char *prefix,
  59                             unsigned int *retfmt)
  60{
  61        struct device_node *bitclkmaster = NULL;
  62        struct device_node *framemaster = NULL;
  63        unsigned int daifmt;
  64
  65        daifmt = snd_soc_daifmt_parse_format(node, prefix);
  66
  67        snd_soc_daifmt_parse_clock_provider_as_phandle(node, prefix, &bitclkmaster, &framemaster);
  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_daifmt_parse_clock_provider_as_flag(codec, NULL);
  77        } else {
  78                daifmt |= snd_soc_daifmt_clock_provider_from_bitmap(
  79                                ((codec == bitclkmaster) << 4) | (codec == framemaster));
  80        }
  81
  82        of_node_put(bitclkmaster);
  83        of_node_put(framemaster);
  84
  85        *retfmt = daifmt;
  86
  87        return 0;
  88}
  89EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt);
  90
  91int asoc_simple_parse_tdm_width_map(struct device *dev, struct device_node *np,
  92                                    struct asoc_simple_dai *dai)
  93{
  94        u32 *array_values, *p;
  95        int n, i, ret;
  96
  97        if (!of_property_read_bool(np, "dai-tdm-slot-width-map"))
  98                return 0;
  99
 100        n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32));
 101        if (n % 3) {
 102                dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n");
 103                return -EINVAL;
 104        }
 105
 106        dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL);
 107        if (!dai->tdm_width_map)
 108                return -ENOMEM;
 109
 110        array_values = kcalloc(n, sizeof(*array_values), GFP_KERNEL);
 111        if (!array_values)
 112                return -ENOMEM;
 113
 114        ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n);
 115        if (ret < 0) {
 116                dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret);
 117                goto out;
 118        }
 119
 120        p = array_values;
 121        for (i = 0; i < n / 3; ++i) {
 122                dai->tdm_width_map[i].sample_bits = *p++;
 123                dai->tdm_width_map[i].slot_width = *p++;
 124                dai->tdm_width_map[i].slot_count = *p++;
 125        }
 126
 127        dai->n_tdm_widths = i;
 128        ret = 0;
 129out:
 130        kfree(array_values);
 131
 132        return ret;
 133}
 134EXPORT_SYMBOL_GPL(asoc_simple_parse_tdm_width_map);
 135
 136int asoc_simple_set_dailink_name(struct device *dev,
 137                                 struct snd_soc_dai_link *dai_link,
 138                                 const char *fmt, ...)
 139{
 140        va_list ap;
 141        char *name = NULL;
 142        int ret = -ENOMEM;
 143
 144        va_start(ap, fmt);
 145        name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
 146        va_end(ap);
 147
 148        if (name) {
 149                ret = 0;
 150
 151                dai_link->name          = name;
 152                dai_link->stream_name   = name;
 153        }
 154
 155        return ret;
 156}
 157EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name);
 158
 159int asoc_simple_parse_card_name(struct snd_soc_card *card,
 160                                char *prefix)
 161{
 162        int ret;
 163
 164        if (!prefix)
 165                prefix = "";
 166
 167        /* Parse the card name from DT */
 168        ret = snd_soc_of_parse_card_name(card, "label");
 169        if (ret < 0 || !card->name) {
 170                char prop[128];
 171
 172                snprintf(prop, sizeof(prop), "%sname", prefix);
 173                ret = snd_soc_of_parse_card_name(card, prop);
 174                if (ret < 0)
 175                        return ret;
 176        }
 177
 178        if (!card->name && card->dai_link)
 179                card->name = card->dai_link->name;
 180
 181        return 0;
 182}
 183EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name);
 184
 185static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
 186{
 187        if (dai)
 188                return clk_prepare_enable(dai->clk);
 189
 190        return 0;
 191}
 192
 193static void asoc_simple_clk_disable(struct asoc_simple_dai *dai)
 194{
 195        if (dai)
 196                clk_disable_unprepare(dai->clk);
 197}
 198
 199int asoc_simple_parse_clk(struct device *dev,
 200                          struct device_node *node,
 201                          struct asoc_simple_dai *simple_dai,
 202                          struct snd_soc_dai_link_component *dlc)
 203{
 204        struct clk *clk;
 205        u32 val;
 206
 207        /*
 208         * Parse dai->sysclk come from "clocks = <&xxx>"
 209         * (if system has common clock)
 210         *  or "system-clock-frequency = <xxx>"
 211         *  or device's module clock.
 212         */
 213        clk = devm_get_clk_from_child(dev, node, NULL);
 214        simple_dai->clk_fixed = of_property_read_bool(
 215                node, "system-clock-fixed");
 216        if (!IS_ERR(clk)) {
 217                simple_dai->sysclk = clk_get_rate(clk);
 218
 219                simple_dai->clk = clk;
 220        } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
 221                simple_dai->sysclk = val;
 222                simple_dai->clk_fixed = true;
 223        } else {
 224                clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
 225                if (!IS_ERR(clk))
 226                        simple_dai->sysclk = clk_get_rate(clk);
 227        }
 228
 229        if (of_property_read_bool(node, "system-clock-direction-out"))
 230                simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
 231
 232        return 0;
 233}
 234EXPORT_SYMBOL_GPL(asoc_simple_parse_clk);
 235
 236static int asoc_simple_check_fixed_sysclk(struct device *dev,
 237                                          struct asoc_simple_dai *dai,
 238                                          unsigned int *fixed_sysclk)
 239{
 240        if (dai->clk_fixed) {
 241                if (*fixed_sysclk && *fixed_sysclk != dai->sysclk) {
 242                        dev_err(dev, "inconsistent fixed sysclk rates (%u vs %u)\n",
 243                                *fixed_sysclk, dai->sysclk);
 244                        return -EINVAL;
 245                }
 246                *fixed_sysclk = dai->sysclk;
 247        }
 248
 249        return 0;
 250}
 251
 252int asoc_simple_startup(struct snd_pcm_substream *substream)
 253{
 254        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 255        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 256        struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 257        struct asoc_simple_dai *dai;
 258        unsigned int fixed_sysclk = 0;
 259        int i1, i2, i;
 260        int ret;
 261
 262        for_each_prop_dai_cpu(props, i1, dai) {
 263                ret = asoc_simple_clk_enable(dai);
 264                if (ret)
 265                        goto cpu_err;
 266                ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
 267                if (ret)
 268                        goto cpu_err;
 269        }
 270
 271        for_each_prop_dai_codec(props, i2, dai) {
 272                ret = asoc_simple_clk_enable(dai);
 273                if (ret)
 274                        goto codec_err;
 275                ret = asoc_simple_check_fixed_sysclk(rtd->dev, dai, &fixed_sysclk);
 276                if (ret)
 277                        goto codec_err;
 278        }
 279
 280        if (fixed_sysclk && props->mclk_fs) {
 281                unsigned int fixed_rate = fixed_sysclk / props->mclk_fs;
 282
 283                if (fixed_sysclk % props->mclk_fs) {
 284                        dev_err(rtd->dev, "fixed sysclk %u not divisible by mclk_fs %u\n",
 285                                fixed_sysclk, props->mclk_fs);
 286                        return -EINVAL;
 287                }
 288                ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE,
 289                        fixed_rate, fixed_rate);
 290                if (ret)
 291                        goto codec_err;
 292        }
 293
 294        return 0;
 295
 296codec_err:
 297        for_each_prop_dai_codec(props, i, dai) {
 298                if (i >= i2)
 299                        break;
 300                asoc_simple_clk_disable(dai);
 301        }
 302cpu_err:
 303        for_each_prop_dai_cpu(props, i, dai) {
 304                if (i >= i1)
 305                        break;
 306                asoc_simple_clk_disable(dai);
 307        }
 308        return ret;
 309}
 310EXPORT_SYMBOL_GPL(asoc_simple_startup);
 311
 312void asoc_simple_shutdown(struct snd_pcm_substream *substream)
 313{
 314        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 315        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 316        struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 317        struct asoc_simple_dai *dai;
 318        int i;
 319
 320        for_each_prop_dai_cpu(props, i, dai) {
 321                struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, i);
 322
 323                if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(cpu_dai))
 324                        snd_soc_dai_set_sysclk(cpu_dai,
 325                                               0, 0, SND_SOC_CLOCK_OUT);
 326
 327                asoc_simple_clk_disable(dai);
 328        }
 329        for_each_prop_dai_codec(props, i, dai) {
 330                struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, i);
 331
 332                if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(codec_dai))
 333                        snd_soc_dai_set_sysclk(codec_dai,
 334                                               0, 0, SND_SOC_CLOCK_IN);
 335
 336                asoc_simple_clk_disable(dai);
 337        }
 338}
 339EXPORT_SYMBOL_GPL(asoc_simple_shutdown);
 340
 341static int asoc_simple_set_clk_rate(struct device *dev,
 342                                    struct asoc_simple_dai *simple_dai,
 343                                    unsigned long rate)
 344{
 345        if (!simple_dai)
 346                return 0;
 347
 348        if (simple_dai->clk_fixed && rate != simple_dai->sysclk) {
 349                dev_err(dev, "dai %s invalid clock rate %lu\n", simple_dai->name, rate);
 350                return -EINVAL;
 351        }
 352
 353        if (!simple_dai->clk)
 354                return 0;
 355
 356        if (clk_get_rate(simple_dai->clk) == rate)
 357                return 0;
 358
 359        return clk_set_rate(simple_dai->clk, rate);
 360}
 361
 362static int asoc_simple_set_tdm(struct snd_soc_dai *dai,
 363                                struct asoc_simple_dai *simple_dai,
 364                                struct snd_pcm_hw_params *params)
 365{
 366        int sample_bits = params_width(params);
 367        int slot_width, slot_count;
 368        int i, ret;
 369
 370        if (!simple_dai || !simple_dai->tdm_width_map)
 371                return 0;
 372
 373        slot_width = simple_dai->slot_width;
 374        slot_count = simple_dai->slots;
 375
 376        if (slot_width == 0)
 377                slot_width = sample_bits;
 378
 379        for (i = 0; i < simple_dai->n_tdm_widths; ++i) {
 380                if (simple_dai->tdm_width_map[i].sample_bits == sample_bits) {
 381                        slot_width = simple_dai->tdm_width_map[i].slot_width;
 382                        slot_count = simple_dai->tdm_width_map[i].slot_count;
 383                        break;
 384                }
 385        }
 386
 387        ret = snd_soc_dai_set_tdm_slot(dai,
 388                                       simple_dai->tx_slot_mask,
 389                                       simple_dai->rx_slot_mask,
 390                                       slot_count,
 391                                       slot_width);
 392        if (ret && ret != -ENOTSUPP) {
 393                dev_err(dai->dev, "simple-card: set_tdm_slot error: %d\n", ret);
 394                return ret;
 395        }
 396
 397        return 0;
 398}
 399
 400int asoc_simple_hw_params(struct snd_pcm_substream *substream,
 401                          struct snd_pcm_hw_params *params)
 402{
 403        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 404        struct asoc_simple_dai *pdai;
 405        struct snd_soc_dai *sdai;
 406        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 407        struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 408        unsigned int mclk, mclk_fs = 0;
 409        int i, ret;
 410
 411        if (props->mclk_fs)
 412                mclk_fs = props->mclk_fs;
 413
 414        if (mclk_fs) {
 415                struct snd_soc_component *component;
 416                mclk = params_rate(params) * mclk_fs;
 417
 418                for_each_prop_dai_codec(props, i, pdai) {
 419                        ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk);
 420                        if (ret < 0)
 421                                return ret;
 422                }
 423
 424                for_each_prop_dai_cpu(props, i, pdai) {
 425                        ret = asoc_simple_set_clk_rate(rtd->dev, pdai, mclk);
 426                        if (ret < 0)
 427                                return ret;
 428                }
 429
 430                /* Ensure sysclk is set on all components in case any
 431                 * (such as platform components) are missed by calls to
 432                 * snd_soc_dai_set_sysclk.
 433                 */
 434                for_each_rtd_components(rtd, i, component) {
 435                        ret = snd_soc_component_set_sysclk(component, 0, 0,
 436                                                           mclk, SND_SOC_CLOCK_IN);
 437                        if (ret && ret != -ENOTSUPP)
 438                                return ret;
 439                }
 440
 441                for_each_rtd_codec_dais(rtd, i, sdai) {
 442                        ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN);
 443                        if (ret && ret != -ENOTSUPP)
 444                                return ret;
 445                }
 446
 447                for_each_rtd_cpu_dais(rtd, i, sdai) {
 448                        ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT);
 449                        if (ret && ret != -ENOTSUPP)
 450                                return ret;
 451                }
 452        }
 453
 454        for_each_prop_dai_codec(props, i, pdai) {
 455                sdai = asoc_rtd_to_codec(rtd, i);
 456                ret = asoc_simple_set_tdm(sdai, pdai, params);
 457                if (ret < 0)
 458                        return ret;
 459        }
 460
 461        for_each_prop_dai_cpu(props, i, pdai) {
 462                sdai = asoc_rtd_to_cpu(rtd, i);
 463                ret = asoc_simple_set_tdm(sdai, pdai, params);
 464                if (ret < 0)
 465                        return ret;
 466        }
 467
 468        return 0;
 469}
 470EXPORT_SYMBOL_GPL(asoc_simple_hw_params);
 471
 472int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 473                                   struct snd_pcm_hw_params *params)
 474{
 475        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 476        struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
 477
 478        asoc_simple_convert_fixup(&dai_props->adata, params);
 479
 480        return 0;
 481}
 482EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup);
 483
 484static int asoc_simple_init_dai(struct snd_soc_dai *dai,
 485                                     struct asoc_simple_dai *simple_dai)
 486{
 487        int ret;
 488
 489        if (!simple_dai)
 490                return 0;
 491
 492        if (simple_dai->sysclk) {
 493                ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
 494                                             simple_dai->clk_direction);
 495                if (ret && ret != -ENOTSUPP) {
 496                        dev_err(dai->dev, "simple-card: set_sysclk error\n");
 497                        return ret;
 498                }
 499        }
 500
 501        if (simple_dai->slots) {
 502                ret = snd_soc_dai_set_tdm_slot(dai,
 503                                               simple_dai->tx_slot_mask,
 504                                               simple_dai->rx_slot_mask,
 505                                               simple_dai->slots,
 506                                               simple_dai->slot_width);
 507                if (ret && ret != -ENOTSUPP) {
 508                        dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
 509                        return ret;
 510                }
 511        }
 512
 513        return 0;
 514}
 515
 516static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd,
 517                                            struct simple_dai_props *dai_props)
 518{
 519        struct snd_soc_dai_link *dai_link = rtd->dai_link;
 520        struct snd_soc_component *component;
 521        struct snd_soc_pcm_stream *params;
 522        struct snd_pcm_hardware hw;
 523        int i, ret, stream;
 524
 525        /* Only Codecs */
 526        for_each_rtd_components(rtd, i, component) {
 527                if (!snd_soc_component_is_codec(component))
 528                        return 0;
 529        }
 530
 531        /* Assumes the capabilities are the same for all supported streams */
 532        for_each_pcm_streams(stream) {
 533                ret = snd_soc_runtime_calc_hw(rtd, &hw, stream);
 534                if (ret == 0)
 535                        break;
 536        }
 537
 538        if (ret < 0) {
 539                dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
 540                return ret;
 541        }
 542
 543        params = devm_kzalloc(rtd->dev, sizeof(*params), GFP_KERNEL);
 544        if (!params)
 545                return -ENOMEM;
 546
 547        params->formats = hw.formats;
 548        params->rates = hw.rates;
 549        params->rate_min = hw.rate_min;
 550        params->rate_max = hw.rate_max;
 551        params->channels_min = hw.channels_min;
 552        params->channels_max = hw.channels_max;
 553
 554        dai_link->params = params;
 555        dai_link->num_params = 1;
 556
 557        return 0;
 558}
 559
 560int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
 561{
 562        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 563        struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 564        struct asoc_simple_dai *dai;
 565        int i, ret;
 566
 567        for_each_prop_dai_codec(props, i, dai) {
 568                ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai);
 569                if (ret < 0)
 570                        return ret;
 571        }
 572        for_each_prop_dai_cpu(props, i, dai) {
 573                ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai);
 574                if (ret < 0)
 575                        return ret;
 576        }
 577
 578        ret = asoc_simple_init_dai_link_params(rtd, props);
 579        if (ret < 0)
 580                return ret;
 581
 582        return 0;
 583}
 584EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
 585
 586void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms,
 587                                       struct snd_soc_dai_link_component *cpus)
 588{
 589        /* Assumes platform == cpu */
 590        if (!platforms->of_node)
 591                platforms->of_node = cpus->of_node;
 592}
 593EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
 594
 595void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
 596                                  int is_single_links)
 597{
 598        /*
 599         * In soc_bind_dai_link() will check cpu name after
 600         * of_node matching if dai_link has cpu_dai_name.
 601         * but, it will never match if name was created by
 602         * fmt_single_name() remove cpu_dai_name if cpu_args
 603         * was 0. See:
 604         *      fmt_single_name()
 605         *      fmt_multiple_name()
 606         */
 607        if (is_single_links)
 608                cpus->dai_name = NULL;
 609}
 610EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
 611
 612int asoc_simple_clean_reference(struct snd_soc_card *card)
 613{
 614        struct snd_soc_dai_link *dai_link;
 615        struct snd_soc_dai_link_component *cpu;
 616        struct snd_soc_dai_link_component *codec;
 617        int i, j;
 618
 619        for_each_card_prelinks(card, i, dai_link) {
 620                for_each_link_cpus(dai_link, j, cpu)
 621                        of_node_put(cpu->of_node);
 622                for_each_link_codecs(dai_link, j, codec)
 623                        of_node_put(codec->of_node);
 624        }
 625        return 0;
 626}
 627EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
 628
 629int asoc_simple_parse_routing(struct snd_soc_card *card,
 630                              char *prefix)
 631{
 632        struct device_node *node = card->dev->of_node;
 633        char prop[128];
 634
 635        if (!prefix)
 636                prefix = "";
 637
 638        snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
 639
 640        if (!of_property_read_bool(node, prop))
 641                return 0;
 642
 643        return snd_soc_of_parse_audio_routing(card, prop);
 644}
 645EXPORT_SYMBOL_GPL(asoc_simple_parse_routing);
 646
 647int asoc_simple_parse_widgets(struct snd_soc_card *card,
 648                              char *prefix)
 649{
 650        struct device_node *node = card->dev->of_node;
 651        char prop[128];
 652
 653        if (!prefix)
 654                prefix = "";
 655
 656        snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
 657
 658        if (of_property_read_bool(node, prop))
 659                return snd_soc_of_parse_audio_simple_widgets(card, prop);
 660
 661        /* no widgets is not error */
 662        return 0;
 663}
 664EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets);
 665
 666int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
 667                                   char *prefix)
 668{
 669        char prop[128];
 670
 671        if (!prefix)
 672                prefix = "";
 673
 674        snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
 675
 676        return snd_soc_of_parse_pin_switches(card, prop);
 677}
 678EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
 679
 680int asoc_simple_init_jack(struct snd_soc_card *card,
 681                          struct asoc_simple_jack *sjack,
 682                          int is_hp, char *prefix,
 683                          char *pin)
 684{
 685        struct device *dev = card->dev;
 686        enum of_gpio_flags flags;
 687        char prop[128];
 688        char *pin_name;
 689        char *gpio_name;
 690        int mask;
 691        int det;
 692
 693        if (!prefix)
 694                prefix = "";
 695
 696        sjack->gpio.gpio = -ENOENT;
 697
 698        if (is_hp) {
 699                snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
 700                pin_name        = pin ? pin : "Headphones";
 701                gpio_name       = "Headphone detection";
 702                mask            = SND_JACK_HEADPHONE;
 703        } else {
 704                snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
 705                pin_name        = pin ? pin : "Mic Jack";
 706                gpio_name       = "Mic detection";
 707                mask            = SND_JACK_MICROPHONE;
 708        }
 709
 710        det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
 711        if (det == -EPROBE_DEFER)
 712                return -EPROBE_DEFER;
 713
 714        if (gpio_is_valid(det)) {
 715                sjack->pin.pin          = pin_name;
 716                sjack->pin.mask         = mask;
 717
 718                sjack->gpio.name        = gpio_name;
 719                sjack->gpio.report      = mask;
 720                sjack->gpio.gpio        = det;
 721                sjack->gpio.invert      = !!(flags & OF_GPIO_ACTIVE_LOW);
 722                sjack->gpio.debounce_time = 150;
 723
 724                snd_soc_card_jack_new(card, pin_name, mask,
 725                                      &sjack->jack,
 726                                      &sjack->pin, 1);
 727
 728                snd_soc_jack_add_gpios(&sjack->jack, 1,
 729                                       &sjack->gpio);
 730        }
 731
 732        return 0;
 733}
 734EXPORT_SYMBOL_GPL(asoc_simple_init_jack);
 735
 736int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 737                          struct link_info *li)
 738{
 739        struct snd_soc_card *card = simple_priv_to_card(priv);
 740        struct device *dev = simple_priv_to_dev(priv);
 741        struct snd_soc_dai_link *dai_link;
 742        struct simple_dai_props *dai_props;
 743        struct asoc_simple_dai *dais;
 744        struct snd_soc_dai_link_component *dlcs;
 745        struct snd_soc_codec_conf *cconf = NULL;
 746        struct snd_soc_pcm_stream *c2c_conf = NULL;
 747        int i, dai_num = 0, dlc_num = 0, cnf_num = 0, c2c_num = 0;
 748
 749        dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
 750        dai_link  = devm_kcalloc(dev, li->link, sizeof(*dai_link),  GFP_KERNEL);
 751        if (!dai_props || !dai_link)
 752                return -ENOMEM;
 753
 754        /*
 755         * dais (= CPU+Codec)
 756         * dlcs (= CPU+Codec+Platform)
 757         */
 758        for (i = 0; i < li->link; i++) {
 759                int cc = li->num[i].cpus + li->num[i].codecs;
 760
 761                dai_num += cc;
 762                dlc_num += cc + li->num[i].platforms;
 763
 764                if (!li->num[i].cpus)
 765                        cnf_num += li->num[i].codecs;
 766
 767                c2c_num += li->num[i].c2c;
 768        }
 769
 770        dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL);
 771        dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dlcs), GFP_KERNEL);
 772        if (!dais || !dlcs)
 773                return -ENOMEM;
 774
 775        if (cnf_num) {
 776                cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL);
 777                if (!cconf)
 778                        return -ENOMEM;
 779        }
 780
 781        if (c2c_num) {
 782                c2c_conf = devm_kcalloc(dev, c2c_num, sizeof(*c2c_conf), GFP_KERNEL);
 783                if (!c2c_conf)
 784                        return -ENOMEM;
 785        }
 786
 787        dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
 788                li->link, dai_num, cnf_num);
 789
 790        /* dummy CPU/Codec */
 791        priv->dummy.of_node     = NULL;
 792        priv->dummy.dai_name    = "snd-soc-dummy-dai";
 793        priv->dummy.name        = "snd-soc-dummy";
 794
 795        priv->dai_props         = dai_props;
 796        priv->dai_link          = dai_link;
 797        priv->dais              = dais;
 798        priv->dlcs              = dlcs;
 799        priv->codec_conf        = cconf;
 800        priv->c2c_conf          = c2c_conf;
 801
 802        card->dai_link          = priv->dai_link;
 803        card->num_links         = li->link;
 804        card->codec_conf        = cconf;
 805        card->num_configs       = cnf_num;
 806
 807        for (i = 0; i < li->link; i++) {
 808                if (li->num[i].cpus) {
 809                        /* Normal CPU */
 810                        dai_props[i].cpus       =
 811                        dai_link[i].cpus        = dlcs;
 812                        dai_props[i].num.cpus   =
 813                        dai_link[i].num_cpus    = li->num[i].cpus;
 814                        dai_props[i].cpu_dai    = dais;
 815
 816                        dlcs += li->num[i].cpus;
 817                        dais += li->num[i].cpus;
 818
 819                        if (li->num[i].c2c) {
 820                                /* Codec2Codec */
 821                                dai_props[i].c2c_conf = c2c_conf;
 822                                c2c_conf += li->num[i].c2c;
 823                        }
 824                } else {
 825                        /* DPCM Be's CPU = dummy */
 826                        dai_props[i].cpus       =
 827                        dai_link[i].cpus        = &priv->dummy;
 828                        dai_props[i].num.cpus   =
 829                        dai_link[i].num_cpus    = 1;
 830                }
 831
 832                if (li->num[i].codecs) {
 833                        /* Normal Codec */
 834                        dai_props[i].codecs     =
 835                        dai_link[i].codecs      = dlcs;
 836                        dai_props[i].num.codecs =
 837                        dai_link[i].num_codecs  = li->num[i].codecs;
 838                        dai_props[i].codec_dai  = dais;
 839
 840                        dlcs += li->num[i].codecs;
 841                        dais += li->num[i].codecs;
 842
 843                        if (!li->num[i].cpus) {
 844                                /* DPCM Be's Codec */
 845                                dai_props[i].codec_conf = cconf;
 846                                cconf += li->num[i].codecs;
 847                        }
 848                } else {
 849                        /* DPCM Fe's Codec = dummy */
 850                        dai_props[i].codecs     =
 851                        dai_link[i].codecs      = &priv->dummy;
 852                        dai_props[i].num.codecs =
 853                        dai_link[i].num_codecs  = 1;
 854                }
 855
 856                if (li->num[i].platforms) {
 857                        /* Have Platform */
 858                        dai_props[i].platforms          =
 859                        dai_link[i].platforms           = dlcs;
 860                        dai_props[i].num.platforms      =
 861                        dai_link[i].num_platforms       = li->num[i].platforms;
 862
 863                        dlcs += li->num[i].platforms;
 864                } else {
 865                        /* Doesn't have Platform */
 866                        dai_props[i].platforms          =
 867                        dai_link[i].platforms           = NULL;
 868                        dai_props[i].num.platforms      =
 869                        dai_link[i].num_platforms       = 0;
 870                }
 871        }
 872
 873        return 0;
 874}
 875EXPORT_SYMBOL_GPL(asoc_simple_init_priv);
 876
 877int asoc_simple_remove(struct platform_device *pdev)
 878{
 879        struct snd_soc_card *card = platform_get_drvdata(pdev);
 880
 881        return asoc_simple_clean_reference(card);
 882}
 883EXPORT_SYMBOL_GPL(asoc_simple_remove);
 884
 885int asoc_graph_card_probe(struct snd_soc_card *card)
 886{
 887        struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
 888        int ret;
 889
 890        ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
 891        if (ret < 0)
 892                return ret;
 893
 894        ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
 895        if (ret < 0)
 896                return ret;
 897
 898        return 0;
 899}
 900EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
 901
 902int asoc_graph_is_ports0(struct device_node *np)
 903{
 904        struct device_node *port, *ports, *ports0, *top;
 905        int ret;
 906
 907        /* np is "endpoint" or "port" */
 908        if (of_node_name_eq(np, "endpoint")) {
 909                port = of_get_parent(np);
 910        } else {
 911                port = np;
 912                of_node_get(port);
 913        }
 914
 915        ports   = of_get_parent(port);
 916        top     = of_get_parent(ports);
 917        ports0  = of_get_child_by_name(top, "ports");
 918
 919        ret = ports0 == ports;
 920
 921        of_node_put(port);
 922        of_node_put(ports);
 923        of_node_put(ports0);
 924        of_node_put(top);
 925
 926        return ret;
 927}
 928EXPORT_SYMBOL_GPL(asoc_graph_is_ports0);
 929
 930/* Module information */
 931MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 932MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
 933MODULE_LICENSE("GPL v2");
 934