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 SND_SOC_DAPM_MIC("SoC DMIC", NULL), 312 }; 313 314 static const struct snd_soc_dapm_route sof_map[] = { 315 /* HP jack connectors - unknown if we have jack detection */ 316 { "Headphone Jack", NULL, "HPOL" }, 317 { "Headphone Jack", NULL, "HPOR" }, 318 319 /* other jacks */ 320 { "IN1P", NULL, "Headset Mic" }, 321 322 /* digital mics */ 323 {"DMic", NULL, "SoC DMIC"}, 324 325 }; 326 327 static const struct snd_soc_dapm_route speaker_map[] = { 328 /* speaker */ 329 { "Spk", NULL, "Speaker" }, 330 }; 331 332 static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) 333 { 334 struct snd_soc_card *card = rtd->card; 335 int ret; 336 337 ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map, 338 ARRAY_SIZE(speaker_map)); 339 340 if (ret) 341 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); 342 return ret; 343 } 344 345 /* sof audio machine driver for rt5682 codec */ 346 static struct snd_soc_card sof_audio_card_rt5682 = { 347 .name = "sof_rt5682", 348 .owner = THIS_MODULE, 349 .controls = sof_controls, 350 .num_controls = ARRAY_SIZE(sof_controls), 351 .dapm_widgets = sof_widgets, 352 .num_dapm_widgets = ARRAY_SIZE(sof_widgets), 353 .dapm_routes = sof_map, 354 .num_dapm_routes = ARRAY_SIZE(sof_map), 355 .fully_routed = true, 356 .late_probe = sof_card_late_probe, 357 }; 358 359 static struct snd_soc_dai_link_component rt5682_component[] = { 360 { 361 .name = "i2c-10EC5682:00", 362 .dai_name = "rt5682-aif1", 363 } 364 }; 365 366 static struct snd_soc_dai_link_component dmic_component[] = { 367 { 368 .name = "dmic-codec", 369 .dai_name = "dmic-hifi", 370 } 371 }; 372 373 static struct snd_soc_dai_link_component max98357a_component[] = { 374 { 375 .name = "MX98357A:00", 376 .dai_name = "HiFi", 377 } 378 }; 379 380 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, 381 int ssp_codec, 382 int ssp_amp, 383 int dmic_be_num, 384 int hdmi_num) 385 { 386 struct snd_soc_dai_link_component *idisp_components; 387 struct snd_soc_dai_link_component *cpus; 388 struct snd_soc_dai_link *links; 389 int i, id = 0; 390 391 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * 392 sof_audio_card_rt5682.num_links, GFP_KERNEL); 393 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * 394 sof_audio_card_rt5682.num_links, GFP_KERNEL); 395 if (!links || !cpus) 396 goto devm_err; 397 398 /* codec SSP */ 399 links[id].name = devm_kasprintf(dev, GFP_KERNEL, 400 "SSP%d-Codec", ssp_codec); 401 if (!links[id].name) 402 goto devm_err; 403 404 links[id].id = id; 405 links[id].codecs = rt5682_component; 406 links[id].num_codecs = ARRAY_SIZE(rt5682_component); 407 links[id].platforms = platform_component; 408 links[id].num_platforms = ARRAY_SIZE(platform_component); 409 links[id].init = sof_rt5682_codec_init; 410 links[id].ops = &sof_rt5682_ops; 411 links[id].nonatomic = true; 412 links[id].dpcm_playback = 1; 413 links[id].dpcm_capture = 1; 414 links[id].no_pcm = 1; 415 links[id].cpus = &cpus[id]; 416 links[id].num_cpus = 1; 417 if (is_legacy_cpu) { 418 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 419 "ssp%d-port", 420 ssp_codec); 421 if (!links[id].cpus->dai_name) 422 goto devm_err; 423 } else { 424 /* 425 * Currently, On SKL+ platforms MCLK will be turned off in sof 426 * runtime suspended, and it will go into runtime suspended 427 * right after playback is stop. However, rt5682 will output 428 * static noise if sysclk turns off during playback. Set 429 * ignore_pmdown_time to power down rt5682 immediately and 430 * avoid the noise. 431 * It can be removed once we can control MCLK by driver. 432 */ 433 links[id].ignore_pmdown_time = 1; 434 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 435 "SSP%d Pin", 436 ssp_codec); 437 if (!links[id].cpus->dai_name) 438 goto devm_err; 439 } 440 id++; 441 442 /* dmic */ 443 if (dmic_be_num > 0) { 444 /* at least we have dmic01 */ 445 links[id].name = "dmic01"; 446 links[id].cpus = &cpus[id]; 447 links[id].cpus->dai_name = "DMIC01 Pin"; 448 if (dmic_be_num > 1) { 449 /* set up 2 BE links at most */ 450 links[id + 1].name = "dmic16k"; 451 links[id + 1].cpus = &cpus[id + 1]; 452 links[id + 1].cpus->dai_name = "DMIC16k Pin"; 453 dmic_be_num = 2; 454 } 455 } 456 457 for (i = 0; i < dmic_be_num; i++) { 458 links[id].id = id; 459 links[id].num_cpus = 1; 460 links[id].codecs = dmic_component; 461 links[id].num_codecs = ARRAY_SIZE(dmic_component); 462 links[id].platforms = platform_component; 463 links[id].num_platforms = ARRAY_SIZE(platform_component); 464 links[id].ignore_suspend = 1; 465 links[id].dpcm_capture = 1; 466 links[id].no_pcm = 1; 467 id++; 468 } 469 470 /* HDMI */ 471 if (hdmi_num > 0) { 472 idisp_components = devm_kzalloc(dev, 473 sizeof(struct snd_soc_dai_link_component) * 474 hdmi_num, GFP_KERNEL); 475 if (!idisp_components) 476 goto devm_err; 477 } 478 for (i = 1; i <= hdmi_num; i++) { 479 links[id].name = devm_kasprintf(dev, GFP_KERNEL, 480 "iDisp%d", i); 481 if (!links[id].name) 482 goto devm_err; 483 484 links[id].id = id; 485 links[id].cpus = &cpus[id]; 486 links[id].num_cpus = 1; 487 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 488 "iDisp%d Pin", i); 489 if (!links[id].cpus->dai_name) 490 goto devm_err; 491 492 idisp_components[i - 1].name = "ehdaudio0D2"; 493 idisp_components[i - 1].dai_name = devm_kasprintf(dev, 494 GFP_KERNEL, 495 "intel-hdmi-hifi%d", 496 i); 497 if (!idisp_components[i - 1].dai_name) 498 goto devm_err; 499 500 links[id].codecs = &idisp_components[i - 1]; 501 links[id].num_codecs = 1; 502 links[id].platforms = platform_component; 503 links[id].num_platforms = ARRAY_SIZE(platform_component); 504 links[id].init = sof_hdmi_init; 505 links[id].dpcm_playback = 1; 506 links[id].no_pcm = 1; 507 id++; 508 } 509 510 /* speaker amp */ 511 if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) { 512 links[id].name = devm_kasprintf(dev, GFP_KERNEL, 513 "SSP%d-Codec", ssp_amp); 514 if (!links[id].name) 515 goto devm_err; 516 517 links[id].id = id; 518 links[id].codecs = max98357a_component; 519 links[id].num_codecs = ARRAY_SIZE(max98357a_component); 520 links[id].platforms = platform_component; 521 links[id].num_platforms = ARRAY_SIZE(platform_component); 522 links[id].init = speaker_codec_init, 523 links[id].nonatomic = true; 524 links[id].dpcm_playback = 1; 525 links[id].no_pcm = 1; 526 links[id].cpus = &cpus[id]; 527 links[id].num_cpus = 1; 528 if (is_legacy_cpu) { 529 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 530 "ssp%d-port", 531 ssp_amp); 532 if (!links[id].cpus->dai_name) 533 goto devm_err; 534 535 } else { 536 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 537 "SSP%d Pin", 538 ssp_amp); 539 if (!links[id].cpus->dai_name) 540 goto devm_err; 541 } 542 } 543 544 return links; 545 devm_err: 546 return NULL; 547 } 548 549 static int sof_audio_probe(struct platform_device *pdev) 550 { 551 struct snd_soc_dai_link *dai_links; 552 struct snd_soc_acpi_mach *mach; 553 struct sof_card_private *ctx; 554 int dmic_be_num, hdmi_num; 555 int ret, ssp_amp, ssp_codec; 556 557 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 558 if (!ctx) 559 return -ENOMEM; 560 561 if (soc_intel_is_byt() || soc_intel_is_cht()) { 562 is_legacy_cpu = 1; 563 dmic_be_num = 0; 564 hdmi_num = 0; 565 /* default quirk for legacy cpu */ 566 sof_rt5682_quirk = SOF_RT5682_MCLK_EN | 567 SOF_RT5682_MCLK_BYTCHT_EN | 568 SOF_RT5682_SSP_CODEC(2); 569 } else { 570 dmic_be_num = 2; 571 hdmi_num = 3; 572 } 573 574 dmi_check_system(sof_rt5682_quirk_table); 575 576 /* need to get main clock from pmc */ 577 if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { 578 ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); 579 ret = clk_prepare_enable(ctx->mclk); 580 if (ret < 0) { 581 dev_err(&pdev->dev, 582 "could not configure MCLK state"); 583 return ret; 584 } 585 } 586 587 dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); 588 589 ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> 590 SOF_RT5682_SSP_AMP_SHIFT; 591 592 ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; 593 594 /* compute number of dai links */ 595 sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num; 596 597 if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) 598 sof_audio_card_rt5682.num_links++; 599 600 dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, 601 dmic_be_num, hdmi_num); 602 if (!dai_links) 603 return -ENOMEM; 604 605 sof_audio_card_rt5682.dai_link = dai_links; 606 607 INIT_LIST_HEAD(&ctx->hdmi_pcm_list); 608 609 sof_audio_card_rt5682.dev = &pdev->dev; 610 mach = (&pdev->dev)->platform_data; 611 612 /* set platform name for each dailink */ 613 ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682, 614 mach->mach_params.platform); 615 if (ret) 616 return ret; 617 618 snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx); 619 620 return devm_snd_soc_register_card(&pdev->dev, 621 &sof_audio_card_rt5682); 622 } 623 624 static struct platform_driver sof_audio = { 625 .probe = sof_audio_probe, 626 .driver = { 627 .name = "sof_rt5682", 628 .pm = &snd_soc_pm_ops, 629 }, 630 }; 631 module_platform_driver(sof_audio) 632 633 /* Module information */ 634 MODULE_DESCRIPTION("SOF Audio Machine driver"); 635 MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>"); 636 MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); 637 MODULE_LICENSE("GPL v2"); 638 MODULE_ALIAS("platform:sof_rt5682"); 639