linux/sound/soc/intel/boards/bxt_da7219_max98357a.c
<<
>>
Prefs
   1/*
   2 * Intel Broxton-P I2S Machine Driver
   3 *
   4 * Copyright (C) 2016, Intel Corporation. All rights reserved.
   5 *
   6 * Modified from:
   7 *   Intel Skylake I2S Machine driver
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License version
  11 * 2 as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/platform_device.h>
  21#include <sound/core.h>
  22#include <sound/jack.h>
  23#include <sound/pcm.h>
  24#include <sound/pcm_params.h>
  25#include <sound/soc.h>
  26#include "../../codecs/hdac_hdmi.h"
  27#include "../../codecs/da7219.h"
  28#include "../../codecs/da7219-aad.h"
  29
  30#define BXT_DIALOG_CODEC_DAI    "da7219-hifi"
  31#define BXT_MAXIM_CODEC_DAI     "HiFi"
  32#define DUAL_CHANNEL            2
  33
  34static struct snd_soc_jack broxton_headset;
  35
  36enum {
  37        BXT_DPCM_AUDIO_PB = 0,
  38        BXT_DPCM_AUDIO_CP,
  39        BXT_DPCM_AUDIO_REF_CP,
  40        BXT_DPCM_AUDIO_HDMI1_PB,
  41        BXT_DPCM_AUDIO_HDMI2_PB,
  42        BXT_DPCM_AUDIO_HDMI3_PB,
  43};
  44
  45static const struct snd_kcontrol_new broxton_controls[] = {
  46        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
  47        SOC_DAPM_PIN_SWITCH("Headset Mic"),
  48        SOC_DAPM_PIN_SWITCH("Spk"),
  49};
  50
  51static const struct snd_soc_dapm_widget broxton_widgets[] = {
  52        SND_SOC_DAPM_HP("Headphone Jack", NULL),
  53        SND_SOC_DAPM_MIC("Headset Mic", NULL),
  54        SND_SOC_DAPM_SPK("Spk", NULL),
  55        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
  56        SND_SOC_DAPM_SPK("HDMI1", NULL),
  57        SND_SOC_DAPM_SPK("HDMI2", NULL),
  58        SND_SOC_DAPM_SPK("HDMI3", NULL),
  59};
  60
  61static const struct snd_soc_dapm_route broxton_map[] = {
  62        /* HP jack connectors - unknown if we have jack detection */
  63        {"Headphone Jack", NULL, "HPL"},
  64        {"Headphone Jack", NULL, "HPR"},
  65
  66        /* speaker */
  67        {"Spk", NULL, "Speaker"},
  68
  69        /* other jacks */
  70        {"MIC", NULL, "Headset Mic"},
  71
  72        /* digital mics */
  73        {"DMic", NULL, "SoC DMIC"},
  74
  75        /* CODEC BE connections */
  76        {"HiFi Playback", NULL, "ssp5 Tx"},
  77        {"ssp5 Tx", NULL, "codec0_out"},
  78
  79        {"Playback", NULL, "ssp1 Tx"},
  80        {"ssp1 Tx", NULL, "codec1_out"},
  81
  82        {"codec0_in", NULL, "ssp1 Rx"},
  83        {"ssp1 Rx", NULL, "Capture"},
  84
  85        {"HDMI1", NULL, "hif5 Output"},
  86        {"HDMI2", NULL, "hif6 Output"},
  87        {"HDMI3", NULL, "hif7 Output"},
  88
  89        {"hifi3", NULL, "iDisp3 Tx"},
  90        {"iDisp3 Tx", NULL, "iDisp3_out"},
  91        {"hifi2", NULL, "iDisp2 Tx"},
  92        {"iDisp2 Tx", NULL, "iDisp2_out"},
  93        {"hifi1", NULL, "iDisp1 Tx"},
  94        {"iDisp1 Tx", NULL, "iDisp1_out"},
  95
  96        /* DMIC */
  97        {"dmic01_hifi", NULL, "DMIC01 Rx"},
  98        {"DMIC01 Rx", NULL, "DMIC AIF"},
  99};
 100
 101static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
 102                        struct snd_pcm_hw_params *params)
 103{
 104        struct snd_interval *rate = hw_param_interval(params,
 105                        SNDRV_PCM_HW_PARAM_RATE);
 106        struct snd_interval *channels = hw_param_interval(params,
 107                        SNDRV_PCM_HW_PARAM_CHANNELS);
 108        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 109
 110        /* The ADSP will convert the FE rate to 48k, stereo */
 111        rate->min = rate->max = 48000;
 112        channels->min = channels->max = DUAL_CHANNEL;
 113
 114        /* set SSP to 24 bit */
 115        snd_mask_none(fmt);
 116        snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
 117
 118        return 0;
 119}
 120
 121static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
 122{
 123        int ret;
 124        struct snd_soc_codec *codec = rtd->codec;
 125
 126        /*
 127         * Headset buttons map to the google Reference headset.
 128         * These can be configured by userspace.
 129         */
 130        ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
 131                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 132                        SND_JACK_BTN_2 | SND_JACK_BTN_3, &broxton_headset,
 133                        NULL, 0);
 134        if (ret) {
 135                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
 136                return ret;
 137        }
 138
 139        da7219_aad_jack_det(codec, &broxton_headset);
 140
 141        snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 142
 143        return ret;
 144}
 145
 146static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
 147{
 148        struct snd_soc_dai *dai = rtd->codec_dai;
 149
 150        return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
 151}
 152
 153static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
 154{
 155        struct snd_soc_dapm_context *dapm;
 156        struct snd_soc_component *component = rtd->cpu_dai->component;
 157
 158        dapm = snd_soc_component_get_dapm(component);
 159        snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
 160
 161        return 0;
 162}
 163
 164static unsigned int rates[] = {
 165        48000,
 166};
 167
 168static struct snd_pcm_hw_constraint_list constraints_rates = {
 169        .count = ARRAY_SIZE(rates),
 170        .list  = rates,
 171        .mask = 0,
 172};
 173
 174static unsigned int channels[] = {
 175        DUAL_CHANNEL,
 176};
 177
 178static struct snd_pcm_hw_constraint_list constraints_channels = {
 179        .count = ARRAY_SIZE(channels),
 180        .list = channels,
 181        .mask = 0,
 182};
 183
 184static int bxt_fe_startup(struct snd_pcm_substream *substream)
 185{
 186        struct snd_pcm_runtime *runtime = substream->runtime;
 187
 188        /*
 189         * On this platform for PCM device we support,
 190         * 48Khz
 191         * stereo
 192         * 16 bit audio
 193         */
 194
 195        runtime->hw.channels_max = DUAL_CHANNEL;
 196        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 197                                           &constraints_channels);
 198
 199        runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
 200        snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
 201
 202        snd_pcm_hw_constraint_list(runtime, 0,
 203                                SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 204
 205        return 0;
 206}
 207
 208static const struct snd_soc_ops broxton_da7219_fe_ops = {
 209        .startup = bxt_fe_startup,
 210};
 211
 212static int broxton_da7219_hw_params(struct snd_pcm_substream *substream,
 213                                struct snd_pcm_hw_params *params)
 214{
 215        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 216        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 217        int ret;
 218
 219        ret = snd_soc_dai_set_sysclk(codec_dai,
 220                        DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN);
 221        if (ret < 0)
 222                dev_err(codec_dai->dev, "can't set codec sysclk configuration\n");
 223
 224        ret = snd_soc_dai_set_pll(codec_dai, 0,
 225                        DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304);
 226        if (ret < 0) {
 227                dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret);
 228                return -EIO;
 229        }
 230
 231        return ret;
 232}
 233
 234static int broxton_da7219_hw_free(struct snd_pcm_substream *substream)
 235{
 236        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 237        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 238        int ret;
 239
 240        ret = snd_soc_dai_set_pll(codec_dai, 0,
 241                        DA7219_SYSCLK_MCLK, 0, 0);
 242        if (ret < 0) {
 243                dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret);
 244                return -EIO;
 245        }
 246
 247        return ret;
 248}
 249
 250static struct snd_soc_ops broxton_da7219_ops = {
 251        .hw_params = broxton_da7219_hw_params,
 252        .hw_free = broxton_da7219_hw_free,
 253};
 254
 255/* broxton digital audio interface glue - connects codec <--> CPU */
 256static struct snd_soc_dai_link broxton_dais[] = {
 257        /* Front End DAI links */
 258        [BXT_DPCM_AUDIO_PB]
 259        {
 260                .name = "Bxt Audio Port",
 261                .stream_name = "Audio",
 262                .cpu_dai_name = "System Pin",
 263                .platform_name = "0000:00:0e.0",
 264                .dynamic = 1,
 265                .codec_name = "snd-soc-dummy",
 266                .codec_dai_name = "snd-soc-dummy-dai",
 267                .nonatomic = 1,
 268                .init = broxton_da7219_fe_init,
 269                .trigger = {
 270                        SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
 271                .dpcm_playback = 1,
 272                .ops = &broxton_da7219_fe_ops,
 273        },
 274        [BXT_DPCM_AUDIO_CP]
 275        {
 276                .name = "Bxt Audio Capture Port",
 277                .stream_name = "Audio Record",
 278                .cpu_dai_name = "System Pin",
 279                .platform_name = "0000:00:0e.0",
 280                .dynamic = 1,
 281                .codec_name = "snd-soc-dummy",
 282                .codec_dai_name = "snd-soc-dummy-dai",
 283                .nonatomic = 1,
 284                .trigger = {
 285                        SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
 286                .dpcm_capture = 1,
 287                .ops = &broxton_da7219_fe_ops,
 288        },
 289        [BXT_DPCM_AUDIO_REF_CP]
 290        {
 291                .name = "Bxt Audio Reference cap",
 292                .stream_name = "Refcap",
 293                .cpu_dai_name = "Reference Pin",
 294                .codec_name = "snd-soc-dummy",
 295                .codec_dai_name = "snd-soc-dummy-dai",
 296                .platform_name = "0000:00:0e.0",
 297                .init = NULL,
 298                .dpcm_capture = 1,
 299                .ignore_suspend = 1,
 300                .nonatomic = 1,
 301                .dynamic = 1,
 302        },
 303        [BXT_DPCM_AUDIO_HDMI1_PB]
 304        {
 305                .name = "Bxt HDMI Port1",
 306                .stream_name = "Hdmi1",
 307                .cpu_dai_name = "HDMI1 Pin",
 308                .codec_name = "snd-soc-dummy",
 309                .codec_dai_name = "snd-soc-dummy-dai",
 310                .platform_name = "0000:00:0e.0",
 311                .dpcm_playback = 1,
 312                .init = NULL,
 313                .nonatomic = 1,
 314                .dynamic = 1,
 315        },
 316        [BXT_DPCM_AUDIO_HDMI2_PB]
 317        {
 318                .name = "Bxt HDMI Port2",
 319                .stream_name = "Hdmi2",
 320                .cpu_dai_name = "HDMI2 Pin",
 321                .codec_name = "snd-soc-dummy",
 322                .codec_dai_name = "snd-soc-dummy-dai",
 323                .platform_name = "0000:00:0e.0",
 324                .dpcm_playback = 1,
 325                .init = NULL,
 326                .nonatomic = 1,
 327                .dynamic = 1,
 328        },
 329        [BXT_DPCM_AUDIO_HDMI3_PB]
 330        {
 331                .name = "Bxt HDMI Port3",
 332                .stream_name = "Hdmi3",
 333                .cpu_dai_name = "HDMI3 Pin",
 334                .codec_name = "snd-soc-dummy",
 335                .codec_dai_name = "snd-soc-dummy-dai",
 336                .platform_name = "0000:00:0e.0",
 337                .dpcm_playback = 1,
 338                .init = NULL,
 339                .nonatomic = 1,
 340                .dynamic = 1,
 341        },
 342        /* Back End DAI links */
 343        {
 344                /* SSP5 - Codec */
 345                .name = "SSP5-Codec",
 346                .id = 0,
 347                .cpu_dai_name = "SSP5 Pin",
 348                .platform_name = "0000:00:0e.0",
 349                .no_pcm = 1,
 350                .codec_name = "MX98357A:00",
 351                .codec_dai_name = BXT_MAXIM_CODEC_DAI,
 352                .dai_fmt = SND_SOC_DAIFMT_I2S |
 353                        SND_SOC_DAIFMT_NB_NF |
 354                        SND_SOC_DAIFMT_CBS_CFS,
 355                .ignore_pmdown_time = 1,
 356                .be_hw_params_fixup = broxton_ssp_fixup,
 357                .dpcm_playback = 1,
 358        },
 359        {
 360                /* SSP1 - Codec */
 361                .name = "SSP1-Codec",
 362                .id = 1,
 363                .cpu_dai_name = "SSP1 Pin",
 364                .platform_name = "0000:00:0e.0",
 365                .no_pcm = 1,
 366                .codec_name = "i2c-DLGS7219:00",
 367                .codec_dai_name = BXT_DIALOG_CODEC_DAI,
 368                .init = broxton_da7219_codec_init,
 369                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 370                        SND_SOC_DAIFMT_CBS_CFS,
 371                .ignore_pmdown_time = 1,
 372                .be_hw_params_fixup = broxton_ssp_fixup,
 373                .ops = &broxton_da7219_ops,
 374                .dpcm_playback = 1,
 375                .dpcm_capture = 1,
 376        },
 377        {
 378                .name = "dmic01",
 379                .id = 2,
 380                .cpu_dai_name = "DMIC01 Pin",
 381                .codec_name = "dmic-codec",
 382                .codec_dai_name = "dmic-hifi",
 383                .platform_name = "0000:00:0e.0",
 384                .ignore_suspend = 1,
 385                .dpcm_capture = 1,
 386                .no_pcm = 1,
 387        },
 388        {
 389                .name = "iDisp1",
 390                .id = 3,
 391                .cpu_dai_name = "iDisp1 Pin",
 392                .codec_name = "ehdaudio0D2",
 393                .codec_dai_name = "intel-hdmi-hifi1",
 394                .platform_name = "0000:00:0e.0",
 395                .init = broxton_hdmi_init,
 396                .dpcm_playback = 1,
 397                .no_pcm = 1,
 398        },
 399        {
 400                .name = "iDisp2",
 401                .id = 4,
 402                .cpu_dai_name = "iDisp2 Pin",
 403                .codec_name = "ehdaudio0D2",
 404                .codec_dai_name = "intel-hdmi-hifi2",
 405                .platform_name = "0000:00:0e.0",
 406                .init = broxton_hdmi_init,
 407                .dpcm_playback = 1,
 408                .no_pcm = 1,
 409        },
 410        {
 411                .name = "iDisp3",
 412                .id = 5,
 413                .cpu_dai_name = "iDisp3 Pin",
 414                .codec_name = "ehdaudio0D2",
 415                .codec_dai_name = "intel-hdmi-hifi3",
 416                .platform_name = "0000:00:0e.0",
 417                .init = broxton_hdmi_init,
 418                .dpcm_playback = 1,
 419                .no_pcm = 1,
 420        },
 421};
 422
 423/* broxton audio machine driver for SPT + da7219 */
 424static struct snd_soc_card broxton_audio_card = {
 425        .name = "bxtda7219max",
 426        .owner = THIS_MODULE,
 427        .dai_link = broxton_dais,
 428        .num_links = ARRAY_SIZE(broxton_dais),
 429        .controls = broxton_controls,
 430        .num_controls = ARRAY_SIZE(broxton_controls),
 431        .dapm_widgets = broxton_widgets,
 432        .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
 433        .dapm_routes = broxton_map,
 434        .num_dapm_routes = ARRAY_SIZE(broxton_map),
 435        .fully_routed = true,
 436};
 437
 438static int broxton_audio_probe(struct platform_device *pdev)
 439{
 440        broxton_audio_card.dev = &pdev->dev;
 441        return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card);
 442}
 443
 444static struct platform_driver broxton_audio = {
 445        .probe = broxton_audio_probe,
 446        .driver = {
 447                .name = "bxt_da7219_max98357a_i2s",
 448                .pm = &snd_soc_pm_ops,
 449        },
 450};
 451module_platform_driver(broxton_audio)
 452
 453/* Module information */
 454MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode");
 455MODULE_AUTHOR("Sathyanarayana Nujella <sathyanarayana.nujella@intel.com>");
 456MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>");
 457MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
 458MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
 459MODULE_LICENSE("GPL v2");
 460MODULE_ALIAS("platform:bxt_da7219_max98357a_i2s");
 461