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