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