linux/sound/soc/generic/simple-card.c
<<
>>
Prefs
   1/*
   2 * ASoC simple sound card support
   3 *
   4 * Copyright (C) 2012 Renesas Solutions Corp.
   5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11#include <linux/clk.h>
  12#include <linux/device.h>
  13#include <linux/gpio.h>
  14#include <linux/module.h>
  15#include <linux/of.h>
  16#include <linux/of_gpio.h>
  17#include <linux/platform_device.h>
  18#include <linux/string.h>
  19#include <sound/jack.h>
  20#include <sound/simple_card.h>
  21#include <sound/soc-dai.h>
  22#include <sound/soc.h>
  23
  24struct asoc_simple_jack {
  25        struct snd_soc_jack jack;
  26        struct snd_soc_jack_pin pin;
  27        struct snd_soc_jack_gpio gpio;
  28};
  29
  30struct simple_card_data {
  31        struct snd_soc_card snd_card;
  32        struct simple_dai_props {
  33                struct asoc_simple_dai cpu_dai;
  34                struct asoc_simple_dai codec_dai;
  35                unsigned int mclk_fs;
  36        } *dai_props;
  37        unsigned int mclk_fs;
  38        struct asoc_simple_jack hp_jack;
  39        struct asoc_simple_jack mic_jack;
  40        struct snd_soc_dai_link dai_link[];     /* dynamically allocated */
  41};
  42
  43#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
  44#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
  45#define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
  46
  47#define PREFIX  "simple-audio-card,"
  48
  49#define asoc_simple_card_init_hp(card, sjack, prefix)\
  50        asoc_simple_card_init_jack(card, sjack, 1, prefix)
  51#define asoc_simple_card_init_mic(card, sjack, prefix)\
  52        asoc_simple_card_init_jack(card, sjack, 0, prefix)
  53static int asoc_simple_card_init_jack(struct snd_soc_card *card,
  54                                      struct asoc_simple_jack *sjack,
  55                                      int is_hp, char *prefix)
  56{
  57        struct device *dev = card->dev;
  58        enum of_gpio_flags flags;
  59        char prop[128];
  60        char *pin_name;
  61        char *gpio_name;
  62        int mask;
  63        int det;
  64
  65        sjack->gpio.gpio = -ENOENT;
  66
  67        if (is_hp) {
  68                snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
  69                pin_name        = "Headphones";
  70                gpio_name       = "Headphone detection";
  71                mask            = SND_JACK_HEADPHONE;
  72        } else {
  73                snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
  74                pin_name        = "Mic Jack";
  75                gpio_name       = "Mic detection";
  76                mask            = SND_JACK_MICROPHONE;
  77        }
  78
  79        det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
  80        if (det == -EPROBE_DEFER)
  81                return -EPROBE_DEFER;
  82
  83        if (gpio_is_valid(det)) {
  84                sjack->pin.pin          = pin_name;
  85                sjack->pin.mask         = mask;
  86
  87                sjack->gpio.name        = gpio_name;
  88                sjack->gpio.report      = mask;
  89                sjack->gpio.gpio        = det;
  90                sjack->gpio.invert      = !!(flags & OF_GPIO_ACTIVE_LOW);
  91                sjack->gpio.debounce_time = 150;
  92
  93                snd_soc_card_jack_new(card, pin_name, mask,
  94                                      &sjack->jack,
  95                                      &sjack->pin, 1);
  96
  97                snd_soc_jack_add_gpios(&sjack->jack, 1,
  98                                       &sjack->gpio);
  99        }
 100
 101        return 0;
 102}
 103
 104static void asoc_simple_card_remove_jack(struct asoc_simple_jack *sjack)
 105{
 106        if (gpio_is_valid(sjack->gpio.gpio))
 107                snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio);
 108}
 109
 110static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
 111{
 112        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 113        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
 114        struct simple_dai_props *dai_props =
 115                &priv->dai_props[rtd->num];
 116        int ret;
 117
 118        ret = clk_prepare_enable(dai_props->cpu_dai.clk);
 119        if (ret)
 120                return ret;
 121        
 122        ret = clk_prepare_enable(dai_props->codec_dai.clk);
 123        if (ret)
 124                clk_disable_unprepare(dai_props->cpu_dai.clk);
 125
 126        return ret;
 127}
 128
 129static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
 130{
 131        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 132        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
 133        struct simple_dai_props *dai_props =
 134                &priv->dai_props[rtd->num];
 135
 136        clk_disable_unprepare(dai_props->cpu_dai.clk);
 137
 138        clk_disable_unprepare(dai_props->codec_dai.clk);
 139}
 140
 141static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
 142                                      struct snd_pcm_hw_params *params)
 143{
 144        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 145        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 146        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 147        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
 148        struct simple_dai_props *dai_props = &priv->dai_props[rtd->num];
 149        unsigned int mclk, mclk_fs = 0;
 150        int ret = 0;
 151
 152        if (priv->mclk_fs)
 153                mclk_fs = priv->mclk_fs;
 154        else if (dai_props->mclk_fs)
 155                mclk_fs = dai_props->mclk_fs;
 156
 157        if (mclk_fs) {
 158                mclk = params_rate(params) * mclk_fs;
 159                ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
 160                                             SND_SOC_CLOCK_IN);
 161                if (ret && ret != -ENOTSUPP)
 162                        goto err;
 163
 164                ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
 165                                             SND_SOC_CLOCK_OUT);
 166                if (ret && ret != -ENOTSUPP)
 167                        goto err;
 168        }
 169        return 0;
 170err:
 171        return ret;
 172}
 173
 174static struct snd_soc_ops asoc_simple_card_ops = {
 175        .startup = asoc_simple_card_startup,
 176        .shutdown = asoc_simple_card_shutdown,
 177        .hw_params = asoc_simple_card_hw_params,
 178};
 179
 180static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
 181                                       struct asoc_simple_dai *set)
 182{
 183        int ret;
 184
 185        if (set->sysclk) {
 186                ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
 187                if (ret && ret != -ENOTSUPP) {
 188                        dev_err(dai->dev, "simple-card: set_sysclk error\n");
 189                        goto err;
 190                }
 191        }
 192
 193        if (set->slots) {
 194                ret = snd_soc_dai_set_tdm_slot(dai,
 195                                               set->tx_slot_mask,
 196                                               set->rx_slot_mask,
 197                                                set->slots,
 198                                                set->slot_width);
 199                if (ret && ret != -ENOTSUPP) {
 200                        dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
 201                        goto err;
 202                }
 203        }
 204
 205        ret = 0;
 206
 207err:
 208        return ret;
 209}
 210
 211static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 212{
 213        struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
 214        struct snd_soc_dai *codec = rtd->codec_dai;
 215        struct snd_soc_dai *cpu = rtd->cpu_dai;
 216        struct simple_dai_props *dai_props;
 217        int ret;
 218
 219        dai_props = &priv->dai_props[rtd->num];
 220        ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
 221        if (ret < 0)
 222                return ret;
 223
 224        ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
 225        if (ret < 0)
 226                return ret;
 227
 228        ret = asoc_simple_card_init_hp(rtd->card, &priv->hp_jack, PREFIX);
 229        if (ret < 0)
 230                return ret;
 231
 232        ret = asoc_simple_card_init_mic(rtd->card, &priv->hp_jack, PREFIX);
 233        if (ret < 0)
 234                return ret;
 235
 236        return 0;
 237}
 238
 239static int
 240asoc_simple_card_sub_parse_of(struct device_node *np,
 241                              struct asoc_simple_dai *dai,
 242                              struct device_node **p_node,
 243                              const char **name,
 244                              int *args_count)
 245{
 246        struct of_phandle_args args;
 247        struct clk *clk;
 248        u32 val;
 249        int ret;
 250
 251        if (!np)
 252                return 0;
 253
 254        /*
 255         * Get node via "sound-dai = <&phandle port>"
 256         * it will be used as xxx_of_node on soc_bind_dai_link()
 257         */
 258        ret = of_parse_phandle_with_args(np, "sound-dai",
 259                                         "#sound-dai-cells", 0, &args);
 260        if (ret)
 261                return ret;
 262
 263        *p_node = args.np;
 264
 265        if (args_count)
 266                *args_count = args.args_count;
 267
 268        /* Get dai->name */
 269        if (name) {
 270                ret = snd_soc_of_get_dai_name(np, name);
 271                if (ret < 0)
 272                        return ret;
 273        }
 274
 275        if (!dai)
 276                return 0;
 277
 278        /* Parse TDM slot */
 279        ret = snd_soc_of_parse_tdm_slot(np, &dai->tx_slot_mask,
 280                                        &dai->rx_slot_mask,
 281                                        &dai->slots, &dai->slot_width);
 282        if (ret)
 283                return ret;
 284
 285        /*
 286         * Parse dai->sysclk come from "clocks = <&xxx>"
 287         * (if system has common clock)
 288         *  or "system-clock-frequency = <xxx>"
 289         *  or device's module clock.
 290         */
 291        if (of_property_read_bool(np, "clocks")) {
 292                clk = of_clk_get(np, 0);
 293                if (IS_ERR(clk)) {
 294                        ret = PTR_ERR(clk);
 295                        return ret;
 296                }
 297
 298                dai->sysclk = clk_get_rate(clk);
 299                dai->clk = clk;
 300        } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
 301                dai->sysclk = val;
 302        } else {
 303                clk = of_clk_get(args.np, 0);
 304                if (!IS_ERR(clk))
 305                        dai->sysclk = clk_get_rate(clk);
 306        }
 307
 308        return 0;
 309}
 310
 311static int asoc_simple_card_dai_link_of(struct device_node *node,
 312                                        struct simple_card_data *priv,
 313                                        int idx,
 314                                        bool is_top_level_node)
 315{
 316        struct device *dev = simple_priv_to_dev(priv);
 317        struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
 318        struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
 319        struct device_node *cpu = NULL;
 320        struct device_node *plat = NULL;
 321        struct device_node *codec = NULL;
 322        char prop[128];
 323        char *prefix = "";
 324        int ret, cpu_args;
 325        u32 val;
 326
 327        /* For single DAI link & old style of DT node */
 328        if (is_top_level_node)
 329                prefix = PREFIX;
 330
 331        snprintf(prop, sizeof(prop), "%scpu", prefix);
 332        cpu = of_get_child_by_name(node, prop);
 333
 334        snprintf(prop, sizeof(prop), "%splat", prefix);
 335        plat = of_get_child_by_name(node, prop);
 336
 337        snprintf(prop, sizeof(prop), "%scodec", prefix);
 338        codec = of_get_child_by_name(node, prop);
 339
 340        if (!cpu || !codec) {
 341                ret = -EINVAL;
 342                dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
 343                goto dai_link_of_err;
 344        }
 345
 346        ret = asoc_simple_card_parse_daifmt(dev, node, codec,
 347                                            prefix, &dai_link->dai_fmt);
 348        if (ret < 0)
 349                goto dai_link_of_err;
 350
 351        if (!of_property_read_u32(node, "mclk-fs", &val))
 352                dai_props->mclk_fs = val;
 353
 354        ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,
 355                                            &dai_link->cpu_of_node,
 356                                            &dai_link->cpu_dai_name,
 357                                            &cpu_args);
 358        if (ret < 0)
 359                goto dai_link_of_err;
 360
 361        ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai,
 362                                            &dai_link->codec_of_node,
 363                                            &dai_link->codec_dai_name, NULL);
 364        if (ret < 0)
 365                goto dai_link_of_err;
 366
 367        ret = asoc_simple_card_sub_parse_of(plat, NULL,
 368                                            &dai_link->platform_of_node,
 369                                            NULL, NULL);
 370        if (ret < 0)
 371                goto dai_link_of_err;
 372
 373        if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
 374                ret = -EINVAL;
 375                goto dai_link_of_err;
 376        }
 377
 378        /* Assumes platform == cpu */
 379        if (!dai_link->platform_of_node)
 380                dai_link->platform_of_node = dai_link->cpu_of_node;
 381
 382        ret = asoc_simple_card_set_dailink_name(dev, dai_link,
 383                                                "%s-%s",
 384                                                dai_link->cpu_dai_name,
 385                                                dai_link->codec_dai_name);
 386        if (ret < 0)
 387                goto dai_link_of_err;
 388
 389        dai_link->ops = &asoc_simple_card_ops;
 390        dai_link->init = asoc_simple_card_dai_init;
 391
 392        dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
 393        dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
 394        dev_dbg(dev, "\tcpu : %s / %d\n",
 395                dai_link->cpu_dai_name,
 396                dai_props->cpu_dai.sysclk);
 397        dev_dbg(dev, "\tcodec : %s / %d\n",
 398                dai_link->codec_dai_name,
 399                dai_props->codec_dai.sysclk);
 400
 401        /*
 402         * In soc_bind_dai_link() will check cpu name after
 403         * of_node matching if dai_link has cpu_dai_name.
 404         * but, it will never match if name was created by
 405         * fmt_single_name() remove cpu_dai_name if cpu_args
 406         * was 0. See:
 407         *      fmt_single_name()
 408         *      fmt_multiple_name()
 409         */
 410        if (!cpu_args)
 411                dai_link->cpu_dai_name = NULL;
 412
 413dai_link_of_err:
 414        of_node_put(cpu);
 415        of_node_put(codec);
 416
 417        return ret;
 418}
 419
 420static int asoc_simple_card_parse_of(struct device_node *node,
 421                                     struct simple_card_data *priv)
 422{
 423        struct device *dev = simple_priv_to_dev(priv);
 424        u32 val;
 425        int ret;
 426
 427        if (!node)
 428                return -EINVAL;
 429
 430        /* The off-codec widgets */
 431        if (of_property_read_bool(node, PREFIX "widgets")) {
 432                ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
 433                                        PREFIX "widgets");
 434                if (ret)
 435                        return ret;
 436        }
 437
 438        /* DAPM routes */
 439        if (of_property_read_bool(node, PREFIX "routing")) {
 440                ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
 441                                        PREFIX "routing");
 442                if (ret)
 443                        return ret;
 444        }
 445
 446        /* Factor to mclk, used in hw_params() */
 447        ret = of_property_read_u32(node, PREFIX "mclk-fs", &val);
 448        if (ret == 0)
 449                priv->mclk_fs = val;
 450
 451        /* Single/Muti DAI link(s) & New style of DT node */
 452        if (of_get_child_by_name(node, PREFIX "dai-link")) {
 453                struct device_node *np = NULL;
 454                int i = 0;
 455
 456                for_each_child_of_node(node, np) {
 457                        dev_dbg(dev, "\tlink %d:\n", i);
 458                        ret = asoc_simple_card_dai_link_of(np, priv,
 459                                                           i, false);
 460                        if (ret < 0) {
 461                                of_node_put(np);
 462                                return ret;
 463                        }
 464                        i++;
 465                }
 466        } else {
 467                /* For single DAI link & old style of DT node */
 468                ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
 469                if (ret < 0)
 470                        return ret;
 471        }
 472
 473        ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
 474        if (ret)
 475                return ret;
 476
 477        return 0;
 478}
 479
 480/* Decrease the reference count of the device nodes */
 481static int asoc_simple_card_unref(struct snd_soc_card *card)
 482{
 483        struct snd_soc_dai_link *dai_link;
 484        int num_links;
 485
 486        for (num_links = 0, dai_link = card->dai_link;
 487             num_links < card->num_links;
 488             num_links++, dai_link++) {
 489                of_node_put(dai_link->cpu_of_node);
 490                of_node_put(dai_link->codec_of_node);
 491        }
 492        return 0;
 493}
 494
 495static int asoc_simple_card_probe(struct platform_device *pdev)
 496{
 497        struct simple_card_data *priv;
 498        struct snd_soc_dai_link *dai_link;
 499        struct device_node *np = pdev->dev.of_node;
 500        struct device *dev = &pdev->dev;
 501        int num_links, ret;
 502
 503        /* Get the number of DAI links */
 504        if (np && of_get_child_by_name(np, PREFIX "dai-link"))
 505                num_links = of_get_child_count(np);
 506        else
 507                num_links = 1;
 508
 509        /* Allocate the private data and the DAI link array */
 510        priv = devm_kzalloc(dev,
 511                        sizeof(*priv) + sizeof(*dai_link) * num_links,
 512                        GFP_KERNEL);
 513        if (!priv)
 514                return -ENOMEM;
 515
 516        /* Init snd_soc_card */
 517        priv->snd_card.owner = THIS_MODULE;
 518        priv->snd_card.dev = dev;
 519        dai_link = priv->dai_link;
 520        priv->snd_card.dai_link = dai_link;
 521        priv->snd_card.num_links = num_links;
 522
 523        /* Get room for the other properties */
 524        priv->dai_props = devm_kzalloc(dev,
 525                        sizeof(*priv->dai_props) * num_links,
 526                        GFP_KERNEL);
 527        if (!priv->dai_props)
 528                return -ENOMEM;
 529
 530        if (np && of_device_is_available(np)) {
 531
 532                ret = asoc_simple_card_parse_of(np, priv);
 533                if (ret < 0) {
 534                        if (ret != -EPROBE_DEFER)
 535                                dev_err(dev, "parse error %d\n", ret);
 536                        goto err;
 537                }
 538
 539        } else {
 540                struct asoc_simple_card_info *cinfo;
 541
 542                cinfo = dev->platform_data;
 543                if (!cinfo) {
 544                        dev_err(dev, "no info for asoc-simple-card\n");
 545                        return -EINVAL;
 546                }
 547
 548                if (!cinfo->name ||
 549                    !cinfo->codec_dai.name ||
 550                    !cinfo->codec ||
 551                    !cinfo->platform ||
 552                    !cinfo->cpu_dai.name) {
 553                        dev_err(dev, "insufficient asoc_simple_card_info settings\n");
 554                        return -EINVAL;
 555                }
 556
 557                priv->snd_card.name     = (cinfo->card) ? cinfo->card : cinfo->name;
 558                dai_link->name          = cinfo->name;
 559                dai_link->stream_name   = cinfo->name;
 560                dai_link->platform_name = cinfo->platform;
 561                dai_link->codec_name    = cinfo->codec;
 562                dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
 563                dai_link->codec_dai_name = cinfo->codec_dai.name;
 564                dai_link->dai_fmt       = cinfo->daifmt;
 565                dai_link->init          = asoc_simple_card_dai_init;
 566                memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
 567                                        sizeof(priv->dai_props->cpu_dai));
 568                memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
 569                                        sizeof(priv->dai_props->codec_dai));
 570
 571        }
 572
 573        snd_soc_card_set_drvdata(&priv->snd_card, priv);
 574
 575        ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
 576        if (ret >= 0)
 577                return ret;
 578
 579err:
 580        asoc_simple_card_unref(&priv->snd_card);
 581        return ret;
 582}
 583
 584static int asoc_simple_card_remove(struct platform_device *pdev)
 585{
 586        struct snd_soc_card *card = platform_get_drvdata(pdev);
 587        struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
 588
 589        asoc_simple_card_remove_jack(&priv->hp_jack);
 590        asoc_simple_card_remove_jack(&priv->mic_jack);
 591
 592        return asoc_simple_card_unref(card);
 593}
 594
 595static const struct of_device_id asoc_simple_of_match[] = {
 596        { .compatible = "simple-audio-card", },
 597        {},
 598};
 599MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
 600
 601static struct platform_driver asoc_simple_card = {
 602        .driver = {
 603                .name = "asoc-simple-card",
 604                .pm = &snd_soc_pm_ops,
 605                .of_match_table = asoc_simple_of_match,
 606        },
 607        .probe = asoc_simple_card_probe,
 608        .remove = asoc_simple_card_remove,
 609};
 610
 611module_platform_driver(asoc_simple_card);
 612
 613MODULE_ALIAS("platform:asoc-simple-card");
 614MODULE_LICENSE("GPL");
 615MODULE_DESCRIPTION("ASoC Simple Sound Card");
 616MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 617