1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright (c) 2020 Intel Corporation 3 4 /* 5 * sof_sdw - ASOC Machine driver for Intel SoundWire platforms 6 */ 7 8 #include <linux/acpi.h> 9 #include <linux/bitmap.h> 10 #include <linux/device.h> 11 #include <linux/dmi.h> 12 #include <linux/module.h> 13 #include <linux/soundwire/sdw.h> 14 #include <linux/soundwire/sdw_type.h> 15 #include <linux/soundwire/sdw_intel.h> 16 #include <sound/core.h> 17 #include <sound/soc-acpi.h> 18 #include "sof_sdw_common.h" 19 #include "../../codecs/rt711.h" 20 21 static unsigned long sof_sdw_quirk = RT711_JD1; 22 static int quirk_override = -1; 23 module_param_named(quirk, quirk_override, int, 0444); 24 MODULE_PARM_DESC(quirk, "Board-specific quirk override"); 25 26 #define DMIC_DEFAULT_CHANNELS 2 27 28 static void log_quirks(struct device *dev) 29 { 30 if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk)) 31 dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", 32 SOC_SDW_JACK_JDSRC(sof_sdw_quirk)); 33 if (sof_sdw_quirk & SOC_SDW_FOUR_SPK) 34 dev_err(dev, "quirk SOC_SDW_FOUR_SPK enabled but no longer supported\n"); 35 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) 36 dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n"); 37 if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) 38 dev_dbg(dev, "quirk SOC_SDW_PCH_DMIC enabled\n"); 39 if (SOF_SSP_GET_PORT(sof_sdw_quirk)) 40 dev_dbg(dev, "SSP port %ld\n", 41 SOF_SSP_GET_PORT(sof_sdw_quirk)); 42 if (sof_sdw_quirk & SOC_SDW_NO_AGGREGATION) 43 dev_err(dev, "quirk SOC_SDW_NO_AGGREGATION enabled but no longer supported\n"); 44 if (sof_sdw_quirk & SOC_SDW_CODEC_SPKR) 45 dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n"); 46 if (sof_sdw_quirk & SOC_SDW_SIDECAR_AMPS) 47 dev_dbg(dev, "quirk SOC_SDW_SIDECAR_AMPS enabled\n"); 48 if (sof_sdw_quirk & SOC_SDW_CODEC_MIC) 49 dev_dbg(dev, "quirk SOC_SDW_CODEC_MIC enabled\n"); 50 } 51 52 static int sof_sdw_quirk_cb(const struct dmi_system_id *id) 53 { 54 sof_sdw_quirk = (unsigned long)id->driver_data; 55 return 1; 56 } 57 58 static const struct dmi_system_id sof_sdw_quirk_table[] = { 59 /* CometLake devices */ 60 { 61 .callback = sof_sdw_quirk_cb, 62 .matches = { 63 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 64 DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"), 65 }, 66 .driver_data = (void *)SOC_SDW_PCH_DMIC, 67 }, 68 { 69 .callback = sof_sdw_quirk_cb, 70 .matches = { 71 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 72 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6") 73 }, 74 .driver_data = (void *)RT711_JD2, 75 }, 76 { 77 /* early version of SKU 09C6 */ 78 .callback = sof_sdw_quirk_cb, 79 .matches = { 80 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 81 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983") 82 }, 83 .driver_data = (void *)RT711_JD2, 84 }, 85 { 86 .callback = sof_sdw_quirk_cb, 87 .matches = { 88 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 89 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), 90 }, 91 .driver_data = (void *)(RT711_JD2), 92 }, 93 { 94 .callback = sof_sdw_quirk_cb, 95 .matches = { 96 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 97 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), 98 }, 99 .driver_data = (void *)(RT711_JD2), 100 }, 101 /* IceLake devices */ 102 { 103 .callback = sof_sdw_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 *)SOC_SDW_PCH_DMIC, 109 }, 110 /* TigerLake devices */ 111 { 112 .callback = sof_sdw_quirk_cb, 113 .matches = { 114 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 115 DMI_MATCH(DMI_PRODUCT_NAME, 116 "Tiger Lake Client Platform"), 117 }, 118 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 119 RT711_JD1 | 120 SOC_SDW_PCH_DMIC | 121 SOF_SSP_PORT(SOF_I2S_SSP2)), 122 }, 123 { 124 .callback = sof_sdw_quirk_cb, 125 .matches = { 126 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 127 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E") 128 }, 129 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 130 RT711_JD2), 131 }, 132 { 133 /* another SKU of Dell Latitude 9520 */ 134 .callback = sof_sdw_quirk_cb, 135 .matches = { 136 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 137 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F") 138 }, 139 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 140 RT711_JD2), 141 }, 142 { 143 /* Dell XPS 9710 */ 144 .callback = sof_sdw_quirk_cb, 145 .matches = { 146 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 147 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D") 148 }, 149 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 150 RT711_JD2), 151 }, 152 { 153 .callback = sof_sdw_quirk_cb, 154 .matches = { 155 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 156 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E") 157 }, 158 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 159 RT711_JD2), 160 }, 161 { 162 .callback = sof_sdw_quirk_cb, 163 .matches = { 164 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 165 DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"), 166 }, 167 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 168 SOC_SDW_PCH_DMIC | 169 SOF_BT_OFFLOAD_SSP(2) | 170 SOF_SSP_BT_OFFLOAD_PRESENT), 171 }, 172 { 173 .callback = sof_sdw_quirk_cb, 174 .matches = { 175 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 176 DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"), 177 }, 178 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 179 SOC_SDW_PCH_DMIC), 180 }, 181 { 182 /* 183 * this entry covers multiple HP SKUs. The family name 184 * does not seem robust enough, so we use a partial 185 * match that ignores the product name suffix 186 * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx) 187 */ 188 .callback = sof_sdw_quirk_cb, 189 .matches = { 190 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 191 DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"), 192 }, 193 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 194 SOC_SDW_PCH_DMIC | 195 RT711_JD1), 196 }, 197 { 198 /* 199 * this entry covers HP Spectre x360 where the DMI information 200 * changed somehow 201 */ 202 .callback = sof_sdw_quirk_cb, 203 .matches = { 204 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 205 DMI_MATCH(DMI_BOARD_NAME, "8709"), 206 }, 207 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 208 SOC_SDW_PCH_DMIC | 209 RT711_JD1), 210 }, 211 { 212 /* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */ 213 .callback = sof_sdw_quirk_cb, 214 .matches = { 215 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), 216 DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"), 217 }, 218 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 219 SOC_SDW_PCH_DMIC | 220 RT711_JD1), 221 }, 222 { 223 /* NUC15 LAPBC710 skews */ 224 .callback = sof_sdw_quirk_cb, 225 .matches = { 226 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), 227 DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"), 228 }, 229 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 230 SOC_SDW_PCH_DMIC | 231 RT711_JD1), 232 }, 233 { 234 /* 235 * Avell B.ON (OEM rebrand of NUC15 'Bishop County' LAPBC510 and 236 * LAPBC710) 237 */ 238 .callback = sof_sdw_quirk_cb, 239 .matches = { 240 DMI_MATCH(DMI_SYS_VENDOR, "Avell High Performance"), 241 DMI_MATCH(DMI_PRODUCT_NAME, "B.ON"), 242 }, 243 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 244 SOC_SDW_PCH_DMIC | 245 RT711_JD1), 246 }, 247 { 248 /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */ 249 .callback = sof_sdw_quirk_cb, 250 .matches = { 251 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), 252 DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"), 253 }, 254 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 255 SOC_SDW_PCH_DMIC | 256 RT711_JD2_100K), 257 }, 258 { 259 /* NUC15 LAPRC710 skews */ 260 .callback = sof_sdw_quirk_cb, 261 .matches = { 262 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), 263 DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"), 264 }, 265 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 266 SOC_SDW_PCH_DMIC | 267 RT711_JD2_100K), 268 }, 269 /* TigerLake-SDCA devices */ 270 { 271 .callback = sof_sdw_quirk_cb, 272 .matches = { 273 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 274 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32") 275 }, 276 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 277 RT711_JD2), 278 }, 279 { 280 .callback = sof_sdw_quirk_cb, 281 .matches = { 282 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 283 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45") 284 }, 285 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 286 RT711_JD2), 287 }, 288 /* AlderLake devices */ 289 { 290 .callback = sof_sdw_quirk_cb, 291 .matches = { 292 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 293 DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"), 294 }, 295 .driver_data = (void *)(RT711_JD2_100K | 296 SOF_SDW_TGL_HDMI | 297 SOF_BT_OFFLOAD_SSP(2) | 298 SOF_SSP_BT_OFFLOAD_PRESENT), 299 }, 300 { 301 .callback = sof_sdw_quirk_cb, 302 .matches = { 303 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), 304 DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"), 305 }, 306 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 307 RT711_JD2_100K), 308 }, 309 { 310 .callback = sof_sdw_quirk_cb, 311 .matches = { 312 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 313 DMI_MATCH(DMI_PRODUCT_NAME, "Brya"), 314 }, 315 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 316 SOC_SDW_PCH_DMIC | 317 SOF_BT_OFFLOAD_SSP(2) | 318 SOF_SSP_BT_OFFLOAD_PRESENT), 319 }, 320 { 321 .callback = sof_sdw_quirk_cb, 322 .matches = { 323 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 324 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0") 325 }, 326 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 327 RT711_JD2), 328 }, 329 { 330 .callback = sof_sdw_quirk_cb, 331 .matches = { 332 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 333 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"), 334 }, 335 /* No Jack */ 336 .driver_data = (void *)(SOF_SDW_TGL_HDMI), 337 }, 338 { 339 .callback = sof_sdw_quirk_cb, 340 .matches = { 341 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 342 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE") 343 }, 344 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 345 RT711_JD2), 346 }, 347 { 348 .callback = sof_sdw_quirk_cb, 349 .matches = { 350 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 351 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF") 352 }, 353 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 354 RT711_JD2), 355 }, 356 { 357 .callback = sof_sdw_quirk_cb, 358 .matches = { 359 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 360 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00") 361 }, 362 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 363 RT711_JD2), 364 }, 365 { 366 .callback = sof_sdw_quirk_cb, 367 .matches = { 368 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 369 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01") 370 }, 371 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 372 RT711_JD2), 373 }, 374 { 375 .callback = sof_sdw_quirk_cb, 376 .matches = { 377 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 378 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11") 379 }, 380 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 381 RT711_JD2), 382 }, 383 { 384 .callback = sof_sdw_quirk_cb, 385 .matches = { 386 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 387 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12") 388 }, 389 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 390 RT711_JD2), 391 }, 392 { 393 .callback = sof_sdw_quirk_cb, 394 .matches = { 395 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 396 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"), 397 }, 398 /* No Jack */ 399 .driver_data = (void *)SOF_SDW_TGL_HDMI, 400 }, 401 { 402 .callback = sof_sdw_quirk_cb, 403 .matches = { 404 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 405 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"), 406 }, 407 /* No Jack */ 408 .driver_data = (void *)SOF_SDW_TGL_HDMI, 409 }, 410 411 { 412 .callback = sof_sdw_quirk_cb, 413 .matches = { 414 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 415 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"), 416 }, 417 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 418 RT711_JD2), 419 }, 420 { 421 .callback = sof_sdw_quirk_cb, 422 .matches = { 423 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 424 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"), 425 }, 426 /* No Jack */ 427 .driver_data = (void *)SOF_SDW_TGL_HDMI, 428 }, 429 { 430 .callback = sof_sdw_quirk_cb, 431 .matches = { 432 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 433 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"), 434 }, 435 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 436 RT711_JD2), 437 }, 438 { 439 .callback = sof_sdw_quirk_cb, 440 .matches = { 441 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 442 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"), 443 }, 444 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 445 RT711_JD2), 446 }, 447 /* RaptorLake devices */ 448 { 449 .callback = sof_sdw_quirk_cb, 450 .matches = { 451 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 452 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA") 453 }, 454 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 455 RT711_JD2), 456 }, 457 { 458 .callback = sof_sdw_quirk_cb, 459 .matches = { 460 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 461 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F") 462 }, 463 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 464 RT711_JD2), 465 }, 466 { 467 .callback = sof_sdw_quirk_cb, 468 .matches = { 469 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 470 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"), 471 }, 472 /* No Jack */ 473 .driver_data = (void *)(SOF_SDW_TGL_HDMI), 474 }, 475 { 476 .callback = sof_sdw_quirk_cb, 477 .matches = { 478 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 479 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11") 480 }, 481 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 482 RT711_JD2), 483 }, 484 { 485 .callback = sof_sdw_quirk_cb, 486 .matches = { 487 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 488 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40") 489 }, 490 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 491 RT711_JD2), 492 }, 493 { 494 .callback = sof_sdw_quirk_cb, 495 .matches = { 496 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 497 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F") 498 }, 499 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 500 RT711_JD2), 501 }, 502 { 503 .callback = sof_sdw_quirk_cb, 504 .matches = { 505 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 506 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6") 507 }, 508 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 509 }, 510 { 511 .callback = sof_sdw_quirk_cb, 512 .matches = { 513 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 514 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9") 515 }, 516 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 517 }, 518 { 519 .callback = sof_sdw_quirk_cb, 520 .matches = { 521 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 522 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA") 523 }, 524 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 525 }, 526 /* MeteorLake devices */ 527 { 528 .callback = sof_sdw_quirk_cb, 529 .matches = { 530 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"), 531 }, 532 .driver_data = (void *)(RT711_JD1), 533 }, 534 { 535 .callback = sof_sdw_quirk_cb, 536 .matches = { 537 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 538 DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"), 539 }, 540 .driver_data = (void *)(RT711_JD2_100K), 541 }, 542 { 543 .callback = sof_sdw_quirk_cb, 544 .matches = { 545 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 546 DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), 547 }, 548 .driver_data = (void *)(SOC_SDW_PCH_DMIC | 549 SOF_BT_OFFLOAD_SSP(1) | 550 SOF_SSP_BT_OFFLOAD_PRESENT), 551 }, 552 { 553 .callback = sof_sdw_quirk_cb, 554 .matches = { 555 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 556 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"), 557 }, 558 .driver_data = (void *)(RT711_JD2), 559 }, 560 561 /* LunarLake devices */ 562 { 563 .callback = sof_sdw_quirk_cb, 564 .matches = { 565 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 566 DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"), 567 }, 568 .driver_data = (void *)(RT711_JD2), 569 }, 570 { 571 .callback = sof_sdw_quirk_cb, 572 .matches = { 573 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 574 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3") 575 }, 576 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), 577 }, 578 { 579 .callback = sof_sdw_quirk_cb, 580 .matches = { 581 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 582 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4") 583 }, 584 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), 585 }, 586 { 587 .callback = sof_sdw_quirk_cb, 588 .matches = { 589 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 590 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB") 591 }, 592 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 593 }, 594 { 595 .callback = sof_sdw_quirk_cb, 596 .matches = { 597 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 598 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC") 599 }, 600 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 601 }, 602 { 603 .callback = sof_sdw_quirk_cb, 604 .matches = { 605 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 606 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD") 607 }, 608 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 609 }, 610 { 611 .callback = sof_sdw_quirk_cb, 612 .matches = { 613 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 614 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36") 615 }, 616 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 617 }, 618 { 619 .callback = sof_sdw_quirk_cb, 620 .matches = { 621 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 622 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8") 623 }, 624 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 625 }, 626 { 627 .callback = sof_sdw_quirk_cb, 628 .matches = { 629 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 630 DMI_MATCH(DMI_PRODUCT_NAME, "83JX") 631 }, 632 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 633 }, 634 { 635 .callback = sof_sdw_quirk_cb, 636 .matches = { 637 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 638 DMI_MATCH(DMI_PRODUCT_NAME, "83LC") 639 }, 640 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 641 }, 642 { 643 .callback = sof_sdw_quirk_cb, 644 .matches = { 645 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 646 DMI_MATCH(DMI_PRODUCT_NAME, "83MC") 647 }, 648 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 649 }, { 650 .callback = sof_sdw_quirk_cb, 651 .matches = { 652 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 653 DMI_MATCH(DMI_PRODUCT_NAME, "83NM") 654 }, 655 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 656 }, 657 { 658 .callback = sof_sdw_quirk_cb, 659 .matches = { 660 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 661 DMI_MATCH(DMI_PRODUCT_NAME, "83HM") 662 }, 663 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | 664 SOC_SDW_CODEC_MIC), 665 }, 666 { 667 .callback = sof_sdw_quirk_cb, 668 .matches = { 669 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 670 DMI_MATCH(DMI_PRODUCT_NAME, "21QB") 671 }, 672 /* Note this quirk excludes the CODEC mic */ 673 .driver_data = (void *)(SOC_SDW_CODEC_MIC), 674 }, 675 { 676 .callback = sof_sdw_quirk_cb, 677 .matches = { 678 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 679 DMI_MATCH(DMI_PRODUCT_NAME, "21QA") 680 }, 681 /* Note this quirk excludes the CODEC mic */ 682 .driver_data = (void *)(SOC_SDW_CODEC_MIC), 683 }, 684 { 685 .callback = sof_sdw_quirk_cb, 686 .matches = { 687 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 688 DMI_MATCH(DMI_PRODUCT_NAME, "21Q6") 689 }, 690 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 691 }, 692 { 693 .callback = sof_sdw_quirk_cb, 694 .matches = { 695 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 696 DMI_MATCH(DMI_PRODUCT_NAME, "21Q7") 697 }, 698 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 699 }, 700 701 /* ArrowLake devices */ 702 { 703 .callback = sof_sdw_quirk_cb, 704 .matches = { 705 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 706 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8") 707 }, 708 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 709 }, 710 { 711 .callback = sof_sdw_quirk_cb, 712 .matches = { 713 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 714 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF1") 715 }, 716 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 717 }, 718 { 719 .callback = sof_sdw_quirk_cb, 720 .matches = { 721 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 722 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7") 723 }, 724 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 725 }, 726 { 727 .callback = sof_sdw_quirk_cb, 728 .matches = { 729 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 730 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0") 731 }, 732 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 733 }, 734 { 735 .callback = sof_sdw_quirk_cb, 736 .matches = { 737 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 738 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3") 739 }, 740 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 741 }, 742 { 743 .callback = sof_sdw_quirk_cb, 744 .matches = { 745 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 746 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4") 747 }, 748 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 749 }, 750 { 751 .callback = sof_sdw_quirk_cb, 752 .matches = { 753 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 754 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5") 755 }, 756 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 757 }, 758 { 759 .callback = sof_sdw_quirk_cb, 760 .matches = { 761 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 762 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CCC") 763 }, 764 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 765 }, 766 { 767 .callback = sof_sdw_quirk_cb, 768 .matches = { 769 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 770 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CCD") 771 }, 772 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 773 }, 774 /* Pantherlake devices*/ 775 { 776 .callback = sof_sdw_quirk_cb, 777 .matches = { 778 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 779 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0DD6") 780 }, 781 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), 782 }, 783 { 784 .callback = sof_sdw_quirk_cb, 785 .matches = { 786 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"), 787 }, 788 .driver_data = (void *)(SOC_SDW_PCH_DMIC), 789 }, 790 { 791 .callback = sof_sdw_quirk_cb, 792 .matches = { 793 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 794 DMI_MATCH(DMI_PRODUCT_NAME, "Lapis"), 795 }, 796 .driver_data = (void *)(SOC_SDW_CODEC_SPKR | 797 SOC_SDW_PCH_DMIC | 798 SOF_BT_OFFLOAD_SSP(2) | 799 SOF_SSP_BT_OFFLOAD_PRESENT), 800 }, 801 { 802 .callback = sof_sdw_quirk_cb, 803 .matches = { 804 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 805 DMI_MATCH(DMI_PRODUCT_NAME, "Francka"), 806 }, 807 .driver_data = (void *)(SOC_SDW_CODEC_SPKR | 808 SOC_SDW_PCH_DMIC | 809 SOF_BT_OFFLOAD_SSP(2) | 810 SOF_SSP_BT_OFFLOAD_PRESENT), 811 }, 812 { 813 .callback = sof_sdw_quirk_cb, 814 .matches = { 815 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 816 DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Fatcat"), 817 }, 818 .driver_data = (void *)(SOC_SDW_PCH_DMIC | 819 SOF_BT_OFFLOAD_SSP(2) | 820 SOF_SSP_BT_OFFLOAD_PRESENT), 821 }, 822 /* Wildcatlake devices*/ 823 { 824 .callback = sof_sdw_quirk_cb, 825 .matches = { 826 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_wclrvp"), 827 }, 828 .driver_data = (void *)(SOC_SDW_PCH_DMIC), 829 }, 830 { 831 .callback = sof_sdw_quirk_cb, 832 .matches = { 833 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 834 DMI_MATCH(DMI_PRODUCT_NAME, "Ocelot"), 835 }, 836 .driver_data = (void *)(SOC_SDW_PCH_DMIC | 837 SOF_BT_OFFLOAD_SSP(2) | 838 SOF_SSP_BT_OFFLOAD_PRESENT), 839 }, 840 /* Novalake devices*/ 841 { 842 .callback = sof_sdw_quirk_cb, 843 .matches = { 844 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_nvlrvp"), 845 }, 846 .driver_data = (void *)(SOC_SDW_PCH_DMIC), 847 }, 848 {} 849 }; 850 851 static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = { 852 SND_PCI_QUIRK(0x1028, 0x0e53, "Dell XPS WCL", SOC_SDW_SIDECAR_AMPS), 853 SND_PCI_QUIRK(0x1028, 0x0e54, "Dell XPS PTL", SOC_SDW_SIDECAR_AMPS), 854 SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC), 855 SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC), 856 SND_PCI_QUIRK(0x17aa, 0x2347, "Lenovo P16", SOC_SDW_CODEC_MIC), 857 SND_PCI_QUIRK(0x17aa, 0x2348, "Lenovo P16", SOC_SDW_CODEC_MIC), 858 SND_PCI_QUIRK(0x17aa, 0x2349, "Lenovo P1", SOC_SDW_CODEC_MIC), 859 SND_PCI_QUIRK(0x17aa, 0x3821, "Lenovo 0x3821", SOC_SDW_SIDECAR_AMPS), 860 SND_PCI_QUIRK(0x17aa, 0x383c, "Lenovo 0x383c", SOC_SDW_SIDECAR_AMPS), 861 {} 862 }; 863 864 static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach) 865 { 866 const struct snd_pci_quirk *quirk_entry; 867 868 quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor, 869 mach->mach_params.subsystem_device, 870 sof_sdw_ssid_quirk_table); 871 872 if (quirk_entry) 873 sof_sdw_quirk = quirk_entry->value; 874 } 875 876 static const struct snd_soc_ops sdw_ops = { 877 .startup = asoc_sdw_startup, 878 .prepare = asoc_sdw_prepare, 879 .trigger = asoc_sdw_trigger, 880 .hw_params = asoc_sdw_hw_params, 881 .hw_free = asoc_sdw_hw_free, 882 .shutdown = asoc_sdw_shutdown, 883 }; 884 885 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; 886 887 static int create_sdw_dailink(struct snd_soc_card *card, 888 struct asoc_sdw_dailink *sof_dai, 889 struct snd_soc_dai_link **dai_links, 890 int *be_id, struct snd_soc_codec_conf **codec_conf) 891 { 892 struct device *dev = card->dev; 893 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 894 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 895 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 896 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 897 struct asoc_sdw_endpoint *sof_end; 898 int stream; 899 int ret; 900 901 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 902 if (sof_end->name_prefix) { 903 (*codec_conf)->dlc.name = sof_end->codec_name; 904 (*codec_conf)->name_prefix = sof_end->name_prefix; 905 (*codec_conf)++; 906 } 907 908 if (sof_end->include_sidecar && sof_end->codec_info->add_sidecar) { 909 ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); 910 if (ret) 911 return ret; 912 } 913 } 914 915 /* 916 * The dai_type is used to select function topologies. Since the topology stream name 917 * and DAI link name use partial matching, unconditionally appending the dai_type provides 918 * necessary selection metadata without breaking existing topologies. Although 919 * ctx->append_dai_type is not checked here, we overwrite it to ensure consistency in case 920 * it is referenced elsewhere. 921 */ 922 ctx->append_dai_type = true; 923 for_each_pcm_streams(stream) { 924 static const char * const sdw_stream_name[] = { 925 "SDW%d-Playback-%s", 926 "SDW%d-Capture-%s", 927 }; 928 struct snd_soc_dai_link_ch_map *codec_maps; 929 struct snd_soc_dai_link_component *codecs; 930 struct snd_soc_dai_link_component *cpus; 931 struct snd_soc_dai_link_component *platform; 932 int num_cpus = hweight32(sof_dai->link_mask[stream]); 933 int num_codecs = sof_dai->num_devs[stream]; 934 int playback, capture; 935 int cur_link = 0; 936 int i = 0, j = 0; 937 char *name; 938 939 if (!sof_dai->num_devs[stream]) 940 continue; 941 942 sof_end = list_first_entry(&sof_dai->endpoints, 943 struct asoc_sdw_endpoint, list); 944 945 *be_id = sof_end->dai_info->dailink[stream]; 946 if (*be_id < 0) { 947 dev_err(dev, "Invalid dailink id %d\n", *be_id); 948 return -EINVAL; 949 } 950 951 /* create stream name according to first link id */ 952 name = devm_kasprintf(dev, GFP_KERNEL, 953 sdw_stream_name[stream], 954 ffs(sof_end->link_mask) - 1, 955 type_strings[sof_end->dai_info->dai_type]); 956 if (!name) 957 return -ENOMEM; 958 959 cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); 960 if (!cpus) 961 return -ENOMEM; 962 963 codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); 964 if (!codecs) 965 return -ENOMEM; 966 967 platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); 968 if (!platform) 969 return -ENOMEM; 970 971 codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); 972 if (!codec_maps) 973 return -ENOMEM; 974 975 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 976 if (!sof_end->dai_info->direction[stream]) 977 continue; 978 979 if (cur_link != sof_end->link_mask) { 980 int link_num = ffs(sof_end->link_mask) - 1; 981 int pin_num = intel_ctx->sdw_pin_index[link_num]++; 982 983 cur_link = sof_end->link_mask; 984 985 cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, 986 "SDW%d Pin%d", 987 link_num, pin_num); 988 if (!cpus[i].dai_name) 989 return -ENOMEM; 990 i++; 991 } 992 993 codec_maps[j].cpu = i - 1; 994 codec_maps[j].codec = j; 995 996 codecs[j].name = sof_end->codec_name; 997 codecs[j].dai_name = sof_end->dai_info->dai_name; 998 if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC && 999 mach_params->dmic_num > 0) { 1000 dev_warn(dev, 1001 "Both SDW DMIC and PCH DMIC are present, if incorrect, please set kernel params snd_sof_intel_hda_generic dmic_num=0 to disable PCH DMIC\n"); 1002 } 1003 j++; 1004 } 1005 1006 WARN_ON(i != num_cpus || j != num_codecs); 1007 1008 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); 1009 capture = (stream == SNDRV_PCM_STREAM_CAPTURE); 1010 1011 asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, 1012 cpus, num_cpus, platform, 1, codecs, num_codecs, 1013 1, asoc_sdw_rtd_init, &sdw_ops); 1014 1015 /* 1016 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations 1017 * based on wait_for_completion(), tag them as 'nonatomic'. 1018 */ 1019 (*dai_links)->nonatomic = true; 1020 (*dai_links)->ch_maps = codec_maps; 1021 1022 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 1023 if (sof_end->dai_info->init) 1024 sof_end->dai_info->init(card, *dai_links, 1025 sof_end->codec_info, 1026 playback); 1027 } 1028 1029 (*dai_links)++; 1030 } 1031 1032 return 0; 1033 } 1034 1035 static int create_sdw_dailinks(struct snd_soc_card *card, 1036 struct snd_soc_dai_link **dai_links, int *be_id, 1037 struct asoc_sdw_dailink *sof_dais, 1038 struct snd_soc_codec_conf **codec_conf) 1039 { 1040 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1041 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1042 int ret, i; 1043 1044 for (i = 0; i < SDW_INTEL_MAX_LINKS; i++) 1045 intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE; 1046 1047 /* generate DAI links by each sdw link */ 1048 while (sof_dais->initialised) { 1049 int current_be_id = 0; 1050 1051 ret = create_sdw_dailink(card, sof_dais, dai_links, 1052 ¤t_be_id, codec_conf); 1053 if (ret) 1054 return ret; 1055 1056 /* Update the be_id to match the highest ID used for SDW link */ 1057 if (*be_id < current_be_id) 1058 *be_id = current_be_id; 1059 1060 sof_dais++; 1061 } 1062 1063 return 0; 1064 } 1065 1066 static int create_ssp_dailinks(struct snd_soc_card *card, 1067 struct snd_soc_dai_link **dai_links, int *be_id, 1068 struct asoc_sdw_codec_info *ssp_info, 1069 unsigned long ssp_mask) 1070 { 1071 struct device *dev = card->dev; 1072 int i, j = 0; 1073 int ret; 1074 1075 for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) { 1076 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); 1077 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); 1078 char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", 1079 ssp_info->acpi_id, j++); 1080 if (!name || !cpu_dai_name || !codec_name) 1081 return -ENOMEM; 1082 1083 int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; 1084 int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; 1085 1086 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1087 playback, capture, cpu_dai_name, 1088 "dummy", codec_name, 1089 ssp_info->dais[0].dai_name, 1, NULL, 1090 ssp_info->ops); 1091 if (ret) 1092 return ret; 1093 1094 ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0); 1095 if (ret < 0) 1096 return ret; 1097 1098 (*dai_links)++; 1099 } 1100 1101 return 0; 1102 } 1103 1104 static int create_dmic_dailinks(struct snd_soc_card *card, 1105 struct snd_soc_dai_link **dai_links, int *be_id) 1106 { 1107 struct device *dev = card->dev; 1108 int ret; 1109 1110 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01", 1111 0, 1, // DMIC only supports capture 1112 "DMIC01 Pin", "dummy", 1113 "dmic-codec", "dmic-hifi", 1, 1114 asoc_sdw_dmic_init, NULL); 1115 if (ret) 1116 return ret; 1117 1118 (*dai_links)++; 1119 1120 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", 1121 0, 1, // DMIC only supports capture 1122 "DMIC16k Pin", "dummy", 1123 "dmic-codec", "dmic-hifi", 1, 1124 /* don't call asoc_sdw_dmic_init() twice */ 1125 NULL, NULL); 1126 if (ret) 1127 return ret; 1128 1129 (*dai_links)++; 1130 1131 return 0; 1132 } 1133 1134 static int create_hdmi_dailinks(struct snd_soc_card *card, 1135 struct snd_soc_dai_link **dai_links, int *be_id, 1136 int hdmi_num) 1137 { 1138 struct device *dev = card->dev; 1139 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1140 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1141 int i, ret; 1142 1143 for (i = 0; i < hdmi_num; i++) { 1144 char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); 1145 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); 1146 if (!name || !cpu_dai_name) 1147 return -ENOMEM; 1148 1149 char *codec_name, *codec_dai_name; 1150 1151 if (intel_ctx->hdmi.idisp_codec) { 1152 codec_name = "ehdaudio0D2"; 1153 codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, 1154 "intel-hdmi-hifi%d", i + 1); 1155 } else { 1156 codec_name = "snd-soc-dummy"; 1157 codec_dai_name = "snd-soc-dummy-dai"; 1158 } 1159 1160 if (!codec_dai_name) 1161 return -ENOMEM; 1162 1163 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1164 1, 0, // HDMI only supports playback 1165 cpu_dai_name, "dummy", 1166 codec_name, codec_dai_name, 1, 1167 i == 0 ? sof_sdw_hdmi_init : NULL, NULL); 1168 if (ret) 1169 return ret; 1170 1171 (*dai_links)++; 1172 } 1173 1174 return 0; 1175 } 1176 1177 static int create_bt_dailinks(struct snd_soc_card *card, 1178 struct snd_soc_dai_link **dai_links, int *be_id) 1179 { 1180 struct device *dev = card->dev; 1181 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); 1182 char *cpu_dai_name; 1183 char *name; 1184 int port; 1185 int ret; 1186 1187 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) 1188 port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT; 1189 else 1190 port = fls(mach->mach_params.bt_link_mask) - 1; 1191 1192 name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); 1193 cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); 1194 if (!name || !cpu_dai_name) 1195 return -ENOMEM; 1196 1197 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1198 1, 1, cpu_dai_name, "dummy", 1199 snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, 1200 1, NULL, NULL); 1201 if (ret) 1202 return ret; 1203 1204 (*dai_links)++; 1205 1206 return 0; 1207 } 1208 1209 static int create_echoref_dailink(struct snd_soc_card *card, 1210 struct snd_soc_dai_link **dai_links, int *be_id) 1211 { 1212 struct device *dev = card->dev; 1213 int ret; 1214 char *name = devm_kasprintf(dev, GFP_KERNEL, "Loopback_Virtual"); 1215 1216 if (!name) 1217 return -ENOMEM; 1218 1219 /* 1220 * use dummy DAI names as this won't be connected to an actual DAI but just to establish a 1221 * fe <-> be connection for loopback capture for echo reference 1222 */ 1223 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1224 0, 1, "Loopback Virtual Pin", "dummy", 1225 snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, 1226 1, NULL, NULL); 1227 if (ret) 1228 return ret; 1229 1230 (*dai_links)++; 1231 1232 dev_dbg(dev, "Added echo reference DAI link\n"); 1233 1234 return 0; 1235 } 1236 1237 static int sof_card_dai_links_create(struct snd_soc_card *card) 1238 { 1239 struct device *dev = card->dev; 1240 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 1241 int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; 1242 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1243 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1244 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1245 struct snd_soc_codec_conf *codec_conf; 1246 struct asoc_sdw_codec_info *ssp_info; 1247 struct asoc_sdw_endpoint *sof_ends; 1248 struct asoc_sdw_dailink *sof_dais; 1249 struct snd_soc_aux_dev *sof_aux; 1250 int num_devs = 0; 1251 int num_ends = 0; 1252 int num_aux = 0; 1253 int num_confs; 1254 struct snd_soc_dai_link *dai_links; 1255 int num_links; 1256 int be_id = 0; 1257 int hdmi_num; 1258 unsigned long ssp_mask; 1259 int ret; 1260 1261 ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); 1262 if (ret < 0) { 1263 dev_err(dev, "failed to count devices/endpoints: %d\n", ret); 1264 return ret; 1265 } 1266 1267 num_confs = num_ends; 1268 1269 /* 1270 * One per DAI link, worst case is a DAI link for every endpoint, also 1271 * add one additional to act as a terminator such that code can iterate 1272 * until it hits an uninitialised DAI. 1273 */ 1274 sof_dais = kzalloc_objs(*sof_dais, num_ends + 1); 1275 if (!sof_dais) 1276 return -ENOMEM; 1277 1278 /* One per endpoint, ie. each DAI on each codec/amp */ 1279 sof_ends = kzalloc_objs(*sof_ends, num_ends); 1280 if (!sof_ends) { 1281 ret = -ENOMEM; 1282 goto err_dai; 1283 } 1284 1285 sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL); 1286 if (!sof_aux) { 1287 ret = -ENOMEM; 1288 goto err_dai; 1289 } 1290 1291 ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs); 1292 if (ret < 0) 1293 goto err_end; 1294 1295 sdw_be_num = ret; 1296 1297 /* 1298 * on generic tgl platform, I2S or sdw mode is supported 1299 * based on board rework. A ACPI device is registered in 1300 * system only when I2S mode is supported, not sdw mode. 1301 * Here check ACPI ID to confirm I2S is supported. 1302 */ 1303 ssp_info = asoc_sdw_find_codec_info_acpi(mach->id); 1304 if (ssp_info) { 1305 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); 1306 ssp_num = hweight_long(ssp_mask); 1307 } 1308 1309 if (mach_params->codec_mask & IDISP_CODEC_MASK) 1310 intel_ctx->hdmi.idisp_codec = true; 1311 1312 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) 1313 hdmi_num = SOF_TGL_HDMI_COUNT; 1314 else 1315 hdmi_num = SOF_PRE_TGL_HDMI_COUNT; 1316 1317 /* enable dmic01 & dmic16k */ 1318 if (ctx->ignore_internal_dmic) { 1319 dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n"); 1320 mach_params->dmic_num = 0; 1321 } else if (mach_params->dmic_num) { 1322 dmic_num = 2; 1323 } else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) { 1324 dmic_num = 2; 1325 /* 1326 * mach_params->dmic_num will be used to set the cfg-mics value of 1327 * card->components string. Set it to the default value. 1328 */ 1329 mach_params->dmic_num = DMIC_DEFAULT_CHANNELS; 1330 } 1331 1332 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT || mach_params->bt_link_mask) 1333 bt_num = 1; 1334 1335 dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", 1336 sdw_be_num, ssp_num, dmic_num, 1337 intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); 1338 1339 codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL); 1340 if (!codec_conf) { 1341 ret = -ENOMEM; 1342 goto err_end; 1343 } 1344 1345 /* 1346 * allocate BE dailinks, add an extra DAI link for echo reference capture. 1347 * This should be the last DAI link and it is expected both for monolithic 1348 * and functional SOF topologies to support echo reference. 1349 */ 1350 num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num + 1; 1351 dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); 1352 if (!dai_links) { 1353 ret = -ENOMEM; 1354 goto err_end; 1355 } 1356 1357 card->codec_conf = codec_conf; 1358 card->num_configs = num_confs; 1359 card->dai_link = dai_links; 1360 card->num_links = num_links; 1361 card->aux_dev = sof_aux; 1362 card->num_aux_devs = num_aux; 1363 1364 /* SDW */ 1365 if (sdw_be_num) { 1366 ret = create_sdw_dailinks(card, &dai_links, &be_id, 1367 sof_dais, &codec_conf); 1368 if (ret) 1369 goto err_end; 1370 } 1371 1372 /* SSP */ 1373 if (ssp_num) { 1374 ret = create_ssp_dailinks(card, &dai_links, &be_id, 1375 ssp_info, ssp_mask); 1376 if (ret) 1377 goto err_end; 1378 } 1379 1380 /* dmic */ 1381 if (dmic_num) { 1382 ret = create_dmic_dailinks(card, &dai_links, &be_id); 1383 if (ret) 1384 goto err_end; 1385 } 1386 1387 /* HDMI */ 1388 ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num); 1389 if (ret) 1390 goto err_end; 1391 1392 /* BT */ 1393 if (bt_num) { 1394 ret = create_bt_dailinks(card, &dai_links, &be_id); 1395 if (ret) 1396 goto err_end; 1397 } 1398 1399 /* dummy echo ref link. keep this as the last DAI link. The DAI link ID does not matter */ 1400 ret = create_echoref_dailink(card, &dai_links, &be_id); 1401 if (ret) { 1402 dev_err(dev, "failed to create echo ref dai link: %d\n", ret); 1403 goto err_end; 1404 } 1405 1406 WARN_ON(codec_conf != card->codec_conf + card->num_configs); 1407 WARN_ON(dai_links != card->dai_link + card->num_links); 1408 1409 err_end: 1410 kfree(sof_ends); 1411 err_dai: 1412 kfree(sof_dais); 1413 1414 return ret; 1415 } 1416 1417 static int sof_sdw_card_late_probe(struct snd_soc_card *card) 1418 { 1419 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1420 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1421 int ret = 0; 1422 1423 ret = asoc_sdw_card_late_probe(card); 1424 if (ret < 0) 1425 return ret; 1426 1427 if (intel_ctx->hdmi.idisp_codec) 1428 ret = sof_sdw_hdmi_card_late_probe(card); 1429 1430 return ret; 1431 } 1432 1433 static int sof_sdw_add_dai_link(struct snd_soc_card *card, 1434 struct snd_soc_dai_link *link) 1435 { 1436 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1437 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1438 1439 /* Ignore the HDMI PCM link if iDisp is not present */ 1440 if (strstr(link->stream_name, "HDMI") && !intel_ctx->hdmi.idisp_codec) 1441 link->ignore = true; 1442 1443 return 0; 1444 } 1445 1446 static int mc_probe(struct platform_device *pdev) 1447 { 1448 struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); 1449 struct snd_soc_card *card; 1450 struct asoc_sdw_mc_private *ctx; 1451 struct intel_mc_ctx *intel_ctx; 1452 int amp_num = 0, i; 1453 int ret; 1454 1455 dev_dbg(&pdev->dev, "Entry\n"); 1456 1457 intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL); 1458 if (!intel_ctx) 1459 return -ENOMEM; 1460 1461 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 1462 if (!ctx) 1463 return -ENOMEM; 1464 1465 ctx->private = intel_ctx; 1466 ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); 1467 card = &ctx->card; 1468 card->dev = &pdev->dev; 1469 card->name = "soundwire"; 1470 card->owner = THIS_MODULE; 1471 card->late_probe = sof_sdw_card_late_probe; 1472 card->add_dai_link = sof_sdw_add_dai_link; 1473 1474 snd_soc_card_set_drvdata(card, ctx); 1475 1476 if (mach->mach_params.subsystem_id_set) { 1477 snd_soc_card_set_pci_ssid(card, 1478 mach->mach_params.subsystem_vendor, 1479 mach->mach_params.subsystem_device); 1480 sof_sdw_check_ssid_quirk(mach); 1481 } 1482 1483 dmi_check_system(sof_sdw_quirk_table); 1484 1485 if (quirk_override != -1) { 1486 dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", 1487 sof_sdw_quirk, quirk_override); 1488 sof_sdw_quirk = quirk_override; 1489 } 1490 1491 log_quirks(card->dev); 1492 1493 ctx->mc_quirk = sof_sdw_quirk; 1494 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ 1495 for (i = 0; i < ctx->codec_info_list_count; i++) 1496 codec_info_list[i].amp_num = 0; 1497 1498 ret = sof_card_dai_links_create(card); 1499 if (ret < 0) 1500 return ret; 1501 1502 /* 1503 * the default amp_num is zero for each codec and 1504 * amp_num will only be increased for active amp 1505 * codecs on used platform 1506 */ 1507 for (i = 0; i < ctx->codec_info_list_count; i++) 1508 amp_num += codec_info_list[i].amp_num; 1509 1510 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 1511 " cfg-amp:%d", amp_num); 1512 if (!card->components) 1513 return -ENOMEM; 1514 1515 if (mach->mach_params.dmic_num) { 1516 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 1517 "%s mic:dmic cfg-mics:%d", 1518 card->components, 1519 mach->mach_params.dmic_num); 1520 if (!card->components) 1521 return -ENOMEM; 1522 } 1523 1524 /* Register the card */ 1525 ret = devm_snd_soc_register_card(card->dev, card); 1526 if (ret) { 1527 dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); 1528 asoc_sdw_mc_dailink_exit_loop(card); 1529 return ret; 1530 } 1531 1532 platform_set_drvdata(pdev, card); 1533 1534 return ret; 1535 } 1536 1537 static void mc_remove(struct platform_device *pdev) 1538 { 1539 struct snd_soc_card *card = platform_get_drvdata(pdev); 1540 1541 asoc_sdw_mc_dailink_exit_loop(card); 1542 } 1543 1544 static const struct platform_device_id mc_id_table[] = { 1545 { "sof_sdw", }, 1546 {} 1547 }; 1548 MODULE_DEVICE_TABLE(platform, mc_id_table); 1549 1550 static struct platform_driver sof_sdw_driver = { 1551 .driver = { 1552 .name = "sof_sdw", 1553 .pm = &snd_soc_pm_ops, 1554 }, 1555 .probe = mc_probe, 1556 .remove = mc_remove, 1557 .id_table = mc_id_table, 1558 }; 1559 1560 module_platform_driver(sof_sdw_driver); 1561 1562 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver"); 1563 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>"); 1564 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>"); 1565 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); 1566 MODULE_LICENSE("GPL v2"); 1567 MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); 1568 MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); 1569