linux/sound/soc/intel/boards/skl_rt286.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Intel Skylake I2S Machine Driver
   4 *
   5 * Copyright (C) 2014-2015, Intel Corporation. All rights reserved.
   6 *
   7 * Modified from:
   8 *   Intel Broadwell Wildcatpoint SST Audio
   9 *
  10 *   Copyright (C) 2013, Intel Corporation. All rights reserved.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/platform_device.h>
  15#include <sound/core.h>
  16#include <sound/pcm.h>
  17#include <sound/soc.h>
  18#include <sound/jack.h>
  19#include <sound/pcm_params.h>
  20#include "../../codecs/rt286.h"
  21#include "../../codecs/hdac_hdmi.h"
  22
  23static struct snd_soc_jack skylake_headset;
  24static struct snd_soc_jack skylake_hdmi[3];
  25
  26struct skl_hdmi_pcm {
  27        struct list_head head;
  28        struct snd_soc_dai *codec_dai;
  29        int device;
  30};
  31
  32struct skl_rt286_private {
  33        struct list_head hdmi_pcm_list;
  34};
  35
  36enum {
  37        SKL_DPCM_AUDIO_PB = 0,
  38        SKL_DPCM_AUDIO_DB_PB,
  39        SKL_DPCM_AUDIO_CP,
  40        SKL_DPCM_AUDIO_REF_CP,
  41        SKL_DPCM_AUDIO_DMIC_CP,
  42        SKL_DPCM_AUDIO_HDMI1_PB,
  43        SKL_DPCM_AUDIO_HDMI2_PB,
  44        SKL_DPCM_AUDIO_HDMI3_PB,
  45};
  46
  47/* Headset jack detection DAPM pins */
  48static struct snd_soc_jack_pin skylake_headset_pins[] = {
  49        {
  50                .pin = "Mic Jack",
  51                .mask = SND_JACK_MICROPHONE,
  52        },
  53        {
  54                .pin = "Headphone Jack",
  55                .mask = SND_JACK_HEADPHONE,
  56        },
  57};
  58
  59static const struct snd_kcontrol_new skylake_controls[] = {
  60        SOC_DAPM_PIN_SWITCH("Speaker"),
  61        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
  62        SOC_DAPM_PIN_SWITCH("Mic Jack"),
  63};
  64
  65static const struct snd_soc_dapm_widget skylake_widgets[] = {
  66        SND_SOC_DAPM_HP("Headphone Jack", NULL),
  67        SND_SOC_DAPM_SPK("Speaker", NULL),
  68        SND_SOC_DAPM_MIC("Mic Jack", NULL),
  69        SND_SOC_DAPM_MIC("DMIC2", NULL),
  70        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
  71        SND_SOC_DAPM_SPK("HDMI1", NULL),
  72        SND_SOC_DAPM_SPK("HDMI2", NULL),
  73        SND_SOC_DAPM_SPK("HDMI3", NULL),
  74};
  75
  76static const struct snd_soc_dapm_route skylake_rt286_map[] = {
  77        /* speaker */
  78        {"Speaker", NULL, "SPOR"},
  79        {"Speaker", NULL, "SPOL"},
  80
  81        /* HP jack connectors - unknown if we have jack deteck */
  82        {"Headphone Jack", NULL, "HPO Pin"},
  83
  84        /* other jacks */
  85        {"MIC1", NULL, "Mic Jack"},
  86
  87        /* digital mics */
  88        {"DMIC1 Pin", NULL, "DMIC2"},
  89        {"DMic", NULL, "SoC DMIC"},
  90
  91        /* CODEC BE connections */
  92        { "AIF1 Playback", NULL, "ssp0 Tx"},
  93        { "ssp0 Tx", NULL, "codec0_out"},
  94        { "ssp0 Tx", NULL, "codec1_out"},
  95
  96        { "codec0_in", NULL, "ssp0 Rx" },
  97        { "codec1_in", NULL, "ssp0 Rx" },
  98        { "ssp0 Rx", NULL, "AIF1 Capture" },
  99
 100        { "dmic01_hifi", NULL, "DMIC01 Rx" },
 101        { "DMIC01 Rx", NULL, "DMIC AIF" },
 102
 103        { "hifi3", NULL, "iDisp3 Tx"},
 104        { "iDisp3 Tx", NULL, "iDisp3_out"},
 105        { "hifi2", NULL, "iDisp2 Tx"},
 106        { "iDisp2 Tx", NULL, "iDisp2_out"},
 107        { "hifi1", NULL, "iDisp1 Tx"},
 108        { "iDisp1 Tx", NULL, "iDisp1_out"},
 109
 110};
 111
 112static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd)
 113{
 114        struct snd_soc_dapm_context *dapm;
 115        struct snd_soc_component *component = asoc_rtd_to_cpu(rtd, 0)->component;
 116
 117        dapm = snd_soc_component_get_dapm(component);
 118        snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
 119
 120        return 0;
 121}
 122
 123static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 124{
 125        struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
 126        int ret;
 127
 128        ret = snd_soc_card_jack_new(rtd->card, "Headset",
 129                SND_JACK_HEADSET | SND_JACK_BTN_0,
 130                &skylake_headset,
 131                skylake_headset_pins, ARRAY_SIZE(skylake_headset_pins));
 132
 133        if (ret)
 134                return ret;
 135
 136        rt286_mic_detect(component, &skylake_headset);
 137
 138        snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 139
 140        return 0;
 141}
 142
 143static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
 144{
 145        struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card);
 146        struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
 147        struct skl_hdmi_pcm *pcm;
 148
 149        pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
 150        if (!pcm)
 151                return -ENOMEM;
 152
 153        pcm->device = SKL_DPCM_AUDIO_HDMI1_PB + dai->id;
 154        pcm->codec_dai = dai;
 155
 156        list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
 157
 158        return 0;
 159}
 160
 161static const unsigned int rates[] = {
 162        48000,
 163};
 164
 165static const struct snd_pcm_hw_constraint_list constraints_rates = {
 166        .count = ARRAY_SIZE(rates),
 167        .list  = rates,
 168        .mask = 0,
 169};
 170
 171static const unsigned int channels[] = {
 172        2,
 173};
 174
 175static const struct snd_pcm_hw_constraint_list constraints_channels = {
 176        .count = ARRAY_SIZE(channels),
 177        .list = channels,
 178        .mask = 0,
 179};
 180
 181static int skl_fe_startup(struct snd_pcm_substream *substream)
 182{
 183        struct snd_pcm_runtime *runtime = substream->runtime;
 184
 185        /*
 186         * on this platform for PCM device we support,
 187         *      48Khz
 188         *      stereo
 189         *      16 bit audio
 190         */
 191
 192        runtime->hw.channels_max = 2;
 193        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 194                                           &constraints_channels);
 195
 196        runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
 197        snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
 198
 199        snd_pcm_hw_constraint_list(runtime, 0,
 200                                SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 201
 202        return 0;
 203}
 204
 205static const struct snd_soc_ops skylake_rt286_fe_ops = {
 206        .startup = skl_fe_startup,
 207};
 208
 209static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
 210                        struct snd_pcm_hw_params *params)
 211{
 212        struct snd_interval *rate = hw_param_interval(params,
 213                        SNDRV_PCM_HW_PARAM_RATE);
 214        struct snd_interval *chan = hw_param_interval(params,
 215                                                SNDRV_PCM_HW_PARAM_CHANNELS);
 216        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 217
 218        /* The output is 48KHz, stereo, 16bits */
 219        rate->min = rate->max = 48000;
 220        chan->min = chan->max = 2;
 221
 222        /* set SSP0 to 24 bit */
 223        snd_mask_none(fmt);
 224        snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
 225        return 0;
 226}
 227
 228static int skylake_rt286_hw_params(struct snd_pcm_substream *substream,
 229        struct snd_pcm_hw_params *params)
 230{
 231        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
 232        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
 233        int ret;
 234
 235        ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
 236                SND_SOC_CLOCK_IN);
 237        if (ret < 0)
 238                dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
 239
 240        return ret;
 241}
 242
 243static const struct snd_soc_ops skylake_rt286_ops = {
 244        .hw_params = skylake_rt286_hw_params,
 245};
 246
 247static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
 248                                struct snd_pcm_hw_params *params)
 249{
 250        struct snd_interval *chan = hw_param_interval(params,
 251                                                SNDRV_PCM_HW_PARAM_CHANNELS);
 252        if (params_channels(params) == 2)
 253                chan->min = chan->max = 2;
 254        else
 255                chan->min = chan->max = 4;
 256
 257        return 0;
 258}
 259
 260static const unsigned int channels_dmic[] = {
 261        2, 4,
 262};
 263
 264static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
 265        .count = ARRAY_SIZE(channels_dmic),
 266        .list = channels_dmic,
 267        .mask = 0,
 268};
 269
 270static int skylake_dmic_startup(struct snd_pcm_substream *substream)
 271{
 272        struct snd_pcm_runtime *runtime = substream->runtime;
 273
 274        runtime->hw.channels_max = 4;
 275        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 276                                           &constraints_dmic_channels);
 277
 278        return snd_pcm_hw_constraint_list(substream->runtime, 0,
 279                        SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 280}
 281
 282static const struct snd_soc_ops skylake_dmic_ops = {
 283        .startup = skylake_dmic_startup,
 284};
 285
 286SND_SOC_DAILINK_DEF(dummy,
 287        DAILINK_COMP_ARRAY(COMP_DUMMY()));
 288
 289SND_SOC_DAILINK_DEF(system,
 290        DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
 291
 292SND_SOC_DAILINK_DEF(deepbuffer,
 293        DAILINK_COMP_ARRAY(COMP_CPU("Deepbuffer Pin")));
 294
 295SND_SOC_DAILINK_DEF(reference,
 296        DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin")));
 297
 298SND_SOC_DAILINK_DEF(dmic,
 299        DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
 300
 301SND_SOC_DAILINK_DEF(hdmi1,
 302        DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin")));
 303
 304SND_SOC_DAILINK_DEF(hdmi2,
 305        DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin")));
 306
 307SND_SOC_DAILINK_DEF(hdmi3,
 308        DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin")));
 309
 310SND_SOC_DAILINK_DEF(ssp0_pin,
 311        DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
 312SND_SOC_DAILINK_DEF(ssp0_codec,
 313        DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
 314
 315SND_SOC_DAILINK_DEF(dmic01_pin,
 316        DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
 317SND_SOC_DAILINK_DEF(dmic_codec,
 318        DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
 319
 320SND_SOC_DAILINK_DEF(idisp1_pin,
 321        DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
 322SND_SOC_DAILINK_DEF(idisp1_codec,
 323        DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
 324
 325SND_SOC_DAILINK_DEF(idisp2_pin,
 326        DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
 327SND_SOC_DAILINK_DEF(idisp2_codec,
 328        DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
 329
 330SND_SOC_DAILINK_DEF(idisp3_pin,
 331        DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
 332SND_SOC_DAILINK_DEF(idisp3_codec,
 333        DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
 334
 335SND_SOC_DAILINK_DEF(platform,
 336        DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
 337
 338/* skylake digital audio interface glue - connects codec <--> CPU */
 339static struct snd_soc_dai_link skylake_rt286_dais[] = {
 340        /* Front End DAI links */
 341        [SKL_DPCM_AUDIO_PB] = {
 342                .name = "Skl Audio Port",
 343                .stream_name = "Audio",
 344                .nonatomic = 1,
 345                .dynamic = 1,
 346                .init = skylake_rt286_fe_init,
 347                .trigger = {
 348                        SND_SOC_DPCM_TRIGGER_POST,
 349                        SND_SOC_DPCM_TRIGGER_POST
 350                },
 351                .dpcm_playback = 1,
 352                .ops = &skylake_rt286_fe_ops,
 353                SND_SOC_DAILINK_REG(system, dummy, platform),
 354        },
 355        [SKL_DPCM_AUDIO_DB_PB] = {
 356                .name = "Skl Deepbuffer Port",
 357                .stream_name = "Deep Buffer Audio",
 358                .nonatomic = 1,
 359                .dynamic = 1,
 360                .trigger = {
 361                        SND_SOC_DPCM_TRIGGER_POST,
 362                        SND_SOC_DPCM_TRIGGER_POST
 363                },
 364                .dpcm_playback = 1,
 365                .ops = &skylake_rt286_fe_ops,
 366                SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
 367        },
 368        [SKL_DPCM_AUDIO_CP] = {
 369                .name = "Skl Audio Capture Port",
 370                .stream_name = "Audio Record",
 371                .nonatomic = 1,
 372                .dynamic = 1,
 373                .trigger = {
 374                        SND_SOC_DPCM_TRIGGER_POST,
 375                        SND_SOC_DPCM_TRIGGER_POST
 376                },
 377                .dpcm_capture = 1,
 378                .ops = &skylake_rt286_fe_ops,
 379                SND_SOC_DAILINK_REG(system, dummy, platform),
 380        },
 381        [SKL_DPCM_AUDIO_REF_CP] = {
 382                .name = "Skl Audio Reference cap",
 383                .stream_name = "refcap",
 384                .init = NULL,
 385                .dpcm_capture = 1,
 386                .nonatomic = 1,
 387                .dynamic = 1,
 388                SND_SOC_DAILINK_REG(reference, dummy, platform),
 389        },
 390        [SKL_DPCM_AUDIO_DMIC_CP] = {
 391                .name = "Skl Audio DMIC cap",
 392                .stream_name = "dmiccap",
 393                .init = NULL,
 394                .dpcm_capture = 1,
 395                .nonatomic = 1,
 396                .dynamic = 1,
 397                .ops = &skylake_dmic_ops,
 398                SND_SOC_DAILINK_REG(dmic, dummy, platform),
 399        },
 400        [SKL_DPCM_AUDIO_HDMI1_PB] = {
 401                .name = "Skl HDMI Port1",
 402                .stream_name = "Hdmi1",
 403                .dpcm_playback = 1,
 404                .init = NULL,
 405                .nonatomic = 1,
 406                .dynamic = 1,
 407                SND_SOC_DAILINK_REG(hdmi1, dummy, platform),
 408        },
 409        [SKL_DPCM_AUDIO_HDMI2_PB] = {
 410                .name = "Skl HDMI Port2",
 411                .stream_name = "Hdmi2",
 412                .dpcm_playback = 1,
 413                .init = NULL,
 414                .nonatomic = 1,
 415                .dynamic = 1,
 416                SND_SOC_DAILINK_REG(hdmi2, dummy, platform),
 417        },
 418        [SKL_DPCM_AUDIO_HDMI3_PB] = {
 419                .name = "Skl HDMI Port3",
 420                .stream_name = "Hdmi3",
 421                .dpcm_playback = 1,
 422                .init = NULL,
 423                .nonatomic = 1,
 424                .dynamic = 1,
 425                SND_SOC_DAILINK_REG(hdmi3, dummy, platform),
 426        },
 427
 428        /* Back End DAI links */
 429        {
 430                /* SSP0 - Codec */
 431                .name = "SSP0-Codec",
 432                .id = 0,
 433                .no_pcm = 1,
 434                .init = skylake_rt286_codec_init,
 435                .dai_fmt = SND_SOC_DAIFMT_I2S |
 436                        SND_SOC_DAIFMT_NB_NF |
 437                        SND_SOC_DAIFMT_CBS_CFS,
 438                .ignore_pmdown_time = 1,
 439                .be_hw_params_fixup = skylake_ssp0_fixup,
 440                .ops = &skylake_rt286_ops,
 441                .dpcm_playback = 1,
 442                .dpcm_capture = 1,
 443                SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
 444        },
 445        {
 446                .name = "dmic01",
 447                .id = 1,
 448                .be_hw_params_fixup = skylake_dmic_fixup,
 449                .ignore_suspend = 1,
 450                .dpcm_capture = 1,
 451                .no_pcm = 1,
 452                SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform),
 453        },
 454        {
 455                .name = "iDisp1",
 456                .id = 2,
 457                .init = skylake_hdmi_init,
 458                .dpcm_playback = 1,
 459                .no_pcm = 1,
 460                SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
 461        },
 462        {
 463                .name = "iDisp2",
 464                .id = 3,
 465                .init = skylake_hdmi_init,
 466                .dpcm_playback = 1,
 467                .no_pcm = 1,
 468                SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
 469        },
 470        {
 471                .name = "iDisp3",
 472                .id = 4,
 473                .init = skylake_hdmi_init,
 474                .dpcm_playback = 1,
 475                .no_pcm = 1,
 476                SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
 477        },
 478};
 479
 480#define NAME_SIZE       32
 481static int skylake_card_late_probe(struct snd_soc_card *card)
 482{
 483        struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card);
 484        struct skl_hdmi_pcm *pcm;
 485        struct snd_soc_component *component = NULL;
 486        int err, i = 0;
 487        char jack_name[NAME_SIZE];
 488
 489        list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
 490                component = pcm->codec_dai->component;
 491                snprintf(jack_name, sizeof(jack_name),
 492                        "HDMI/DP, pcm=%d Jack", pcm->device);
 493                err = snd_soc_card_jack_new(card, jack_name,
 494                                        SND_JACK_AVOUT, &skylake_hdmi[i],
 495                                        NULL, 0);
 496
 497                if (err)
 498                        return err;
 499
 500                err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
 501                                                &skylake_hdmi[i]);
 502                if (err < 0)
 503                        return err;
 504
 505                i++;
 506        }
 507
 508        if (!component)
 509                return -EINVAL;
 510
 511        return hdac_hdmi_jack_port_init(component, &card->dapm);
 512}
 513
 514/* skylake audio machine driver for SPT + RT286S */
 515static struct snd_soc_card skylake_rt286 = {
 516        .name = "skylake-rt286",
 517        .owner = THIS_MODULE,
 518        .dai_link = skylake_rt286_dais,
 519        .num_links = ARRAY_SIZE(skylake_rt286_dais),
 520        .controls = skylake_controls,
 521        .num_controls = ARRAY_SIZE(skylake_controls),
 522        .dapm_widgets = skylake_widgets,
 523        .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
 524        .dapm_routes = skylake_rt286_map,
 525        .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map),
 526        .fully_routed = true,
 527        .late_probe = skylake_card_late_probe,
 528};
 529
 530static int skylake_audio_probe(struct platform_device *pdev)
 531{
 532        struct skl_rt286_private *ctx;
 533
 534        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 535        if (!ctx)
 536                return -ENOMEM;
 537
 538        INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
 539
 540        skylake_rt286.dev = &pdev->dev;
 541        snd_soc_card_set_drvdata(&skylake_rt286, ctx);
 542
 543        return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286);
 544}
 545
 546static const struct platform_device_id skl_board_ids[] = {
 547        { .name = "skl_alc286s_i2s" },
 548        { .name = "kbl_alc286s_i2s" },
 549        { }
 550};
 551MODULE_DEVICE_TABLE(platform, skl_board_ids);
 552
 553static struct platform_driver skylake_audio = {
 554        .probe = skylake_audio_probe,
 555        .driver = {
 556                .name = "skl_alc286s_i2s",
 557                .pm = &snd_soc_pm_ops,
 558        },
 559        .id_table = skl_board_ids,
 560
 561};
 562
 563module_platform_driver(skylake_audio)
 564
 565/* Module information */
 566MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>");
 567MODULE_DESCRIPTION("Intel SST Audio for Skylake");
 568MODULE_LICENSE("GPL v2");
 569