1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright(c) 2019 Intel Corporation. 3 4 /* 5 * Intel SOF Machine Driver with Realtek rt5682 Codec 6 * and speaker codec MAX98357A 7 */ 8 #include <linux/i2c.h> 9 #include <linux/input.h> 10 #include <linux/module.h> 11 #include <linux/platform_device.h> 12 #include <linux/clk.h> 13 #include <linux/dmi.h> 14 #include <sound/core.h> 15 #include <sound/jack.h> 16 #include <sound/pcm.h> 17 #include <sound/pcm_params.h> 18 #include <sound/soc.h> 19 #include <sound/rt5682.h> 20 #include <sound/soc-acpi.h> 21 #include "../../codecs/rt5682.h" 22 #include "../../codecs/hdac_hdmi.h" 23 #include "../common/soc-intel-quirks.h" 24 25 #define NAME_SIZE 32 26 27 #define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) 28 #define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0)) 29 #define SOF_RT5682_MCLK_EN BIT(3) 30 #define SOF_RT5682_MCLK_24MHZ BIT(4) 31 #define SOF_SPEAKER_AMP_PRESENT BIT(5) 32 #define SOF_RT5682_SSP_AMP_SHIFT 6 33 #define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) 34 #define SOF_RT5682_SSP_AMP(quirk) \ 35 (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) 36 #define SOF_RT5682_MCLK_BYTCHT_EN BIT(9) 37 38 /* Default: MCLK on, MCLK 19.2M, SSP0 */ 39 static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | 40 SOF_RT5682_SSP_CODEC(0); 41 42 static int is_legacy_cpu; 43 44 static struct snd_soc_jack sof_hdmi[3]; 45 46 struct sof_hdmi_pcm { 47 struct list_head head; 48 struct snd_soc_dai *codec_dai; 49 int device; 50 }; 51 52 struct sof_card_private { 53 struct clk *mclk; 54 struct snd_soc_jack sof_headset; 55 struct list_head hdmi_pcm_list; 56 }; 57 58 static int sof_rt5682_quirk_cb(const struct dmi_system_id *id) 59 { 60 sof_rt5682_quirk = (unsigned long)id->driver_data; 61 return 1; 62 } 63 64 static const struct dmi_system_id sof_rt5682_quirk_table[] = { 65 { 66 .callback = sof_rt5682_quirk_cb, 67 .matches = { 68 DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), 69 DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"), 70 }, 71 .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), 72 }, 73 { 74 .callback = sof_rt5682_quirk_cb, 75 .matches = { 76 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 77 DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"), 78 }, 79 .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), 80 }, 81 { 82 .callback = sof_rt5682_quirk_cb, 83 .matches = { 84 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 85 DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"), 86 }, 87 .driver_data = (void *)(SOF_RT5682_MCLK_EN | 88 SOF_RT5682_MCLK_24MHZ | 89 SOF_RT5682_SSP_CODEC(1)), 90 }, 91 { 92 .callback = sof_rt5682_quirk_cb, 93 .matches = { 94 DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"), 95 }, 96 .driver_data = (void *)(SOF_RT5682_MCLK_EN | 97 SOF_RT5682_MCLK_24MHZ | 98 SOF_RT5682_SSP_CODEC(0) | 99 SOF_SPEAKER_AMP_PRESENT | 100 SOF_RT5682_SSP_AMP(1)), 101 }, 102 { 103 .callback = sof_rt5682_quirk_cb, 104 .matches = { 105 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 106 DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), 107 }, 108 .driver_data = (void *)(SOF_RT5682_MCLK_EN | 109 SOF_RT5682_SSP_CODEC(0)), 110 }, 111 {} 112 }; 113 114 static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) 115 { 116 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 117 struct snd_soc_dai *dai = rtd->codec_dai; 118 struct sof_hdmi_pcm *pcm; 119 120 pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); 121 if (!pcm) 122 return -ENOMEM; 123 124 /* dai_link id is 1:1 mapped to the PCM device */ 125 pcm->device = rtd->dai_link->id; 126 pcm->codec_dai = dai; 127 128 list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); 129 130 return 0; 131 } 132 133 static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) 134 { 135 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 136 struct snd_soc_component *component = rtd->codec_dai->component; 137 struct snd_soc_jack *jack; 138 int ret; 139 140 /* need to enable ASRC function for 24MHz mclk rate */ 141 if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) && 142 (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) { 143 rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | 144 RT5682_AD_STEREO1_FILTER, 145 RT5682_CLK_SEL_I2S1_ASRC); 146 } 147 148 if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { 149 /* 150 * The firmware might enable the clock at 151 * boot (this information may or may not 152 * be reflected in the enable clock register). 153 * To change the rate we must disable the clock 154 * first to cover these cases. Due to common 155 * clock framework restrictions that do not allow 156 * to disable a clock that has not been enabled, 157 * we need to enable the clock first. 158 */ 159 ret = clk_prepare_enable(ctx->mclk); 160 if (!ret) 161 clk_disable_unprepare(ctx->mclk); 162 163 ret = clk_set_rate(ctx->mclk, 19200000); 164 165 if (ret) 166 dev_err(rtd->dev, "unable to set MCLK rate\n"); 167 } 168 169 /* 170 * Headset buttons map to the google Reference headset. 171 * These can be configured by userspace. 172 */ 173 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", 174 SND_JACK_HEADSET | SND_JACK_BTN_0 | 175 SND_JACK_BTN_1 | SND_JACK_BTN_2 | 176 SND_JACK_BTN_3, 177 &ctx->sof_headset, NULL, 0); 178 if (ret) { 179 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); 180 return ret; 181 } 182 183 jack = &ctx->sof_headset; 184 185 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 186 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 187 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 188 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 189 ret = snd_soc_component_set_jack(component, jack, NULL); 190 191 if (ret) { 192 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); 193 return ret; 194 } 195 196 return ret; 197 }; 198 199 static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, 200 struct snd_pcm_hw_params *params) 201 { 202 struct snd_soc_pcm_runtime *rtd = substream->private_data; 203 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 204 struct snd_soc_dai *codec_dai = rtd->codec_dai; 205 int clk_id, clk_freq, pll_out, ret; 206 207 if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { 208 if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { 209 ret = clk_prepare_enable(ctx->mclk); 210 if (ret < 0) { 211 dev_err(rtd->dev, 212 "could not configure MCLK state"); 213 return ret; 214 } 215 } 216 217 clk_id = RT5682_PLL1_S_MCLK; 218 if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) 219 clk_freq = 24000000; 220 else 221 clk_freq = 19200000; 222 } else { 223 clk_id = RT5682_PLL1_S_BCLK1; 224 clk_freq = params_rate(params) * 50; 225 } 226 227 pll_out = params_rate(params) * 512; 228 229 ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); 230 if (ret < 0) 231 dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); 232 233 /* Configure sysclk for codec */ 234 ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, 235 pll_out, SND_SOC_CLOCK_IN); 236 if (ret < 0) 237 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); 238 239 /* 240 * slot_width should equal or large than data length, set them 241 * be the same 242 */ 243 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, 244 params_width(params)); 245 if (ret < 0) { 246 dev_err(rtd->dev, "set TDM slot err:%d\n", ret); 247 return ret; 248 } 249 250 return ret; 251 } 252 253 static struct snd_soc_ops sof_rt5682_ops = { 254 .hw_params = sof_rt5682_hw_params, 255 }; 256 257 static struct snd_soc_dai_link_component platform_component[] = { 258 { 259 /* name might be overridden during probe */ 260 .name = "0000:00:1f.3" 261 } 262 }; 263 264 static int sof_card_late_probe(struct snd_soc_card *card) 265 { 266 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); 267 struct snd_soc_component *component = NULL; 268 char jack_name[NAME_SIZE]; 269 struct sof_hdmi_pcm *pcm; 270 int err = 0; 271 int i = 0; 272 273 /* HDMI is not supported by SOF on Baytrail/CherryTrail */ 274 if (is_legacy_cpu) 275 return 0; 276 277 list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { 278 component = pcm->codec_dai->component; 279 snprintf(jack_name, sizeof(jack_name), 280 "HDMI/DP, pcm=%d Jack", pcm->device); 281 err = snd_soc_card_jack_new(card, jack_name, 282 SND_JACK_AVOUT, &sof_hdmi[i], 283 NULL, 0); 284 285 if (err) 286 return err; 287 288 err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, 289 &sof_hdmi[i]); 290 if (err < 0) 291 return err; 292 293 i++; 294 } 295 if (!component) 296 return -EINVAL; 297 298 return hdac_hdmi_jack_port_init(component, &card->dapm); 299 } 300 301 static const struct snd_kcontrol_new sof_controls[] = { 302 SOC_DAPM_PIN_SWITCH("Headphone Jack"), 303 SOC_DAPM_PIN_SWITCH("Headset Mic"), 304 SOC_DAPM_PIN_SWITCH("Spk"), 305 }; 306 307 static const struct snd_soc_dapm_widget sof_widgets[] = { 308 SND_SOC_DAPM_HP("Headphone Jack", NULL), 309 SND_SOC_DAPM_MIC("Headset Mic", NULL), 310 SND_SOC_DAPM_SPK("Spk", NULL), 311 }; 312 313 static const struct snd_soc_dapm_widget dmic_widgets[] = { 314 SND_SOC_DAPM_MIC("SoC DMIC", NULL), 315 }; 316 317 static const struct snd_soc_dapm_route sof_map[] = { 318 /* HP jack connectors - unknown if we have jack detection */ 319 { "Headphone Jack", NULL, "HPOL" }, 320 { "Headphone Jack", NULL, "HPOR" }, 321 322 /* other jacks */ 323 { "IN1P", NULL, "Headset Mic" }, 324 }; 325 326 static const struct snd_soc_dapm_route speaker_map[] = { 327 /* speaker */ 328 { "Spk", NULL, "Speaker" }, 329 }; 330 331 static const struct snd_soc_dapm_route dmic_map[] = { 332 /* digital mics */ 333 {"DMic", NULL, "SoC DMIC"}, 334 }; 335 336 static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) 337 { 338 struct snd_soc_card *card = rtd->card; 339 int ret; 340 341 ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map, 342 ARRAY_SIZE(speaker_map)); 343 344 if (ret) 345 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); 346 return ret; 347 } 348 349 static int dmic_init(struct snd_soc_pcm_runtime *rtd) 350 { 351 struct snd_soc_card *card = rtd->card; 352 int ret; 353 354 ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, 355 ARRAY_SIZE(dmic_widgets)); 356 if (ret) { 357 dev_err(card->dev, "DMic widget addition failed: %d\n", ret); 358 /* Don't need to add routes if widget addition failed */ 359 return ret; 360 } 361 362 ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, 363 ARRAY_SIZE(dmic_map)); 364 365 if (ret) 366 dev_err(card->dev, "DMic map addition failed: %d\n", ret); 367 368 return ret; 369 } 370 371 /* sof audio machine driver for rt5682 codec */ 372 static struct snd_soc_card sof_audio_card_rt5682 = { 373 .name = "sof_rt5682", 374 .owner = THIS_MODULE, 375 .controls = sof_controls, 376 .num_controls = ARRAY_SIZE(sof_controls), 377 .dapm_widgets = sof_widgets, 378 .num_dapm_widgets = ARRAY_SIZE(sof_widgets), 379 .dapm_routes = sof_map, 380 .num_dapm_routes = ARRAY_SIZE(sof_map), 381 .fully_routed = true, 382 .late_probe = sof_card_late_probe, 383 }; 384 385 static struct snd_soc_dai_link_component rt5682_component[] = { 386 { 387 .name = "i2c-10EC5682:00", 388 .dai_name = "rt5682-aif1", 389 } 390 }; 391 392 static struct snd_soc_dai_link_component dmic_component[] = { 393 { 394 .name = "dmic-codec", 395 .dai_name = "dmic-hifi", 396 } 397 }; 398 399 static struct snd_soc_dai_link_component max98357a_component[] = { 400 { 401 .name = "MX98357A:00", 402 .dai_name = "HiFi", 403 } 404 }; 405 406 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, 407 int ssp_codec, 408 int ssp_amp, 409 int dmic_be_num, 410 int hdmi_num) 411 { 412 struct snd_soc_dai_link_component *idisp_components; 413 struct snd_soc_dai_link_component *cpus; 414 struct snd_soc_dai_link *links; 415 int i, id = 0; 416 417 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * 418 sof_audio_card_rt5682.num_links, GFP_KERNEL); 419 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * 420 sof_audio_card_rt5682.num_links, GFP_KERNEL); 421 if (!links || !cpus) 422 goto devm_err; 423 424 /* codec SSP */ 425 links[id].name = devm_kasprintf(dev, GFP_KERNEL, 426 "SSP%d-Codec", ssp_codec); 427 if (!links[id].name) 428 goto devm_err; 429 430 links[id].id = id; 431 links[id].codecs = rt5682_component; 432 links[id].num_codecs = ARRAY_SIZE(rt5682_component); 433 links[id].platforms = platform_component; 434 links[id].num_platforms = ARRAY_SIZE(platform_component); 435 links[id].init = sof_rt5682_codec_init; 436 links[id].ops = &sof_rt5682_ops; 437 links[id].nonatomic = true; 438 links[id].dpcm_playback = 1; 439 links[id].dpcm_capture = 1; 440 links[id].no_pcm = 1; 441 links[id].cpus = &cpus[id]; 442 links[id].num_cpus = 1; 443 if (is_legacy_cpu) { 444 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 445 "ssp%d-port", 446 ssp_codec); 447 if (!links[id].cpus->dai_name) 448 goto devm_err; 449 } else { 450 /* 451 * Currently, On SKL+ platforms MCLK will be turned off in sof 452 * runtime suspended, and it will go into runtime suspended 453 * right after playback is stop. However, rt5682 will output 454 * static noise if sysclk turns off during playback. Set 455 * ignore_pmdown_time to power down rt5682 immediately and 456 * avoid the noise. 457 * It can be removed once we can control MCLK by driver. 458 */ 459 links[id].ignore_pmdown_time = 1; 460 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 461 "SSP%d Pin", 462 ssp_codec); 463 if (!links[id].cpus->dai_name) 464 goto devm_err; 465 } 466 id++; 467 468 /* dmic */ 469 if (dmic_be_num > 0) { 470 /* at least we have dmic01 */ 471 links[id].name = "dmic01"; 472 links[id].cpus = &cpus[id]; 473 links[id].cpus->dai_name = "DMIC01 Pin"; 474 links[id].init = dmic_init; 475 if (dmic_be_num > 1) { 476 /* set up 2 BE links at most */ 477 links[id + 1].name = "dmic16k"; 478 links[id + 1].cpus = &cpus[id + 1]; 479 links[id + 1].cpus->dai_name = "DMIC16k Pin"; 480 dmic_be_num = 2; 481 } 482 } 483 484 for (i = 0; i < dmic_be_num; i++) { 485 links[id].id = id; 486 links[id].num_cpus = 1; 487 links[id].codecs = dmic_component; 488 links[id].num_codecs = ARRAY_SIZE(dmic_component); 489 links[id].platforms = platform_component; 490 links[id].num_platforms = ARRAY_SIZE(platform_component); 491 links[id].ignore_suspend = 1; 492 links[id].dpcm_capture = 1; 493 links[id].no_pcm = 1; 494 id++; 495 } 496 497 /* HDMI */ 498 if (hdmi_num > 0) { 499 idisp_components = devm_kzalloc(dev, 500 sizeof(struct snd_soc_dai_link_component) * 501 hdmi_num, GFP_KERNEL); 502 if (!idisp_components) 503 goto devm_err; 504 } 505 for (i = 1; i <= hdmi_num; i++) { 506 links[id].name = devm_kasprintf(dev, GFP_KERNEL, 507 "iDisp%d", i); 508 if (!links[id].name) 509 goto devm_err; 510 511 links[id].id = id; 512 links[id].cpus = &cpus[id]; 513 links[id].num_cpus = 1; 514 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 515 "iDisp%d Pin", i); 516 if (!links[id].cpus->dai_name) 517 goto devm_err; 518 519 idisp_components[i - 1].name = "ehdaudio0D2"; 520 idisp_components[i - 1].dai_name = devm_kasprintf(dev, 521 GFP_KERNEL, 522 "intel-hdmi-hifi%d", 523 i); 524 if (!idisp_components[i - 1].dai_name) 525 goto devm_err; 526 527 links[id].codecs = &idisp_components[i - 1]; 528 links[id].num_codecs = 1; 529 links[id].platforms = platform_component; 530 links[id].num_platforms = ARRAY_SIZE(platform_component); 531 links[id].init = sof_hdmi_init; 532 links[id].dpcm_playback = 1; 533 links[id].no_pcm = 1; 534 id++; 535 } 536 537 /* speaker amp */ 538 if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) { 539 links[id].name = devm_kasprintf(dev, GFP_KERNEL, 540 "SSP%d-Codec", ssp_amp); 541 if (!links[id].name) 542 goto devm_err; 543 544 links[id].id = id; 545 links[id].codecs = max98357a_component; 546 links[id].num_codecs = ARRAY_SIZE(max98357a_component); 547 links[id].platforms = platform_component; 548 links[id].num_platforms = ARRAY_SIZE(platform_component); 549 links[id].init = speaker_codec_init, 550 links[id].nonatomic = true; 551 links[id].dpcm_playback = 1; 552 links[id].no_pcm = 1; 553 links[id].cpus = &cpus[id]; 554 links[id].num_cpus = 1; 555 if (is_legacy_cpu) { 556 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 557 "ssp%d-port", 558 ssp_amp); 559 if (!links[id].cpus->dai_name) 560 goto devm_err; 561 562 } else { 563 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 564 "SSP%d Pin", 565 ssp_amp); 566 if (!links[id].cpus->dai_name) 567 goto devm_err; 568 } 569 } 570 571 return links; 572 devm_err: 573 return NULL; 574 } 575 576 static int sof_audio_probe(struct platform_device *pdev) 577 { 578 struct snd_soc_dai_link *dai_links; 579 struct snd_soc_acpi_mach *mach; 580 struct sof_card_private *ctx; 581 int dmic_be_num, hdmi_num; 582 int ret, ssp_amp, ssp_codec; 583 584 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 585 if (!ctx) 586 return -ENOMEM; 587 588 if (soc_intel_is_byt() || soc_intel_is_cht()) { 589 is_legacy_cpu = 1; 590 dmic_be_num = 0; 591 hdmi_num = 0; 592 /* default quirk for legacy cpu */ 593 sof_rt5682_quirk = SOF_RT5682_MCLK_EN | 594 SOF_RT5682_MCLK_BYTCHT_EN | 595 SOF_RT5682_SSP_CODEC(2); 596 } else { 597 dmic_be_num = 2; 598 hdmi_num = 3; 599 } 600 601 dmi_check_system(sof_rt5682_quirk_table); 602 603 /* need to get main clock from pmc */ 604 if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { 605 ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); 606 if (IS_ERR(ctx->mclk)) { 607 ret = PTR_ERR(ctx->mclk); 608 609 dev_err(&pdev->dev, 610 "Failed to get MCLK from pmc_plt_clk_3: %d\n", 611 ret); 612 return ret; 613 } 614 615 ret = clk_prepare_enable(ctx->mclk); 616 if (ret < 0) { 617 dev_err(&pdev->dev, 618 "could not configure MCLK state"); 619 return ret; 620 } 621 } 622 623 dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); 624 625 ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> 626 SOF_RT5682_SSP_AMP_SHIFT; 627 628 ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; 629 630 /* compute number of dai links */ 631 sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num; 632 633 if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) 634 sof_audio_card_rt5682.num_links++; 635 636 dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, 637 dmic_be_num, hdmi_num); 638 if (!dai_links) 639 return -ENOMEM; 640 641 sof_audio_card_rt5682.dai_link = dai_links; 642 643 INIT_LIST_HEAD(&ctx->hdmi_pcm_list); 644 645 sof_audio_card_rt5682.dev = &pdev->dev; 646 mach = (&pdev->dev)->platform_data; 647 648 /* set platform name for each dailink */ 649 ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682, 650 mach->mach_params.platform); 651 if (ret) 652 return ret; 653 654 snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx); 655 656 return devm_snd_soc_register_card(&pdev->dev, 657 &sof_audio_card_rt5682); 658 } 659 660 static int sof_rt5682_remove(struct platform_device *pdev) 661 { 662 struct snd_soc_card *card = platform_get_drvdata(pdev); 663 struct snd_soc_component *component = NULL; 664 665 for_each_card_components(card, component) { 666 if (!strcmp(component->name, rt5682_component[0].name)) { 667 snd_soc_component_set_jack(component, NULL, NULL); 668 break; 669 } 670 } 671 672 return 0; 673 } 674 675 static struct platform_driver sof_audio = { 676 .probe = sof_audio_probe, 677 .remove = sof_rt5682_remove, 678 .driver = { 679 .name = "sof_rt5682", 680 .pm = &snd_soc_pm_ops, 681 }, 682 }; 683 module_platform_driver(sof_audio) 684 685 /* Module information */ 686 MODULE_DESCRIPTION("SOF Audio Machine driver"); 687 MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>"); 688 MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); 689 MODULE_LICENSE("GPL v2"); 690 MODULE_ALIAS("platform:sof_rt5682"); 691