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