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 /* Pantherlake devices*/ 745 { 746 .callback = sof_sdw_quirk_cb, 747 .matches = { 748 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"), 749 }, 750 .driver_data = (void *)(SOC_SDW_PCH_DMIC), 751 }, 752 { 753 .callback = sof_sdw_quirk_cb, 754 .matches = { 755 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 756 DMI_MATCH(DMI_PRODUCT_NAME, "Fatcat"), 757 }, 758 .driver_data = (void *)(SOC_SDW_PCH_DMIC | 759 SOF_BT_OFFLOAD_SSP(2) | 760 SOF_SSP_BT_OFFLOAD_PRESENT), 761 }, 762 {} 763 }; 764 765 static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = { 766 SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC), 767 {} 768 }; 769 770 static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach) 771 { 772 const struct snd_pci_quirk *quirk_entry; 773 774 quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor, 775 mach->mach_params.subsystem_device, 776 sof_sdw_ssid_quirk_table); 777 778 if (quirk_entry) 779 sof_sdw_quirk = quirk_entry->value; 780 } 781 782 static struct snd_soc_dai_link_component platform_component[] = { 783 { 784 /* name might be overridden during probe */ 785 .name = "0000:00:1f.3" 786 } 787 }; 788 789 static const struct snd_soc_ops sdw_ops = { 790 .startup = asoc_sdw_startup, 791 .prepare = asoc_sdw_prepare, 792 .trigger = asoc_sdw_trigger, 793 .hw_params = asoc_sdw_hw_params, 794 .hw_free = asoc_sdw_hw_free, 795 .shutdown = asoc_sdw_shutdown, 796 }; 797 798 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; 799 800 static int create_sdw_dailink(struct snd_soc_card *card, 801 struct asoc_sdw_dailink *sof_dai, 802 struct snd_soc_dai_link **dai_links, 803 int *be_id, struct snd_soc_codec_conf **codec_conf) 804 { 805 struct device *dev = card->dev; 806 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 807 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 808 struct asoc_sdw_endpoint *sof_end; 809 int stream; 810 int ret; 811 812 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 813 if (sof_end->name_prefix) { 814 (*codec_conf)->dlc.name = sof_end->codec_name; 815 (*codec_conf)->name_prefix = sof_end->name_prefix; 816 (*codec_conf)++; 817 } 818 819 if (sof_end->include_sidecar) { 820 ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); 821 if (ret) 822 return ret; 823 } 824 } 825 826 for_each_pcm_streams(stream) { 827 static const char * const sdw_stream_name[] = { 828 "SDW%d-Playback", 829 "SDW%d-Capture", 830 "SDW%d-Playback-%s", 831 "SDW%d-Capture-%s", 832 }; 833 struct snd_soc_dai_link_ch_map *codec_maps; 834 struct snd_soc_dai_link_component *codecs; 835 struct snd_soc_dai_link_component *cpus; 836 int num_cpus = hweight32(sof_dai->link_mask[stream]); 837 int num_codecs = sof_dai->num_devs[stream]; 838 int playback, capture; 839 int cur_link = 0; 840 int i = 0, j = 0; 841 char *name; 842 843 if (!sof_dai->num_devs[stream]) 844 continue; 845 846 sof_end = list_first_entry(&sof_dai->endpoints, 847 struct asoc_sdw_endpoint, list); 848 849 *be_id = sof_end->dai_info->dailink[stream]; 850 if (*be_id < 0) { 851 dev_err(dev, "Invalid dailink id %d\n", *be_id); 852 return -EINVAL; 853 } 854 855 /* create stream name according to first link id */ 856 if (ctx->append_dai_type) 857 name = devm_kasprintf(dev, GFP_KERNEL, 858 sdw_stream_name[stream + 2], 859 ffs(sof_end->link_mask) - 1, 860 type_strings[sof_end->dai_info->dai_type]); 861 else 862 name = devm_kasprintf(dev, GFP_KERNEL, 863 sdw_stream_name[stream], 864 ffs(sof_end->link_mask) - 1); 865 if (!name) 866 return -ENOMEM; 867 868 cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); 869 if (!cpus) 870 return -ENOMEM; 871 872 codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); 873 if (!codecs) 874 return -ENOMEM; 875 876 codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); 877 if (!codec_maps) 878 return -ENOMEM; 879 880 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 881 if (!sof_end->dai_info->direction[stream]) 882 continue; 883 884 if (cur_link != sof_end->link_mask) { 885 int link_num = ffs(sof_end->link_mask) - 1; 886 int pin_num = intel_ctx->sdw_pin_index[link_num]++; 887 888 cur_link = sof_end->link_mask; 889 890 cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, 891 "SDW%d Pin%d", 892 link_num, pin_num); 893 if (!cpus[i].dai_name) 894 return -ENOMEM; 895 i++; 896 } 897 898 codec_maps[j].cpu = i - 1; 899 codec_maps[j].codec = j; 900 901 codecs[j].name = sof_end->codec_name; 902 codecs[j].dai_name = sof_end->dai_info->dai_name; 903 j++; 904 } 905 906 WARN_ON(i != num_cpus || j != num_codecs); 907 908 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); 909 capture = (stream == SNDRV_PCM_STREAM_CAPTURE); 910 911 asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, 912 cpus, num_cpus, platform_component, 913 ARRAY_SIZE(platform_component), codecs, num_codecs, 914 1, asoc_sdw_rtd_init, &sdw_ops); 915 916 /* 917 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations 918 * based on wait_for_completion(), tag them as 'nonatomic'. 919 */ 920 (*dai_links)->nonatomic = true; 921 (*dai_links)->ch_maps = codec_maps; 922 923 list_for_each_entry(sof_end, &sof_dai->endpoints, list) { 924 if (sof_end->dai_info->init) 925 sof_end->dai_info->init(card, *dai_links, 926 sof_end->codec_info, 927 playback); 928 } 929 930 (*dai_links)++; 931 } 932 933 return 0; 934 } 935 936 static int create_sdw_dailinks(struct snd_soc_card *card, 937 struct snd_soc_dai_link **dai_links, int *be_id, 938 struct asoc_sdw_dailink *sof_dais, 939 struct snd_soc_codec_conf **codec_conf) 940 { 941 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 942 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 943 int ret, i; 944 945 for (i = 0; i < SDW_INTEL_MAX_LINKS; i++) 946 intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE; 947 948 /* generate DAI links by each sdw link */ 949 while (sof_dais->initialised) { 950 int current_be_id; 951 952 ret = create_sdw_dailink(card, sof_dais, dai_links, 953 ¤t_be_id, codec_conf); 954 if (ret) 955 return ret; 956 957 /* Update the be_id to match the highest ID used for SDW link */ 958 if (*be_id < current_be_id) 959 *be_id = current_be_id; 960 961 sof_dais++; 962 } 963 964 return 0; 965 } 966 967 static int create_ssp_dailinks(struct snd_soc_card *card, 968 struct snd_soc_dai_link **dai_links, int *be_id, 969 struct asoc_sdw_codec_info *ssp_info, 970 unsigned long ssp_mask) 971 { 972 struct device *dev = card->dev; 973 int i, j = 0; 974 int ret; 975 976 for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) { 977 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); 978 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); 979 char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", 980 ssp_info->acpi_id, j++); 981 if (!name || !cpu_dai_name || !codec_name) 982 return -ENOMEM; 983 984 int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; 985 int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; 986 987 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 988 playback, capture, cpu_dai_name, 989 platform_component->name, 990 ARRAY_SIZE(platform_component), codec_name, 991 ssp_info->dais[0].dai_name, 1, NULL, 992 ssp_info->ops); 993 if (ret) 994 return ret; 995 996 ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0); 997 if (ret < 0) 998 return ret; 999 1000 (*dai_links)++; 1001 } 1002 1003 return 0; 1004 } 1005 1006 static int create_dmic_dailinks(struct snd_soc_card *card, 1007 struct snd_soc_dai_link **dai_links, int *be_id) 1008 { 1009 struct device *dev = card->dev; 1010 int ret; 1011 1012 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01", 1013 0, 1, // DMIC only supports capture 1014 "DMIC01 Pin", platform_component->name, 1015 ARRAY_SIZE(platform_component), 1016 "dmic-codec", "dmic-hifi", 1, 1017 asoc_sdw_dmic_init, NULL); 1018 if (ret) 1019 return ret; 1020 1021 (*dai_links)++; 1022 1023 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", 1024 0, 1, // DMIC only supports capture 1025 "DMIC16k Pin", platform_component->name, 1026 ARRAY_SIZE(platform_component), 1027 "dmic-codec", "dmic-hifi", 1, 1028 /* don't call asoc_sdw_dmic_init() twice */ 1029 NULL, NULL); 1030 if (ret) 1031 return ret; 1032 1033 (*dai_links)++; 1034 1035 return 0; 1036 } 1037 1038 static int create_hdmi_dailinks(struct snd_soc_card *card, 1039 struct snd_soc_dai_link **dai_links, int *be_id, 1040 int hdmi_num) 1041 { 1042 struct device *dev = card->dev; 1043 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1044 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1045 int i, ret; 1046 1047 for (i = 0; i < hdmi_num; i++) { 1048 char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); 1049 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); 1050 if (!name || !cpu_dai_name) 1051 return -ENOMEM; 1052 1053 char *codec_name, *codec_dai_name; 1054 1055 if (intel_ctx->hdmi.idisp_codec) { 1056 codec_name = "ehdaudio0D2"; 1057 codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, 1058 "intel-hdmi-hifi%d", i + 1); 1059 } else { 1060 codec_name = "snd-soc-dummy"; 1061 codec_dai_name = "snd-soc-dummy-dai"; 1062 } 1063 1064 if (!codec_dai_name) 1065 return -ENOMEM; 1066 1067 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1068 1, 0, // HDMI only supports playback 1069 cpu_dai_name, platform_component->name, 1070 ARRAY_SIZE(platform_component), 1071 codec_name, codec_dai_name, 1, 1072 i == 0 ? sof_sdw_hdmi_init : NULL, NULL); 1073 if (ret) 1074 return ret; 1075 1076 (*dai_links)++; 1077 } 1078 1079 return 0; 1080 } 1081 1082 static int create_bt_dailinks(struct snd_soc_card *card, 1083 struct snd_soc_dai_link **dai_links, int *be_id) 1084 { 1085 struct device *dev = card->dev; 1086 int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> 1087 SOF_BT_OFFLOAD_SSP_SHIFT; 1088 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); 1089 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); 1090 if (!name || !cpu_dai_name) 1091 return -ENOMEM; 1092 1093 int ret; 1094 1095 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, 1096 1, 1, cpu_dai_name, platform_component->name, 1097 ARRAY_SIZE(platform_component), 1098 snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, 1099 1, NULL, NULL); 1100 if (ret) 1101 return ret; 1102 1103 (*dai_links)++; 1104 1105 return 0; 1106 } 1107 1108 static int sof_card_dai_links_create(struct snd_soc_card *card) 1109 { 1110 struct device *dev = card->dev; 1111 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 1112 int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; 1113 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1114 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1115 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1116 struct snd_soc_codec_conf *codec_conf; 1117 struct asoc_sdw_codec_info *ssp_info; 1118 struct asoc_sdw_endpoint *sof_ends; 1119 struct asoc_sdw_dailink *sof_dais; 1120 int num_devs = 0; 1121 int num_ends = 0; 1122 struct snd_soc_dai_link *dai_links; 1123 int num_links; 1124 int be_id = 0; 1125 int hdmi_num; 1126 unsigned long ssp_mask; 1127 int ret; 1128 1129 ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); 1130 if (ret < 0) { 1131 dev_err(dev, "failed to count devices/endpoints: %d\n", ret); 1132 return ret; 1133 } 1134 1135 /* 1136 * One per DAI link, worst case is a DAI link for every endpoint, also 1137 * add one additional to act as a terminator such that code can iterate 1138 * until it hits an uninitialised DAI. 1139 */ 1140 sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL); 1141 if (!sof_dais) 1142 return -ENOMEM; 1143 1144 /* One per endpoint, ie. each DAI on each codec/amp */ 1145 sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL); 1146 if (!sof_ends) { 1147 ret = -ENOMEM; 1148 goto err_dai; 1149 } 1150 1151 ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); 1152 if (ret < 0) 1153 goto err_end; 1154 1155 sdw_be_num = ret; 1156 1157 /* 1158 * on generic tgl platform, I2S or sdw mode is supported 1159 * based on board rework. A ACPI device is registered in 1160 * system only when I2S mode is supported, not sdw mode. 1161 * Here check ACPI ID to confirm I2S is supported. 1162 */ 1163 ssp_info = asoc_sdw_find_codec_info_acpi(mach->id); 1164 if (ssp_info) { 1165 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); 1166 ssp_num = hweight_long(ssp_mask); 1167 } 1168 1169 if (mach_params->codec_mask & IDISP_CODEC_MASK) 1170 intel_ctx->hdmi.idisp_codec = true; 1171 1172 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) 1173 hdmi_num = SOF_TGL_HDMI_COUNT; 1174 else 1175 hdmi_num = SOF_PRE_TGL_HDMI_COUNT; 1176 1177 /* enable dmic01 & dmic16k */ 1178 if (ctx->ignore_internal_dmic) { 1179 dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n"); 1180 mach_params->dmic_num = 0; 1181 } else if (mach_params->dmic_num) { 1182 dmic_num = 2; 1183 } else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) { 1184 dmic_num = 2; 1185 /* 1186 * mach_params->dmic_num will be used to set the cfg-mics value of 1187 * card->components string. Set it to the default value. 1188 */ 1189 mach_params->dmic_num = DMIC_DEFAULT_CHANNELS; 1190 } 1191 1192 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) 1193 bt_num = 1; 1194 1195 dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", 1196 sdw_be_num, ssp_num, dmic_num, 1197 intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); 1198 1199 codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); 1200 if (!codec_conf) { 1201 ret = -ENOMEM; 1202 goto err_end; 1203 } 1204 1205 /* allocate BE dailinks */ 1206 num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num; 1207 dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); 1208 if (!dai_links) { 1209 ret = -ENOMEM; 1210 goto err_end; 1211 } 1212 1213 card->codec_conf = codec_conf; 1214 card->num_configs = num_devs; 1215 card->dai_link = dai_links; 1216 card->num_links = num_links; 1217 1218 /* SDW */ 1219 if (sdw_be_num) { 1220 ret = create_sdw_dailinks(card, &dai_links, &be_id, 1221 sof_dais, &codec_conf); 1222 if (ret) 1223 goto err_end; 1224 } 1225 1226 /* SSP */ 1227 if (ssp_num) { 1228 ret = create_ssp_dailinks(card, &dai_links, &be_id, 1229 ssp_info, ssp_mask); 1230 if (ret) 1231 goto err_end; 1232 } 1233 1234 /* dmic */ 1235 if (dmic_num) { 1236 ret = create_dmic_dailinks(card, &dai_links, &be_id); 1237 if (ret) 1238 goto err_end; 1239 } 1240 1241 /* HDMI */ 1242 ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num); 1243 if (ret) 1244 goto err_end; 1245 1246 /* BT */ 1247 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { 1248 ret = create_bt_dailinks(card, &dai_links, &be_id); 1249 if (ret) 1250 goto err_end; 1251 } 1252 1253 WARN_ON(codec_conf != card->codec_conf + card->num_configs); 1254 WARN_ON(dai_links != card->dai_link + card->num_links); 1255 1256 err_end: 1257 kfree(sof_ends); 1258 err_dai: 1259 kfree(sof_dais); 1260 1261 return ret; 1262 } 1263 1264 static int sof_sdw_card_late_probe(struct snd_soc_card *card) 1265 { 1266 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1267 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; 1268 int ret = 0; 1269 1270 ret = asoc_sdw_card_late_probe(card); 1271 if (ret < 0) 1272 return ret; 1273 1274 if (intel_ctx->hdmi.idisp_codec) 1275 ret = sof_sdw_hdmi_card_late_probe(card); 1276 1277 return ret; 1278 } 1279 1280 static int mc_probe(struct platform_device *pdev) 1281 { 1282 struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); 1283 struct snd_soc_card *card; 1284 struct asoc_sdw_mc_private *ctx; 1285 struct intel_mc_ctx *intel_ctx; 1286 int amp_num = 0, i; 1287 int ret; 1288 1289 dev_dbg(&pdev->dev, "Entry\n"); 1290 1291 intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL); 1292 if (!intel_ctx) 1293 return -ENOMEM; 1294 1295 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 1296 if (!ctx) 1297 return -ENOMEM; 1298 1299 ctx->private = intel_ctx; 1300 ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); 1301 card = &ctx->card; 1302 card->dev = &pdev->dev; 1303 card->name = "soundwire"; 1304 card->owner = THIS_MODULE; 1305 card->late_probe = sof_sdw_card_late_probe; 1306 1307 snd_soc_card_set_drvdata(card, ctx); 1308 1309 if (mach->mach_params.subsystem_id_set) { 1310 snd_soc_card_set_pci_ssid(card, 1311 mach->mach_params.subsystem_vendor, 1312 mach->mach_params.subsystem_device); 1313 sof_sdw_check_ssid_quirk(mach); 1314 } 1315 1316 dmi_check_system(sof_sdw_quirk_table); 1317 1318 if (quirk_override != -1) { 1319 dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", 1320 sof_sdw_quirk, quirk_override); 1321 sof_sdw_quirk = quirk_override; 1322 } 1323 1324 log_quirks(card->dev); 1325 1326 ctx->mc_quirk = sof_sdw_quirk; 1327 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ 1328 for (i = 0; i < ctx->codec_info_list_count; i++) 1329 codec_info_list[i].amp_num = 0; 1330 1331 ret = sof_card_dai_links_create(card); 1332 if (ret < 0) 1333 return ret; 1334 1335 /* 1336 * the default amp_num is zero for each codec and 1337 * amp_num will only be increased for active amp 1338 * codecs on used platform 1339 */ 1340 for (i = 0; i < ctx->codec_info_list_count; i++) 1341 amp_num += codec_info_list[i].amp_num; 1342 1343 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 1344 " cfg-amp:%d", amp_num); 1345 if (!card->components) 1346 return -ENOMEM; 1347 1348 if (mach->mach_params.dmic_num) { 1349 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 1350 "%s mic:dmic cfg-mics:%d", 1351 card->components, 1352 mach->mach_params.dmic_num); 1353 if (!card->components) 1354 return -ENOMEM; 1355 } 1356 1357 /* Register the card */ 1358 ret = devm_snd_soc_register_card(card->dev, card); 1359 if (ret) { 1360 dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); 1361 asoc_sdw_mc_dailink_exit_loop(card); 1362 return ret; 1363 } 1364 1365 platform_set_drvdata(pdev, card); 1366 1367 return ret; 1368 } 1369 1370 static void mc_remove(struct platform_device *pdev) 1371 { 1372 struct snd_soc_card *card = platform_get_drvdata(pdev); 1373 1374 asoc_sdw_mc_dailink_exit_loop(card); 1375 } 1376 1377 static const struct platform_device_id mc_id_table[] = { 1378 { "sof_sdw", }, 1379 {} 1380 }; 1381 MODULE_DEVICE_TABLE(platform, mc_id_table); 1382 1383 static struct platform_driver sof_sdw_driver = { 1384 .driver = { 1385 .name = "sof_sdw", 1386 .pm = &snd_soc_pm_ops, 1387 }, 1388 .probe = mc_probe, 1389 .remove = mc_remove, 1390 .id_table = mc_id_table, 1391 }; 1392 1393 module_platform_driver(sof_sdw_driver); 1394 1395 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver"); 1396 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>"); 1397 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>"); 1398 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); 1399 MODULE_LICENSE("GPL v2"); 1400 MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); 1401 MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); 1402