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