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 /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */ 235 .callback = sof_sdw_quirk_cb, 236 .matches = { 237 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), 238 DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"), 239 }, 240 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 241 SOC_SDW_PCH_DMIC | 242 RT711_JD2_100K), 243 }, 244 { 245 /* NUC15 LAPRC710 skews */ 246 .callback = sof_sdw_quirk_cb, 247 .matches = { 248 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), 249 DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"), 250 }, 251 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 252 SOC_SDW_PCH_DMIC | 253 RT711_JD2_100K), 254 }, 255 /* TigerLake-SDCA devices */ 256 { 257 .callback = sof_sdw_quirk_cb, 258 .matches = { 259 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 260 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32") 261 }, 262 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 263 RT711_JD2), 264 }, 265 { 266 .callback = sof_sdw_quirk_cb, 267 .matches = { 268 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 269 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45") 270 }, 271 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 272 RT711_JD2), 273 }, 274 /* AlderLake devices */ 275 { 276 .callback = sof_sdw_quirk_cb, 277 .matches = { 278 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 279 DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"), 280 }, 281 .driver_data = (void *)(RT711_JD2_100K | 282 SOF_SDW_TGL_HDMI | 283 SOF_BT_OFFLOAD_SSP(2) | 284 SOF_SSP_BT_OFFLOAD_PRESENT), 285 }, 286 { 287 .callback = sof_sdw_quirk_cb, 288 .matches = { 289 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), 290 DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"), 291 }, 292 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 293 RT711_JD2_100K), 294 }, 295 { 296 .callback = sof_sdw_quirk_cb, 297 .matches = { 298 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 299 DMI_MATCH(DMI_PRODUCT_NAME, "Brya"), 300 }, 301 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 302 SOC_SDW_PCH_DMIC | 303 SOF_BT_OFFLOAD_SSP(2) | 304 SOF_SSP_BT_OFFLOAD_PRESENT), 305 }, 306 { 307 .callback = sof_sdw_quirk_cb, 308 .matches = { 309 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 310 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0") 311 }, 312 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 313 RT711_JD2), 314 }, 315 { 316 .callback = sof_sdw_quirk_cb, 317 .matches = { 318 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 319 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"), 320 }, 321 /* No Jack */ 322 .driver_data = (void *)(SOF_SDW_TGL_HDMI), 323 }, 324 { 325 .callback = sof_sdw_quirk_cb, 326 .matches = { 327 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 328 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE") 329 }, 330 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 331 RT711_JD2), 332 }, 333 { 334 .callback = sof_sdw_quirk_cb, 335 .matches = { 336 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 337 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF") 338 }, 339 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 340 RT711_JD2), 341 }, 342 { 343 .callback = sof_sdw_quirk_cb, 344 .matches = { 345 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 346 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00") 347 }, 348 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 349 RT711_JD2), 350 }, 351 { 352 .callback = sof_sdw_quirk_cb, 353 .matches = { 354 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 355 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01") 356 }, 357 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 358 RT711_JD2), 359 }, 360 { 361 .callback = sof_sdw_quirk_cb, 362 .matches = { 363 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 364 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11") 365 }, 366 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 367 RT711_JD2), 368 }, 369 { 370 .callback = sof_sdw_quirk_cb, 371 .matches = { 372 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 373 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12") 374 }, 375 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 376 RT711_JD2), 377 }, 378 { 379 .callback = sof_sdw_quirk_cb, 380 .matches = { 381 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 382 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"), 383 }, 384 /* No Jack */ 385 .driver_data = (void *)SOF_SDW_TGL_HDMI, 386 }, 387 { 388 .callback = sof_sdw_quirk_cb, 389 .matches = { 390 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 391 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"), 392 }, 393 /* No Jack */ 394 .driver_data = (void *)SOF_SDW_TGL_HDMI, 395 }, 396 397 { 398 .callback = sof_sdw_quirk_cb, 399 .matches = { 400 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 401 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"), 402 }, 403 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 404 RT711_JD2), 405 }, 406 { 407 .callback = sof_sdw_quirk_cb, 408 .matches = { 409 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 410 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"), 411 }, 412 /* No Jack */ 413 .driver_data = (void *)SOF_SDW_TGL_HDMI, 414 }, 415 { 416 .callback = sof_sdw_quirk_cb, 417 .matches = { 418 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 419 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"), 420 }, 421 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 422 RT711_JD2), 423 }, 424 { 425 .callback = sof_sdw_quirk_cb, 426 .matches = { 427 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 428 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"), 429 }, 430 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 431 RT711_JD2), 432 }, 433 /* RaptorLake devices */ 434 { 435 .callback = sof_sdw_quirk_cb, 436 .matches = { 437 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 438 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA") 439 }, 440 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 441 RT711_JD2), 442 }, 443 { 444 .callback = sof_sdw_quirk_cb, 445 .matches = { 446 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 447 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F") 448 }, 449 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 450 RT711_JD2), 451 }, 452 { 453 .callback = sof_sdw_quirk_cb, 454 .matches = { 455 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 456 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"), 457 }, 458 /* No Jack */ 459 .driver_data = (void *)(SOF_SDW_TGL_HDMI), 460 }, 461 { 462 .callback = sof_sdw_quirk_cb, 463 .matches = { 464 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 465 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11") 466 }, 467 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 468 RT711_JD2), 469 }, 470 { 471 .callback = sof_sdw_quirk_cb, 472 .matches = { 473 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 474 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40") 475 }, 476 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 477 RT711_JD2), 478 }, 479 { 480 .callback = sof_sdw_quirk_cb, 481 .matches = { 482 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 483 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F") 484 }, 485 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 486 RT711_JD2), 487 }, 488 { 489 .callback = sof_sdw_quirk_cb, 490 .matches = { 491 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 492 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6") 493 }, 494 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 495 }, 496 { 497 .callback = sof_sdw_quirk_cb, 498 .matches = { 499 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 500 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9") 501 }, 502 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 503 }, 504 { 505 .callback = sof_sdw_quirk_cb, 506 .matches = { 507 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 508 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA") 509 }, 510 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 511 }, 512 /* MeteorLake devices */ 513 { 514 .callback = sof_sdw_quirk_cb, 515 .matches = { 516 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"), 517 }, 518 .driver_data = (void *)(RT711_JD1), 519 }, 520 { 521 .callback = sof_sdw_quirk_cb, 522 .matches = { 523 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 524 DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"), 525 }, 526 .driver_data = (void *)(RT711_JD2_100K), 527 }, 528 { 529 .callback = sof_sdw_quirk_cb, 530 .matches = { 531 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 532 DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), 533 }, 534 .driver_data = (void *)(SOC_SDW_PCH_DMIC | 535 SOF_BT_OFFLOAD_SSP(1) | 536 SOF_SSP_BT_OFFLOAD_PRESENT), 537 }, 538 { 539 .callback = sof_sdw_quirk_cb, 540 .matches = { 541 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 542 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"), 543 }, 544 .driver_data = (void *)(RT711_JD2), 545 }, 546 547 /* LunarLake devices */ 548 { 549 .callback = sof_sdw_quirk_cb, 550 .matches = { 551 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 552 DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"), 553 }, 554 .driver_data = (void *)(RT711_JD2), 555 }, 556 { 557 .callback = sof_sdw_quirk_cb, 558 .matches = { 559 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 560 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3") 561 }, 562 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), 563 }, 564 { 565 .callback = sof_sdw_quirk_cb, 566 .matches = { 567 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 568 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4") 569 }, 570 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), 571 }, 572 { 573 .callback = sof_sdw_quirk_cb, 574 .matches = { 575 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 576 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB") 577 }, 578 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 579 }, 580 { 581 .callback = sof_sdw_quirk_cb, 582 .matches = { 583 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 584 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC") 585 }, 586 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 587 }, 588 { 589 .callback = sof_sdw_quirk_cb, 590 .matches = { 591 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 592 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD") 593 }, 594 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 595 }, 596 { 597 .callback = sof_sdw_quirk_cb, 598 .matches = { 599 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 600 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36") 601 }, 602 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 603 }, 604 { 605 .callback = sof_sdw_quirk_cb, 606 .matches = { 607 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 608 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8") 609 }, 610 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 611 }, 612 { 613 .callback = sof_sdw_quirk_cb, 614 .matches = { 615 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 616 DMI_MATCH(DMI_PRODUCT_NAME, "83JX") 617 }, 618 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 619 }, 620 { 621 .callback = sof_sdw_quirk_cb, 622 .matches = { 623 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 624 DMI_MATCH(DMI_PRODUCT_NAME, "83LC") 625 }, 626 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 627 }, 628 { 629 .callback = sof_sdw_quirk_cb, 630 .matches = { 631 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 632 DMI_MATCH(DMI_PRODUCT_NAME, "83MC") 633 }, 634 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 635 }, { 636 .callback = sof_sdw_quirk_cb, 637 .matches = { 638 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 639 DMI_MATCH(DMI_PRODUCT_NAME, "83NM") 640 }, 641 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 642 }, 643 { 644 .callback = sof_sdw_quirk_cb, 645 .matches = { 646 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 647 DMI_MATCH(DMI_PRODUCT_NAME, "83HM") 648 }, 649 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | 650 SOC_SDW_CODEC_MIC), 651 }, 652 { 653 .callback = sof_sdw_quirk_cb, 654 .matches = { 655 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 656 DMI_MATCH(DMI_PRODUCT_NAME, "21QB") 657 }, 658 /* Note this quirk excludes the CODEC mic */ 659 .driver_data = (void *)(SOC_SDW_CODEC_MIC), 660 }, 661 { 662 .callback = sof_sdw_quirk_cb, 663 .matches = { 664 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 665 DMI_MATCH(DMI_PRODUCT_NAME, "21QA") 666 }, 667 /* Note this quirk excludes the CODEC mic */ 668 .driver_data = (void *)(SOC_SDW_CODEC_MIC), 669 }, 670 { 671 .callback = sof_sdw_quirk_cb, 672 .matches = { 673 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 674 DMI_MATCH(DMI_PRODUCT_NAME, "21Q6") 675 }, 676 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 677 }, 678 { 679 .callback = sof_sdw_quirk_cb, 680 .matches = { 681 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 682 DMI_MATCH(DMI_PRODUCT_NAME, "21Q7") 683 }, 684 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), 685 }, 686 687 /* ArrowLake devices */ 688 { 689 .callback = sof_sdw_quirk_cb, 690 .matches = { 691 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 692 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8") 693 }, 694 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 695 }, 696 { 697 .callback = sof_sdw_quirk_cb, 698 .matches = { 699 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 700 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF1") 701 }, 702 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 703 }, 704 { 705 .callback = sof_sdw_quirk_cb, 706 .matches = { 707 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 708 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7") 709 }, 710 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 711 }, 712 { 713 .callback = sof_sdw_quirk_cb, 714 .matches = { 715 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 716 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0") 717 }, 718 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 719 }, 720 { 721 .callback = sof_sdw_quirk_cb, 722 .matches = { 723 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 724 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3") 725 }, 726 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 727 }, 728 { 729 .callback = sof_sdw_quirk_cb, 730 .matches = { 731 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 732 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4") 733 }, 734 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 735 }, 736 { 737 .callback = sof_sdw_quirk_cb, 738 .matches = { 739 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 740 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5") 741 }, 742 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 743 }, 744 { 745 .callback = sof_sdw_quirk_cb, 746 .matches = { 747 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), 748 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CCC") 749 }, 750 .driver_data = (void *)(SOC_SDW_CODEC_SPKR), 751 }, 752 /* Pantherlake devices*/ 753 { 754 .callback = sof_sdw_quirk_cb, 755 .matches = { 756 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"), 757 }, 758 .driver_data = (void *)(SOC_SDW_PCH_DMIC), 759 }, 760 { 761 .callback = sof_sdw_quirk_cb, 762 .matches = { 763 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 764 DMI_MATCH(DMI_PRODUCT_NAME, "Fatcat"), 765 }, 766 .driver_data = (void *)(SOC_SDW_PCH_DMIC | 767 SOF_BT_OFFLOAD_SSP(2) | 768 SOF_SSP_BT_OFFLOAD_PRESENT), 769 }, 770 /* Wildcatlake devices*/ 771 { 772 .callback = sof_sdw_quirk_cb, 773 .matches = { 774 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_wclrvp"), 775 }, 776 .driver_data = (void *)(SOC_SDW_PCH_DMIC), 777 }, 778 { 779 .callback = sof_sdw_quirk_cb, 780 .matches = { 781 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 782 DMI_MATCH(DMI_PRODUCT_NAME, "Ocelot"), 783 }, 784 .driver_data = (void *)(SOC_SDW_PCH_DMIC | 785 SOF_BT_OFFLOAD_SSP(2) | 786 SOF_SSP_BT_OFFLOAD_PRESENT), 787 }, 788 {} 789 }; 790 791 static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = { 792 SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC), 793 SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC), 794 SND_PCI_QUIRK(0x17aa, 0x2347, "Lenovo P16", SOC_SDW_CODEC_MIC), 795 SND_PCI_QUIRK(0x17aa, 0x2348, "Lenovo P16", SOC_SDW_CODEC_MIC), 796 SND_PCI_QUIRK(0x17aa, 0x2349, "Lenovo P1", SOC_SDW_CODEC_MIC), 797 {} 798 }; 799 800 static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach) 801 { 802 const struct snd_pci_quirk *quirk_entry; 803 804 quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor, 805 mach->mach_params.subsystem_device, 806 sof_sdw_ssid_quirk_table); 807 808 if (quirk_entry) 809 sof_sdw_quirk = quirk_entry->value; 810 } 811 812 static const struct snd_soc_ops sdw_ops = { 813 .startup = asoc_sdw_startup, 814 .prepare = asoc_sdw_prepare, 815 .trigger = asoc_sdw_trigger, 816 .hw_params = asoc_sdw_hw_params, 817 .hw_free = asoc_sdw_hw_free, 818 .shutdown = asoc_sdw_shutdown, 819 }; 820 821 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; 822 823 static int create_sdw_dailink(struct snd_soc_card *card, 824 struct asoc_sdw_dailink *sof_dai, 825 struct snd_soc_dai_link **dai_links, 826 int *be_id, struct snd_soc_codec_conf **codec_conf) 827 { 828 struct device *dev = card->dev; 829 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 830 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 831 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 832 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 833 struct asoc_sdw_endpoint *sof_end; 834 int stream; 835 int ret; 836 837 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 838 if (sof_end->name_prefix) { 839 (*codec_conf)->dlc.name = sof_end->codec_name; 840 (*codec_conf)->name_prefix = sof_end->name_prefix; 841 (*codec_conf)++; 842 } 843 844 if (sof_end->include_sidecar) { 845 ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); 846 if (ret) 847 return ret; 848 } 849 } 850 851 for_each_pcm_streams(stream) { 852 static const char * const sdw_stream_name[] = { 853 "SDW%d-Playback", 854 "SDW%d-Capture", 855 "SDW%d-Playback-%s", 856 "SDW%d-Capture-%s", 857 }; 858 struct snd_soc_dai_link_ch_map *codec_maps; 859 struct snd_soc_dai_link_component *codecs; 860 struct snd_soc_dai_link_component *cpus; 861 struct snd_soc_dai_link_component *platform; 862 int num_cpus = hweight32(sof_dai->link_mask[stream]); 863 int num_codecs = sof_dai->num_devs[stream]; 864 int playback, capture; 865 int cur_link = 0; 866 int i = 0, j = 0; 867 char *name; 868 869 if (!sof_dai->num_devs[stream]) 870 continue; 871 872 sof_end = list_first_entry(&sof_dai->endpoints, 873 struct asoc_sdw_endpoint, list); 874 875 *be_id = sof_end->dai_info->dailink[stream]; 876 if (*be_id < 0) { 877 dev_err(dev, "Invalid dailink id %d\n", *be_id); 878 return -EINVAL; 879 } 880 881 /* create stream name according to first link id */ 882 if (ctx->append_dai_type) 883 name = devm_kasprintf(dev, GFP_KERNEL, 884 sdw_stream_name[stream + 2], 885 ffs(sof_end->link_mask) - 1, 886 type_strings[sof_end->dai_info->dai_type]); 887 else 888 name = devm_kasprintf(dev, GFP_KERNEL, 889 sdw_stream_name[stream], 890 ffs(sof_end->link_mask) - 1); 891 if (!name) 892 return -ENOMEM; 893 894 cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); 895 if (!cpus) 896 return -ENOMEM; 897 898 codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); 899 if (!codecs) 900 return -ENOMEM; 901 902 platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); 903 if (!platform) 904 return -ENOMEM; 905 906 codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); 907 if (!codec_maps) 908 return -ENOMEM; 909 910 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 911 if (!sof_end->dai_info->direction[stream]) 912 continue; 913 914 if (cur_link != sof_end->link_mask) { 915 int link_num = ffs(sof_end->link_mask) - 1; 916 int pin_num = intel_ctx->sdw_pin_index[link_num]++; 917 918 cur_link = sof_end->link_mask; 919 920 cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, 921 "SDW%d Pin%d", 922 link_num, pin_num); 923 if (!cpus[i].dai_name) 924 return -ENOMEM; 925 i++; 926 } 927 928 codec_maps[j].cpu = i - 1; 929 codec_maps[j].codec = j; 930 931 codecs[j].name = sof_end->codec_name; 932 codecs[j].dai_name = sof_end->dai_info->dai_name; 933 if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC && 934 mach_params->dmic_num > 0) { 935 dev_warn(dev, 936 "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"); 937 } 938 j++; 939 } 940 941 WARN_ON(i != num_cpus || j != num_codecs); 942 943 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); 944 capture = (stream == SNDRV_PCM_STREAM_CAPTURE); 945 946 asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, 947 cpus, num_cpus, platform, 1, codecs, num_codecs, 948 1, asoc_sdw_rtd_init, &sdw_ops); 949 950 /* 951 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations 952 * based on wait_for_completion(), tag them as 'nonatomic'. 953 */ 954 (*dai_links)->nonatomic = true; 955 (*dai_links)->ch_maps = codec_maps; 956 957 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 958 if (sof_end->dai_info->init) 959 sof_end->dai_info->init(card, *dai_links, 960 sof_end->codec_info, 961 playback); 962 } 963 964 (*dai_links)++; 965 } 966 967 return 0; 968 } 969 970 static int create_sdw_dailinks(struct snd_soc_card *card, 971 struct snd_soc_dai_link **dai_links, int *be_id, 972 struct asoc_sdw_dailink *sof_dais, 973 struct snd_soc_codec_conf **codec_conf) 974 { 975 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 976 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 977 int ret, i; 978 979 for (i = 0; i < SDW_INTEL_MAX_LINKS; i++) 980 intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE; 981 982 /* generate DAI links by each sdw link */ 983 while (sof_dais->initialised) { 984 int current_be_id = 0; 985 986 ret = create_sdw_dailink(card, sof_dais, dai_links, 987 ¤t_be_id, codec_conf); 988 if (ret) 989 return ret; 990 991 /* Update the be_id to match the highest ID used for SDW link */ 992 if (*be_id < current_be_id) 993 *be_id = current_be_id; 994 995 sof_dais++; 996 } 997 998 return 0; 999 } 1000 1001 static int create_ssp_dailinks(struct snd_soc_card *card, 1002 struct snd_soc_dai_link **dai_links, int *be_id, 1003 struct asoc_sdw_codec_info *ssp_info, 1004 unsigned long ssp_mask) 1005 { 1006 struct device *dev = card->dev; 1007 int i, j = 0; 1008 int ret; 1009 1010 for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) { 1011 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); 1012 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); 1013 char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", 1014 ssp_info->acpi_id, j++); 1015 if (!name || !cpu_dai_name || !codec_name) 1016 return -ENOMEM; 1017 1018 int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; 1019 int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; 1020 1021 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1022 playback, capture, cpu_dai_name, 1023 "dummy", codec_name, 1024 ssp_info->dais[0].dai_name, 1, NULL, 1025 ssp_info->ops); 1026 if (ret) 1027 return ret; 1028 1029 ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0); 1030 if (ret < 0) 1031 return ret; 1032 1033 (*dai_links)++; 1034 } 1035 1036 return 0; 1037 } 1038 1039 static int create_dmic_dailinks(struct snd_soc_card *card, 1040 struct snd_soc_dai_link **dai_links, int *be_id) 1041 { 1042 struct device *dev = card->dev; 1043 int ret; 1044 1045 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01", 1046 0, 1, // DMIC only supports capture 1047 "DMIC01 Pin", "dummy", 1048 "dmic-codec", "dmic-hifi", 1, 1049 asoc_sdw_dmic_init, NULL); 1050 if (ret) 1051 return ret; 1052 1053 (*dai_links)++; 1054 1055 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", 1056 0, 1, // DMIC only supports capture 1057 "DMIC16k Pin", "dummy", 1058 "dmic-codec", "dmic-hifi", 1, 1059 /* don't call asoc_sdw_dmic_init() twice */ 1060 NULL, NULL); 1061 if (ret) 1062 return ret; 1063 1064 (*dai_links)++; 1065 1066 return 0; 1067 } 1068 1069 static int create_hdmi_dailinks(struct snd_soc_card *card, 1070 struct snd_soc_dai_link **dai_links, int *be_id, 1071 int hdmi_num) 1072 { 1073 struct device *dev = card->dev; 1074 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1075 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1076 int i, ret; 1077 1078 for (i = 0; i < hdmi_num; i++) { 1079 char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); 1080 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); 1081 if (!name || !cpu_dai_name) 1082 return -ENOMEM; 1083 1084 char *codec_name, *codec_dai_name; 1085 1086 if (intel_ctx->hdmi.idisp_codec) { 1087 codec_name = "ehdaudio0D2"; 1088 codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, 1089 "intel-hdmi-hifi%d", i + 1); 1090 } else { 1091 codec_name = "snd-soc-dummy"; 1092 codec_dai_name = "snd-soc-dummy-dai"; 1093 } 1094 1095 if (!codec_dai_name) 1096 return -ENOMEM; 1097 1098 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1099 1, 0, // HDMI only supports playback 1100 cpu_dai_name, "dummy", 1101 codec_name, codec_dai_name, 1, 1102 i == 0 ? sof_sdw_hdmi_init : NULL, NULL); 1103 if (ret) 1104 return ret; 1105 1106 (*dai_links)++; 1107 } 1108 1109 return 0; 1110 } 1111 1112 static int create_bt_dailinks(struct snd_soc_card *card, 1113 struct snd_soc_dai_link **dai_links, int *be_id) 1114 { 1115 struct device *dev = card->dev; 1116 int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> 1117 SOF_BT_OFFLOAD_SSP_SHIFT; 1118 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); 1119 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); 1120 if (!name || !cpu_dai_name) 1121 return -ENOMEM; 1122 1123 int ret; 1124 1125 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1126 1, 1, cpu_dai_name, "dummy", 1127 snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, 1128 1, NULL, NULL); 1129 if (ret) 1130 return ret; 1131 1132 (*dai_links)++; 1133 1134 return 0; 1135 } 1136 1137 static int sof_card_dai_links_create(struct snd_soc_card *card) 1138 { 1139 struct device *dev = card->dev; 1140 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 1141 int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; 1142 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1143 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1144 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1145 struct snd_soc_codec_conf *codec_conf; 1146 struct asoc_sdw_codec_info *ssp_info; 1147 struct asoc_sdw_endpoint *sof_ends; 1148 struct asoc_sdw_dailink *sof_dais; 1149 int num_devs = 0; 1150 int num_ends = 0; 1151 struct snd_soc_dai_link *dai_links; 1152 int num_links; 1153 int be_id = 0; 1154 int hdmi_num; 1155 unsigned long ssp_mask; 1156 int ret; 1157 1158 ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); 1159 if (ret < 0) { 1160 dev_err(dev, "failed to count devices/endpoints: %d\n", ret); 1161 return ret; 1162 } 1163 1164 /* 1165 * One per DAI link, worst case is a DAI link for every endpoint, also 1166 * add one additional to act as a terminator such that code can iterate 1167 * until it hits an uninitialised DAI. 1168 */ 1169 sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL); 1170 if (!sof_dais) 1171 return -ENOMEM; 1172 1173 /* One per endpoint, ie. each DAI on each codec/amp */ 1174 sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL); 1175 if (!sof_ends) { 1176 ret = -ENOMEM; 1177 goto err_dai; 1178 } 1179 1180 ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); 1181 if (ret < 0) 1182 goto err_end; 1183 1184 sdw_be_num = ret; 1185 1186 /* 1187 * on generic tgl platform, I2S or sdw mode is supported 1188 * based on board rework. A ACPI device is registered in 1189 * system only when I2S mode is supported, not sdw mode. 1190 * Here check ACPI ID to confirm I2S is supported. 1191 */ 1192 ssp_info = asoc_sdw_find_codec_info_acpi(mach->id); 1193 if (ssp_info) { 1194 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); 1195 ssp_num = hweight_long(ssp_mask); 1196 } 1197 1198 if (mach_params->codec_mask & IDISP_CODEC_MASK) 1199 intel_ctx->hdmi.idisp_codec = true; 1200 1201 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) 1202 hdmi_num = SOF_TGL_HDMI_COUNT; 1203 else 1204 hdmi_num = SOF_PRE_TGL_HDMI_COUNT; 1205 1206 /* enable dmic01 & dmic16k */ 1207 if (ctx->ignore_internal_dmic) { 1208 dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n"); 1209 mach_params->dmic_num = 0; 1210 } else if (mach_params->dmic_num) { 1211 dmic_num = 2; 1212 } else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) { 1213 dmic_num = 2; 1214 /* 1215 * mach_params->dmic_num will be used to set the cfg-mics value of 1216 * card->components string. Set it to the default value. 1217 */ 1218 mach_params->dmic_num = DMIC_DEFAULT_CHANNELS; 1219 } 1220 1221 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) 1222 bt_num = 1; 1223 1224 dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", 1225 sdw_be_num, ssp_num, dmic_num, 1226 intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); 1227 1228 codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); 1229 if (!codec_conf) { 1230 ret = -ENOMEM; 1231 goto err_end; 1232 } 1233 1234 /* allocate BE dailinks */ 1235 num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num; 1236 dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); 1237 if (!dai_links) { 1238 ret = -ENOMEM; 1239 goto err_end; 1240 } 1241 1242 card->codec_conf = codec_conf; 1243 card->num_configs = num_devs; 1244 card->dai_link = dai_links; 1245 card->num_links = num_links; 1246 1247 /* SDW */ 1248 if (sdw_be_num) { 1249 ret = create_sdw_dailinks(card, &dai_links, &be_id, 1250 sof_dais, &codec_conf); 1251 if (ret) 1252 goto err_end; 1253 } 1254 1255 /* SSP */ 1256 if (ssp_num) { 1257 ret = create_ssp_dailinks(card, &dai_links, &be_id, 1258 ssp_info, ssp_mask); 1259 if (ret) 1260 goto err_end; 1261 } 1262 1263 /* dmic */ 1264 if (dmic_num) { 1265 ret = create_dmic_dailinks(card, &dai_links, &be_id); 1266 if (ret) 1267 goto err_end; 1268 } 1269 1270 /* HDMI */ 1271 ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num); 1272 if (ret) 1273 goto err_end; 1274 1275 /* BT */ 1276 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { 1277 ret = create_bt_dailinks(card, &dai_links, &be_id); 1278 if (ret) 1279 goto err_end; 1280 } 1281 1282 WARN_ON(codec_conf != card->codec_conf + card->num_configs); 1283 WARN_ON(dai_links != card->dai_link + card->num_links); 1284 1285 err_end: 1286 kfree(sof_ends); 1287 err_dai: 1288 kfree(sof_dais); 1289 1290 return ret; 1291 } 1292 1293 static int sof_sdw_card_late_probe(struct snd_soc_card *card) 1294 { 1295 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1296 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1297 int ret = 0; 1298 1299 ret = asoc_sdw_card_late_probe(card); 1300 if (ret < 0) 1301 return ret; 1302 1303 if (intel_ctx->hdmi.idisp_codec) 1304 ret = sof_sdw_hdmi_card_late_probe(card); 1305 1306 return ret; 1307 } 1308 1309 static int sof_sdw_add_dai_link(struct snd_soc_card *card, 1310 struct snd_soc_dai_link *link) 1311 { 1312 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1313 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1314 1315 /* Ignore the HDMI PCM link if iDisp is not present */ 1316 if (strstr(link->stream_name, "HDMI") && !intel_ctx->hdmi.idisp_codec) 1317 link->ignore = true; 1318 1319 return 0; 1320 } 1321 1322 static int mc_probe(struct platform_device *pdev) 1323 { 1324 struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); 1325 struct snd_soc_card *card; 1326 struct asoc_sdw_mc_private *ctx; 1327 struct intel_mc_ctx *intel_ctx; 1328 int amp_num = 0, i; 1329 int ret; 1330 1331 dev_dbg(&pdev->dev, "Entry\n"); 1332 1333 intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL); 1334 if (!intel_ctx) 1335 return -ENOMEM; 1336 1337 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 1338 if (!ctx) 1339 return -ENOMEM; 1340 1341 ctx->private = intel_ctx; 1342 ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); 1343 card = &ctx->card; 1344 card->dev = &pdev->dev; 1345 card->name = "soundwire"; 1346 card->owner = THIS_MODULE; 1347 card->late_probe = sof_sdw_card_late_probe; 1348 card->add_dai_link = sof_sdw_add_dai_link; 1349 1350 snd_soc_card_set_drvdata(card, ctx); 1351 1352 if (mach->mach_params.subsystem_id_set) { 1353 snd_soc_card_set_pci_ssid(card, 1354 mach->mach_params.subsystem_vendor, 1355 mach->mach_params.subsystem_device); 1356 sof_sdw_check_ssid_quirk(mach); 1357 } 1358 1359 dmi_check_system(sof_sdw_quirk_table); 1360 1361 if (quirk_override != -1) { 1362 dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", 1363 sof_sdw_quirk, quirk_override); 1364 sof_sdw_quirk = quirk_override; 1365 } 1366 1367 log_quirks(card->dev); 1368 1369 ctx->mc_quirk = sof_sdw_quirk; 1370 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ 1371 for (i = 0; i < ctx->codec_info_list_count; i++) 1372 codec_info_list[i].amp_num = 0; 1373 1374 ret = sof_card_dai_links_create(card); 1375 if (ret < 0) 1376 return ret; 1377 1378 /* 1379 * the default amp_num is zero for each codec and 1380 * amp_num will only be increased for active amp 1381 * codecs on used platform 1382 */ 1383 for (i = 0; i < ctx->codec_info_list_count; i++) 1384 amp_num += codec_info_list[i].amp_num; 1385 1386 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 1387 " cfg-amp:%d", amp_num); 1388 if (!card->components) 1389 return -ENOMEM; 1390 1391 if (mach->mach_params.dmic_num) { 1392 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 1393 "%s mic:dmic cfg-mics:%d", 1394 card->components, 1395 mach->mach_params.dmic_num); 1396 if (!card->components) 1397 return -ENOMEM; 1398 } 1399 1400 /* Register the card */ 1401 ret = devm_snd_soc_register_card(card->dev, card); 1402 if (ret) { 1403 dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); 1404 asoc_sdw_mc_dailink_exit_loop(card); 1405 return ret; 1406 } 1407 1408 platform_set_drvdata(pdev, card); 1409 1410 return ret; 1411 } 1412 1413 static void mc_remove(struct platform_device *pdev) 1414 { 1415 struct snd_soc_card *card = platform_get_drvdata(pdev); 1416 1417 asoc_sdw_mc_dailink_exit_loop(card); 1418 } 1419 1420 static const struct platform_device_id mc_id_table[] = { 1421 { "sof_sdw", }, 1422 {} 1423 }; 1424 MODULE_DEVICE_TABLE(platform, mc_id_table); 1425 1426 static struct platform_driver sof_sdw_driver = { 1427 .driver = { 1428 .name = "sof_sdw", 1429 .pm = &snd_soc_pm_ops, 1430 }, 1431 .probe = mc_probe, 1432 .remove = mc_remove, 1433 .id_table = mc_id_table, 1434 }; 1435 1436 module_platform_driver(sof_sdw_driver); 1437 1438 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver"); 1439 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>"); 1440 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>"); 1441 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); 1442 MODULE_LICENSE("GPL v2"); 1443 MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); 1444 MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); 1445