linux/sound/soc/rockchip/rockchip_max98090.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Rockchip machine ASoC driver for boards using a MAX90809 CODEC.
   4 *
   5 * Copyright (c) 2014, ROCKCHIP CORPORATION.  All rights reserved.
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/of_device.h>
  10#include <linux/platform_device.h>
  11#include <linux/slab.h>
  12#include <linux/gpio.h>
  13#include <linux/of_gpio.h>
  14#include <sound/core.h>
  15#include <sound/jack.h>
  16#include <sound/pcm.h>
  17#include <sound/pcm_params.h>
  18#include <sound/soc.h>
  19
  20#include "rockchip_i2s.h"
  21#include "../codecs/ts3a227e.h"
  22
  23#define DRV_NAME "rockchip-snd-max98090"
  24
  25static struct snd_soc_jack headset_jack;
  26
  27/* Headset jack detection DAPM pins */
  28static struct snd_soc_jack_pin headset_jack_pins[] = {
  29        {
  30                .pin = "Headphone",
  31                .mask = SND_JACK_HEADPHONE,
  32        },
  33        {
  34                .pin = "Headset Mic",
  35                .mask = SND_JACK_MICROPHONE,
  36        },
  37
  38};
  39
  40#define RK_MAX98090_WIDGETS \
  41        SND_SOC_DAPM_HP("Headphone", NULL), \
  42        SND_SOC_DAPM_MIC("Headset Mic", NULL), \
  43        SND_SOC_DAPM_MIC("Int Mic", NULL), \
  44        SND_SOC_DAPM_SPK("Speaker", NULL)
  45
  46#define RK_HDMI_WIDGETS \
  47        SND_SOC_DAPM_LINE("HDMI", NULL)
  48
  49static const struct snd_soc_dapm_widget rk_max98090_dapm_widgets[] = {
  50        RK_MAX98090_WIDGETS,
  51};
  52
  53static const struct snd_soc_dapm_widget rk_hdmi_dapm_widgets[] = {
  54        RK_HDMI_WIDGETS,
  55};
  56
  57static const struct snd_soc_dapm_widget rk_max98090_hdmi_dapm_widgets[] = {
  58        RK_MAX98090_WIDGETS,
  59        RK_HDMI_WIDGETS,
  60};
  61
  62#define RK_MAX98090_AUDIO_MAP \
  63        {"IN34", NULL, "Headset Mic"}, \
  64        {"Headset Mic", NULL, "MICBIAS"}, \
  65        {"DMICL", NULL, "Int Mic"}, \
  66        {"Headphone", NULL, "HPL"}, \
  67        {"Headphone", NULL, "HPR"}, \
  68        {"Speaker", NULL, "SPKL"}, \
  69        {"Speaker", NULL, "SPKR"}
  70
  71#define RK_HDMI_AUDIO_MAP \
  72        {"HDMI", NULL, "TX"}
  73
  74static const struct snd_soc_dapm_route rk_max98090_audio_map[] = {
  75        RK_MAX98090_AUDIO_MAP,
  76};
  77
  78static const struct snd_soc_dapm_route rk_hdmi_audio_map[] = {
  79        RK_HDMI_AUDIO_MAP,
  80};
  81
  82static const struct snd_soc_dapm_route rk_max98090_hdmi_audio_map[] = {
  83        RK_MAX98090_AUDIO_MAP,
  84        RK_HDMI_AUDIO_MAP,
  85};
  86
  87#define RK_MAX98090_CONTROLS \
  88        SOC_DAPM_PIN_SWITCH("Headphone"), \
  89        SOC_DAPM_PIN_SWITCH("Headset Mic"), \
  90        SOC_DAPM_PIN_SWITCH("Int Mic"), \
  91        SOC_DAPM_PIN_SWITCH("Speaker")
  92
  93#define RK_HDMI_CONTROLS \
  94        SOC_DAPM_PIN_SWITCH("HDMI")
  95
  96static const struct snd_kcontrol_new rk_max98090_controls[] = {
  97        RK_MAX98090_CONTROLS,
  98};
  99
 100static const struct snd_kcontrol_new rk_hdmi_controls[] = {
 101        RK_HDMI_CONTROLS,
 102};
 103
 104static const struct snd_kcontrol_new rk_max98090_hdmi_controls[] = {
 105        RK_MAX98090_CONTROLS,
 106        RK_HDMI_CONTROLS,
 107};
 108
 109static int rk_jack_event(struct notifier_block *nb, unsigned long event,
 110                         void *data)
 111{
 112        struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
 113        struct snd_soc_dapm_context *dapm = &jack->card->dapm;
 114
 115        if (event & SND_JACK_MICROPHONE) {
 116                snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
 117                snd_soc_dapm_force_enable_pin(dapm, "SHDN");
 118        } else {
 119                snd_soc_dapm_disable_pin(dapm, "MICBIAS");
 120                snd_soc_dapm_disable_pin(dapm, "SHDN");
 121        }
 122
 123        snd_soc_dapm_sync(dapm);
 124
 125        return 0;
 126}
 127
 128static struct notifier_block rk_jack_nb = {
 129        .notifier_call = rk_jack_event,
 130};
 131
 132static int rk_init(struct snd_soc_pcm_runtime *runtime)
 133{
 134        /*
 135         * The jack has already been created in the rk_98090_headset_init()
 136         * function.
 137         */
 138        snd_soc_jack_notifier_register(&headset_jack, &rk_jack_nb);
 139
 140        return 0;
 141}
 142
 143static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
 144                             struct snd_pcm_hw_params *params)
 145{
 146        int ret = 0;
 147        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 148        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 149        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 150        int mclk;
 151
 152        switch (params_rate(params)) {
 153        case 8000:
 154        case 16000:
 155        case 24000:
 156        case 32000:
 157        case 48000:
 158        case 64000:
 159        case 96000:
 160                mclk = 12288000;
 161                break;
 162        case 11025:
 163        case 22050:
 164        case 44100:
 165        case 88200:
 166                mclk = 11289600;
 167                break;
 168        default:
 169                return -EINVAL;
 170        }
 171
 172        ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
 173                                     SND_SOC_CLOCK_OUT);
 174        if (ret) {
 175                dev_err(cpu_dai->dev, "Can't set cpu dai clock %d\n", ret);
 176                return ret;
 177        }
 178
 179        ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
 180                                     SND_SOC_CLOCK_IN);
 181
 182        /* HDMI codec dai does not need to set sysclk. */
 183        if (!strcmp(rtd->dai_link->name, "HDMI"))
 184                return 0;
 185
 186        if (ret) {
 187                dev_err(codec_dai->dev, "Can't set codec dai clock %d\n", ret);
 188                return ret;
 189        }
 190
 191        return ret;
 192}
 193
 194static int rk_aif1_startup(struct snd_pcm_substream *substream)
 195{
 196        /*
 197         * Set period size to 240 because pl330 has issue
 198         * dealing with larger period in stress testing.
 199         */
 200        return snd_pcm_hw_constraint_minmax(substream->runtime,
 201                        SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 240, 240);
 202}
 203
 204static const struct snd_soc_ops rk_aif1_ops = {
 205        .hw_params = rk_aif1_hw_params,
 206        .startup = rk_aif1_startup,
 207};
 208
 209SND_SOC_DAILINK_DEFS(analog,
 210                     DAILINK_COMP_ARRAY(COMP_EMPTY()),
 211                     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
 212                     DAILINK_COMP_ARRAY(COMP_EMPTY()));
 213
 214SND_SOC_DAILINK_DEFS(hdmi,
 215                     DAILINK_COMP_ARRAY(COMP_EMPTY()),
 216                     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
 217                     DAILINK_COMP_ARRAY(COMP_EMPTY()));
 218
 219enum {
 220        DAILINK_MAX98090,
 221        DAILINK_HDMI,
 222};
 223
 224static struct snd_soc_jack rk_hdmi_jack;
 225
 226static int rk_hdmi_init(struct snd_soc_pcm_runtime *runtime)
 227{
 228        struct snd_soc_card *card = runtime->card;
 229        struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
 230        int ret;
 231
 232        /* enable jack detection */
 233        ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
 234                                    &rk_hdmi_jack, NULL, 0);
 235        if (ret) {
 236                dev_err(card->dev, "Can't new HDMI Jack %d\n", ret);
 237                return ret;
 238        }
 239
 240        return snd_soc_component_set_jack(component, &rk_hdmi_jack, NULL);
 241}
 242
 243/* max98090 dai_link */
 244static struct snd_soc_dai_link rk_max98090_dailinks[] = {
 245        {
 246                .name = "max98090",
 247                .stream_name = "Analog",
 248                .init = rk_init,
 249                .ops = &rk_aif1_ops,
 250                /* set max98090 as slave */
 251                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 252                        SND_SOC_DAIFMT_CBS_CFS,
 253                SND_SOC_DAILINK_REG(analog),
 254        },
 255};
 256
 257/* HDMI codec dai_link */
 258static struct snd_soc_dai_link rk_hdmi_dailinks[] = {
 259        {
 260                .name = "HDMI",
 261                .stream_name = "HDMI",
 262                .init = rk_hdmi_init,
 263                .ops = &rk_aif1_ops,
 264                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 265                        SND_SOC_DAIFMT_CBS_CFS,
 266                SND_SOC_DAILINK_REG(hdmi),
 267        }
 268};
 269
 270/* max98090 and HDMI codec dai_link */
 271static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = {
 272        [DAILINK_MAX98090] = {
 273                .name = "max98090",
 274                .stream_name = "Analog",
 275                .init = rk_init,
 276                .ops = &rk_aif1_ops,
 277                /* set max98090 as slave */
 278                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 279                        SND_SOC_DAIFMT_CBS_CFS,
 280                SND_SOC_DAILINK_REG(analog),
 281        },
 282        [DAILINK_HDMI] = {
 283                .name = "HDMI",
 284                .stream_name = "HDMI",
 285                .init = rk_hdmi_init,
 286                .ops = &rk_aif1_ops,
 287                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 288                        SND_SOC_DAIFMT_CBS_CFS,
 289                SND_SOC_DAILINK_REG(hdmi),
 290        }
 291};
 292
 293static int rk_98090_headset_init(struct snd_soc_component *component);
 294
 295static struct snd_soc_aux_dev rk_98090_headset_dev = {
 296        .dlc = COMP_EMPTY(),
 297        .init = rk_98090_headset_init,
 298};
 299
 300static struct snd_soc_card rockchip_max98090_card = {
 301        .name = "ROCKCHIP-I2S",
 302        .owner = THIS_MODULE,
 303        .dai_link = rk_max98090_dailinks,
 304        .num_links = ARRAY_SIZE(rk_max98090_dailinks),
 305        .aux_dev = &rk_98090_headset_dev,
 306        .num_aux_devs = 1,
 307        .dapm_widgets = rk_max98090_dapm_widgets,
 308        .num_dapm_widgets = ARRAY_SIZE(rk_max98090_dapm_widgets),
 309        .dapm_routes = rk_max98090_audio_map,
 310        .num_dapm_routes = ARRAY_SIZE(rk_max98090_audio_map),
 311        .controls = rk_max98090_controls,
 312        .num_controls = ARRAY_SIZE(rk_max98090_controls),
 313};
 314
 315static struct snd_soc_card rockchip_hdmi_card = {
 316        .name = "ROCKCHIP-HDMI",
 317        .owner = THIS_MODULE,
 318        .dai_link = rk_hdmi_dailinks,
 319        .num_links = ARRAY_SIZE(rk_hdmi_dailinks),
 320        .dapm_widgets = rk_hdmi_dapm_widgets,
 321        .num_dapm_widgets = ARRAY_SIZE(rk_hdmi_dapm_widgets),
 322        .dapm_routes = rk_hdmi_audio_map,
 323        .num_dapm_routes = ARRAY_SIZE(rk_hdmi_audio_map),
 324        .controls = rk_hdmi_controls,
 325        .num_controls = ARRAY_SIZE(rk_hdmi_controls),
 326};
 327
 328static struct snd_soc_card rockchip_max98090_hdmi_card = {
 329        .name = "ROCKCHIP-MAX98090-HDMI",
 330        .owner = THIS_MODULE,
 331        .dai_link = rk_max98090_hdmi_dailinks,
 332        .num_links = ARRAY_SIZE(rk_max98090_hdmi_dailinks),
 333        .aux_dev = &rk_98090_headset_dev,
 334        .num_aux_devs = 1,
 335        .dapm_widgets = rk_max98090_hdmi_dapm_widgets,
 336        .num_dapm_widgets = ARRAY_SIZE(rk_max98090_hdmi_dapm_widgets),
 337        .dapm_routes = rk_max98090_hdmi_audio_map,
 338        .num_dapm_routes = ARRAY_SIZE(rk_max98090_hdmi_audio_map),
 339        .controls = rk_max98090_hdmi_controls,
 340        .num_controls = ARRAY_SIZE(rk_max98090_hdmi_controls),
 341};
 342
 343static int rk_98090_headset_init(struct snd_soc_component *component)
 344{
 345        int ret;
 346
 347        /* Enable Headset and 4 Buttons Jack detection */
 348        ret = snd_soc_card_jack_new(component->card, "Headset Jack",
 349                                    SND_JACK_HEADSET |
 350                                    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 351                                    SND_JACK_BTN_2 | SND_JACK_BTN_3,
 352                                    &headset_jack,
 353                                    headset_jack_pins,
 354                                    ARRAY_SIZE(headset_jack_pins));
 355        if (ret)
 356                return ret;
 357
 358        ret = ts3a227e_enable_jack_detect(component, &headset_jack);
 359
 360        return ret;
 361}
 362
 363static int rk_parse_headset_from_of(struct device *dev, struct device_node *np)
 364{
 365        rk_98090_headset_dev.dlc.of_node = of_parse_phandle(
 366                        np, "rockchip,headset-codec", 0);
 367        if (!rk_98090_headset_dev.dlc.of_node) {
 368                dev_err(dev,
 369                        "Property 'rockchip,headset-codec' missing/invalid\n");
 370                return -EINVAL;
 371        }
 372        return 0;
 373}
 374
 375static int snd_rk_mc_probe(struct platform_device *pdev)
 376{
 377        int ret = 0;
 378        struct snd_soc_card *card;
 379        struct device *dev = &pdev->dev;
 380        struct device_node *np = pdev->dev.of_node;
 381        struct device_node *np_cpu;
 382        struct device_node *np_audio, *np_hdmi;
 383
 384        /* Parse DTS for I2S controller. */
 385        np_cpu = of_parse_phandle(np, "rockchip,i2s-controller", 0);
 386
 387        if (!np_cpu) {
 388                dev_err(&pdev->dev,
 389                        "Property 'rockchip,i2s-controller missing or invalid\n");
 390                return -EINVAL;
 391        }
 392
 393        /*
 394         * Find the card to use based on the presences of audio codec
 395         * and hdmi codec in device property. Set their of_node accordingly.
 396         */
 397        np_audio = of_parse_phandle(np, "rockchip,audio-codec", 0);
 398        np_hdmi = of_parse_phandle(np, "rockchip,hdmi-codec", 0);
 399        if (np_audio && np_hdmi) {
 400                card = &rockchip_max98090_hdmi_card;
 401                card->dai_link[DAILINK_MAX98090].codecs->of_node = np_audio;
 402                card->dai_link[DAILINK_HDMI].codecs->of_node = np_hdmi;
 403                card->dai_link[DAILINK_MAX98090].cpus->of_node = np_cpu;
 404                card->dai_link[DAILINK_MAX98090].platforms->of_node = np_cpu;
 405                card->dai_link[DAILINK_HDMI].cpus->of_node = np_cpu;
 406                card->dai_link[DAILINK_HDMI].platforms->of_node = np_cpu;
 407        } else if (np_audio) {
 408                card = &rockchip_max98090_card;
 409                card->dai_link[0].codecs->of_node = np_audio;
 410                card->dai_link[0].cpus->of_node = np_cpu;
 411                card->dai_link[0].platforms->of_node = np_cpu;
 412        } else if (np_hdmi) {
 413                card = &rockchip_hdmi_card;
 414                card->dai_link[0].codecs->of_node = np_hdmi;
 415                card->dai_link[0].cpus->of_node = np_cpu;
 416                card->dai_link[0].platforms->of_node = np_cpu;
 417        } else {
 418                dev_err(dev, "At least one of codecs should be specified\n");
 419                return -EINVAL;
 420        }
 421
 422        card->dev = dev;
 423
 424        /* Parse headset detection codec. */
 425        if (np_audio) {
 426                ret = rk_parse_headset_from_of(dev, np);
 427                if (ret)
 428                        return ret;
 429        }
 430
 431        /* Parse card name. */
 432        ret = snd_soc_of_parse_card_name(card, "rockchip,model");
 433        if (ret) {
 434                dev_err(&pdev->dev,
 435                        "Soc parse card name failed %d\n", ret);
 436                return ret;
 437        }
 438
 439        /* register the soc card */
 440        ret = devm_snd_soc_register_card(&pdev->dev, card);
 441        if (ret) {
 442                dev_err(&pdev->dev,
 443                        "Soc register card failed %d\n", ret);
 444                return ret;
 445        }
 446
 447        return ret;
 448}
 449
 450static const struct of_device_id rockchip_max98090_of_match[] = {
 451        { .compatible = "rockchip,rockchip-audio-max98090", },
 452        {},
 453};
 454
 455MODULE_DEVICE_TABLE(of, rockchip_max98090_of_match);
 456
 457static struct platform_driver snd_rk_mc_driver = {
 458        .probe = snd_rk_mc_probe,
 459        .driver = {
 460                .name = DRV_NAME,
 461                .pm = &snd_soc_pm_ops,
 462                .of_match_table = rockchip_max98090_of_match,
 463        },
 464};
 465
 466module_platform_driver(snd_rk_mc_driver);
 467
 468MODULE_AUTHOR("jianqun <jay.xu@rock-chips.com>");
 469MODULE_DESCRIPTION("Rockchip max98090 machine ASoC driver");
 470MODULE_LICENSE("GPL v2");
 471MODULE_ALIAS("platform:" DRV_NAME);
 472