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