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