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