linux/sound/soc/rockchip/rk3399_gru_sound.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
   4 *
   5 * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/platform_device.h>
  10#include <linux/slab.h>
  11#include <linux/gpio.h>
  12#include <linux/of_gpio.h>
  13#include <linux/delay.h>
  14#include <linux/spi/spi.h>
  15#include <linux/i2c.h>
  16#include <linux/input.h>
  17#include <sound/core.h>
  18#include <sound/jack.h>
  19#include <sound/pcm.h>
  20#include <sound/pcm_params.h>
  21#include <sound/soc.h>
  22#include "rockchip_i2s.h"
  23#include "../codecs/da7219.h"
  24#include "../codecs/da7219-aad.h"
  25#include "../codecs/rt5514.h"
  26
  27#define DRV_NAME "rk3399-gru-sound"
  28
  29#define SOUND_FS        256
  30
  31static unsigned int dmic_wakeup_delay;
  32
  33static struct snd_soc_jack rockchip_sound_jack;
  34
  35static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
  36        SND_SOC_DAPM_HP("Headphones", NULL),
  37        SND_SOC_DAPM_SPK("Speakers", NULL),
  38        SND_SOC_DAPM_MIC("Headset Mic", NULL),
  39        SND_SOC_DAPM_MIC("Int Mic", NULL),
  40        SND_SOC_DAPM_LINE("HDMI", NULL),
  41};
  42
  43static const struct snd_kcontrol_new rockchip_controls[] = {
  44        SOC_DAPM_PIN_SWITCH("Headphones"),
  45        SOC_DAPM_PIN_SWITCH("Speakers"),
  46        SOC_DAPM_PIN_SWITCH("Headset Mic"),
  47        SOC_DAPM_PIN_SWITCH("Int Mic"),
  48        SOC_DAPM_PIN_SWITCH("HDMI"),
  49};
  50
  51static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
  52                             struct snd_pcm_hw_params *params)
  53{
  54        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  55        unsigned int mclk;
  56        int ret;
  57
  58        mclk = params_rate(params) * SOUND_FS;
  59
  60        ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
  61        if (ret) {
  62                dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
  63                                __func__, mclk, ret);
  64                return ret;
  65        }
  66
  67        return 0;
  68}
  69
  70static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
  71                             struct snd_pcm_hw_params *params)
  72{
  73        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  74        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  75        struct snd_soc_dai *codec_dai = rtd->codec_dai;
  76        unsigned int mclk;
  77        int ret;
  78
  79        mclk = params_rate(params) * SOUND_FS;
  80
  81        ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
  82                                     SND_SOC_CLOCK_OUT);
  83        if (ret < 0) {
  84                dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
  85                return ret;
  86        }
  87
  88        ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
  89                                     mclk, SND_SOC_CLOCK_IN);
  90        if (ret) {
  91                dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
  92                                __func__, params_rate(params) * 512, ret);
  93                return ret;
  94        }
  95
  96        /* Wait for DMIC stable */
  97        msleep(dmic_wakeup_delay);
  98
  99        return 0;
 100}
 101
 102static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
 103                             struct snd_pcm_hw_params *params)
 104{
 105        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 106        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 107        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 108        int mclk, ret;
 109
 110        /* in bypass mode, the mclk has to be one of the frequencies below */
 111        switch (params_rate(params)) {
 112        case 8000:
 113        case 16000:
 114        case 24000:
 115        case 32000:
 116        case 48000:
 117        case 64000:
 118        case 96000:
 119                mclk = 12288000;
 120                break;
 121        case 11025:
 122        case 22050:
 123        case 44100:
 124        case 88200:
 125                mclk = 11289600;
 126                break;
 127        default:
 128                return -EINVAL;
 129        }
 130
 131        ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
 132                                     SND_SOC_CLOCK_OUT);
 133        if (ret < 0) {
 134                dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
 135                return ret;
 136        }
 137
 138        ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
 139                                     SND_SOC_CLOCK_IN);
 140        if (ret < 0) {
 141                dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
 142                return ret;
 143        }
 144
 145        ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
 146        if (ret < 0) {
 147                dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
 148                return ret;
 149        }
 150
 151        return 0;
 152}
 153
 154static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
 155{
 156        struct snd_soc_component *component = rtd->codec_dais[0]->component;
 157        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 158        int ret;
 159
 160        /* We need default MCLK and PLL settings for the accessory detection */
 161        ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000,
 162                                     SND_SOC_CLOCK_IN);
 163        if (ret < 0) {
 164                dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret);
 165                return ret;
 166        }
 167
 168        ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
 169        if (ret < 0) {
 170                dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret);
 171                return ret;
 172        }
 173
 174        /* Enable Headset and 4 Buttons Jack detection */
 175        ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
 176                                    SND_JACK_HEADSET | SND_JACK_LINEOUT |
 177                                    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 178                                    SND_JACK_BTN_2 | SND_JACK_BTN_3,
 179                                    &rockchip_sound_jack, NULL, 0);
 180
 181        if (ret) {
 182                dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
 183                return ret;
 184        }
 185
 186        snd_jack_set_key(
 187                rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
 188        snd_jack_set_key(
 189                rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
 190        snd_jack_set_key(
 191                rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
 192        snd_jack_set_key(
 193                rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
 194
 195        da7219_aad_jack_det(component, &rockchip_sound_jack);
 196
 197        return 0;
 198}
 199
 200static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,
 201                             struct snd_pcm_hw_params *params)
 202{
 203        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 204        unsigned int mclk;
 205        int ret;
 206
 207        mclk = params_rate(params) * SOUND_FS;
 208
 209        ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
 210        if (ret) {
 211                dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
 212                                __func__, mclk, ret);
 213                return ret;
 214        }
 215
 216        /* Wait for DMIC stable */
 217        msleep(dmic_wakeup_delay);
 218
 219        return 0;
 220}
 221
 222static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
 223        .hw_params = rockchip_sound_max98357a_hw_params,
 224};
 225
 226static const struct snd_soc_ops rockchip_sound_rt5514_ops = {
 227        .hw_params = rockchip_sound_rt5514_hw_params,
 228};
 229
 230static const struct snd_soc_ops rockchip_sound_da7219_ops = {
 231        .hw_params = rockchip_sound_da7219_hw_params,
 232};
 233
 234static const struct snd_soc_ops rockchip_sound_dmic_ops = {
 235        .hw_params = rockchip_sound_dmic_hw_params,
 236};
 237
 238static struct snd_soc_card rockchip_sound_card = {
 239        .name = "rk3399-gru-sound",
 240        .owner = THIS_MODULE,
 241        .dapm_widgets = rockchip_dapm_widgets,
 242        .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
 243        .controls = rockchip_controls,
 244        .num_controls = ARRAY_SIZE(rockchip_controls),
 245};
 246
 247enum {
 248        DAILINK_CDNDP,
 249        DAILINK_DA7219,
 250        DAILINK_DMIC,
 251        DAILINK_MAX98357A,
 252        DAILINK_RT5514,
 253        DAILINK_RT5514_DSP,
 254};
 255
 256SND_SOC_DAILINK_DEFS(cdndp,
 257        DAILINK_COMP_ARRAY(COMP_EMPTY()),
 258        DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "spdif-hifi")),
 259        DAILINK_COMP_ARRAY(COMP_EMPTY()));
 260
 261SND_SOC_DAILINK_DEFS(da7219,
 262        DAILINK_COMP_ARRAY(COMP_EMPTY()),
 263        DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "da7219-hifi")),
 264        DAILINK_COMP_ARRAY(COMP_EMPTY()));
 265
 266SND_SOC_DAILINK_DEFS(dmic,
 267        DAILINK_COMP_ARRAY(COMP_EMPTY()),
 268        DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dmic-hifi")),
 269        DAILINK_COMP_ARRAY(COMP_EMPTY()));
 270
 271SND_SOC_DAILINK_DEFS(max98357a,
 272        DAILINK_COMP_ARRAY(COMP_EMPTY()),
 273        DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
 274        DAILINK_COMP_ARRAY(COMP_EMPTY()));
 275
 276SND_SOC_DAILINK_DEFS(rt5514,
 277        DAILINK_COMP_ARRAY(COMP_EMPTY()),
 278        DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5514-aif1")),
 279        DAILINK_COMP_ARRAY(COMP_EMPTY()));
 280
 281SND_SOC_DAILINK_DEFS(rt5514_dsp,
 282        DAILINK_COMP_ARRAY(COMP_EMPTY()),
 283        DAILINK_COMP_ARRAY(COMP_DUMMY()),
 284        DAILINK_COMP_ARRAY(COMP_EMPTY()));
 285
 286static const struct snd_soc_dai_link rockchip_dais[] = {
 287        [DAILINK_CDNDP] = {
 288                .name = "DP",
 289                .stream_name = "DP PCM",
 290                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 291                        SND_SOC_DAIFMT_CBS_CFS,
 292                SND_SOC_DAILINK_REG(cdndp),
 293        },
 294        [DAILINK_DA7219] = {
 295                .name = "DA7219",
 296                .stream_name = "DA7219 PCM",
 297                .init = rockchip_sound_da7219_init,
 298                .ops = &rockchip_sound_da7219_ops,
 299                /* set da7219 as slave */
 300                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 301                        SND_SOC_DAIFMT_CBS_CFS,
 302                SND_SOC_DAILINK_REG(da7219),
 303        },
 304        [DAILINK_DMIC] = {
 305                .name = "DMIC",
 306                .stream_name = "DMIC PCM",
 307                .ops = &rockchip_sound_dmic_ops,
 308                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 309                        SND_SOC_DAIFMT_CBS_CFS,
 310                SND_SOC_DAILINK_REG(dmic),
 311        },
 312        [DAILINK_MAX98357A] = {
 313                .name = "MAX98357A",
 314                .stream_name = "MAX98357A PCM",
 315                .ops = &rockchip_sound_max98357a_ops,
 316                /* set max98357a as slave */
 317                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 318                        SND_SOC_DAIFMT_CBS_CFS,
 319                SND_SOC_DAILINK_REG(max98357a),
 320        },
 321        [DAILINK_RT5514] = {
 322                .name = "RT5514",
 323                .stream_name = "RT5514 PCM",
 324                .ops = &rockchip_sound_rt5514_ops,
 325                /* set rt5514 as slave */
 326                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 327                        SND_SOC_DAIFMT_CBS_CFS,
 328                SND_SOC_DAILINK_REG(rt5514),
 329        },
 330        /* RT5514 DSP for voice wakeup via spi bus */
 331        [DAILINK_RT5514_DSP] = {
 332                .name = "RT5514 DSP",
 333                .stream_name = "Wake on Voice",
 334                SND_SOC_DAILINK_REG(rt5514_dsp),
 335        },
 336};
 337
 338static const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = {
 339        /* Output */
 340        {"HDMI", NULL, "TX"},
 341};
 342
 343static const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = {
 344        /* Output */
 345        {"Headphones", NULL, "HPL"},
 346        {"Headphones", NULL, "HPR"},
 347
 348        /* Input */
 349        {"MIC", NULL, "Headset Mic"},
 350};
 351
 352static const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = {
 353        /* Input */
 354        {"DMic", NULL, "Int Mic"},
 355};
 356
 357static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = {
 358        /* Output */
 359        {"Speakers", NULL, "Speaker"},
 360};
 361
 362static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = {
 363        /* Input */
 364        {"DMIC1L", NULL, "Int Mic"},
 365        {"DMIC1R", NULL, "Int Mic"},
 366};
 367
 368struct rockchip_sound_route {
 369        const struct snd_soc_dapm_route *routes;
 370        int num_routes;
 371};
 372
 373static const struct rockchip_sound_route rockchip_routes[] = {
 374        [DAILINK_CDNDP] = {
 375                .routes = rockchip_sound_cdndp_routes,
 376                .num_routes = ARRAY_SIZE(rockchip_sound_cdndp_routes),
 377        },
 378        [DAILINK_DA7219] = {
 379                .routes = rockchip_sound_da7219_routes,
 380                .num_routes = ARRAY_SIZE(rockchip_sound_da7219_routes),
 381        },
 382        [DAILINK_DMIC] = {
 383                .routes = rockchip_sound_dmic_routes,
 384                .num_routes = ARRAY_SIZE(rockchip_sound_dmic_routes),
 385        },
 386        [DAILINK_MAX98357A] = {
 387                .routes = rockchip_sound_max98357a_routes,
 388                .num_routes = ARRAY_SIZE(rockchip_sound_max98357a_routes),
 389        },
 390        [DAILINK_RT5514] = {
 391                .routes = rockchip_sound_rt5514_routes,
 392                .num_routes = ARRAY_SIZE(rockchip_sound_rt5514_routes),
 393        },
 394        [DAILINK_RT5514_DSP] = {},
 395};
 396
 397struct dailink_match_data {
 398        const char *compatible;
 399        struct bus_type *bus_type;
 400};
 401
 402static const struct dailink_match_data dailink_match[] = {
 403        [DAILINK_CDNDP] = {
 404                .compatible = "rockchip,rk3399-cdn-dp",
 405        },
 406        [DAILINK_DA7219] = {
 407                .compatible = "dlg,da7219",
 408        },
 409        [DAILINK_DMIC] = {
 410                .compatible = "dmic-codec",
 411        },
 412        [DAILINK_MAX98357A] = {
 413                .compatible = "maxim,max98357a",
 414        },
 415        [DAILINK_RT5514] = {
 416                .compatible = "realtek,rt5514",
 417                .bus_type = &i2c_bus_type,
 418        },
 419        [DAILINK_RT5514_DSP] = {
 420                .compatible = "realtek,rt5514",
 421                .bus_type = &spi_bus_type,
 422        },
 423};
 424
 425static int of_dev_node_match(struct device *dev, const void *data)
 426{
 427        return dev->of_node == data;
 428}
 429
 430static int rockchip_sound_codec_node_match(struct device_node *np_codec)
 431{
 432        struct device *dev;
 433        int i;
 434
 435        for (i = 0; i < ARRAY_SIZE(dailink_match); i++) {
 436                if (!of_device_is_compatible(np_codec,
 437                                             dailink_match[i].compatible))
 438                        continue;
 439
 440                if (dailink_match[i].bus_type) {
 441                        dev = bus_find_device(dailink_match[i].bus_type, NULL,
 442                                              np_codec, of_dev_node_match);
 443                        if (!dev)
 444                                continue;
 445                        put_device(dev);
 446                }
 447
 448                return i;
 449        }
 450        return -1;
 451}
 452
 453static int rockchip_sound_of_parse_dais(struct device *dev,
 454                                        struct snd_soc_card *card)
 455{
 456        struct device_node *np_cpu, *np_cpu0, *np_cpu1;
 457        struct device_node *np_codec;
 458        struct snd_soc_dai_link *dai;
 459        struct snd_soc_dapm_route *routes;
 460        int i, index;
 461        int num_routes;
 462
 463        card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
 464                                      GFP_KERNEL);
 465        if (!card->dai_link)
 466                return -ENOMEM;
 467
 468        num_routes = 0;
 469        for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++)
 470                num_routes += rockchip_routes[i].num_routes;
 471        routes = devm_kcalloc(dev, num_routes, sizeof(*routes),
 472                              GFP_KERNEL);
 473        if (!routes)
 474                return -ENOMEM;
 475        card->dapm_routes = routes;
 476
 477        np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
 478        np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);
 479
 480        card->num_dapm_routes = 0;
 481        card->num_links = 0;
 482        for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
 483                np_codec = of_parse_phandle(dev->of_node,
 484                                            "rockchip,codec", i);
 485                if (!np_codec)
 486                        break;
 487
 488                if (!of_device_is_available(np_codec))
 489                        continue;
 490
 491                index = rockchip_sound_codec_node_match(np_codec);
 492                if (index < 0)
 493                        continue;
 494
 495                switch (index) {
 496                case DAILINK_CDNDP:
 497                        np_cpu = np_cpu1;
 498                        break;
 499                case DAILINK_RT5514_DSP:
 500                        np_cpu = np_codec;
 501                        break;
 502                default:
 503                        np_cpu = np_cpu0;
 504                        break;
 505                }
 506
 507                if (!np_cpu) {
 508                        dev_err(dev, "Missing 'rockchip,cpu' for %s\n",
 509                                rockchip_dais[index].name);
 510                        return -EINVAL;
 511                }
 512
 513                dai = &card->dai_link[card->num_links++];
 514                *dai = rockchip_dais[index];
 515
 516                if (!dai->codecs->name)
 517                        dai->codecs->of_node = np_codec;
 518                dai->platforms->of_node = np_cpu;
 519                dai->cpus->of_node = np_cpu;
 520
 521                if (card->num_dapm_routes + rockchip_routes[index].num_routes >
 522                    num_routes) {
 523                        dev_err(dev, "Too many routes\n");
 524                        return -EINVAL;
 525                }
 526
 527                memcpy(routes + card->num_dapm_routes,
 528                       rockchip_routes[index].routes,
 529                       rockchip_routes[index].num_routes * sizeof(*routes));
 530                card->num_dapm_routes += rockchip_routes[index].num_routes;
 531        }
 532
 533        return 0;
 534}
 535
 536static int rockchip_sound_probe(struct platform_device *pdev)
 537{
 538        struct snd_soc_card *card = &rockchip_sound_card;
 539        int ret;
 540
 541        ret = rockchip_sound_of_parse_dais(&pdev->dev, card);
 542        if (ret < 0) {
 543                dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret);
 544                return ret;
 545        }
 546
 547        /* Set DMIC wakeup delay */
 548        ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms",
 549                                        &dmic_wakeup_delay);
 550        if (ret) {
 551                dmic_wakeup_delay = 0;
 552                dev_dbg(&pdev->dev,
 553                        "no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n");
 554        }
 555
 556        card->dev = &pdev->dev;
 557        return devm_snd_soc_register_card(&pdev->dev, card);
 558}
 559
 560static const struct of_device_id rockchip_sound_of_match[] = {
 561        { .compatible = "rockchip,rk3399-gru-sound", },
 562        {},
 563};
 564
 565static struct platform_driver rockchip_sound_driver = {
 566        .probe = rockchip_sound_probe,
 567        .driver = {
 568                .name = DRV_NAME,
 569                .of_match_table = rockchip_sound_of_match,
 570#ifdef CONFIG_PM
 571                .pm = &snd_soc_pm_ops,
 572#endif
 573        },
 574};
 575
 576module_platform_driver(rockchip_sound_driver);
 577
 578MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
 579MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
 580MODULE_LICENSE("GPL v2");
 581MODULE_ALIAS("platform:" DRV_NAME);
 582MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);
 583