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