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/device.h> 9 #include <linux/dmi.h> 10 #include <linux/module.h> 11 #include <linux/soundwire/sdw.h> 12 #include <linux/soundwire/sdw_type.h> 13 #include <sound/soc.h> 14 #include <sound/soc-acpi.h> 15 #include "sof_sdw_common.h" 16 #include "../../codecs/rt711.h" 17 18 unsigned long sof_sdw_quirk = RT711_JD1; 19 static int quirk_override = -1; 20 module_param_named(quirk, quirk_override, int, 0444); 21 MODULE_PARM_DESC(quirk, "Board-specific quirk override"); 22 23 #define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0) 24 25 #define SDW_MAX_LINKS 4 26 27 /* To store SDW Pin index for each SoundWire link */ 28 static unsigned int sdw_pin_index[SDW_MAX_LINKS]; 29 30 static void log_quirks(struct device *dev) 31 { 32 if (SOF_JACK_JDSRC(sof_sdw_quirk)) 33 dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", 34 SOF_JACK_JDSRC(sof_sdw_quirk)); 35 if (sof_sdw_quirk & SOF_SDW_FOUR_SPK) 36 dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n"); 37 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) 38 dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n"); 39 if (sof_sdw_quirk & SOF_SDW_PCH_DMIC) 40 dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n"); 41 if (SOF_SSP_GET_PORT(sof_sdw_quirk)) 42 dev_dbg(dev, "SSP port %ld\n", 43 SOF_SSP_GET_PORT(sof_sdw_quirk)); 44 if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION) 45 dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n"); 46 } 47 48 static int sof_sdw_quirk_cb(const struct dmi_system_id *id) 49 { 50 sof_sdw_quirk = (unsigned long)id->driver_data; 51 return 1; 52 } 53 54 static const struct dmi_system_id sof_sdw_quirk_table[] = { 55 /* CometLake devices */ 56 { 57 .callback = sof_sdw_quirk_cb, 58 .matches = { 59 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 60 DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"), 61 }, 62 .driver_data = (void *)SOF_SDW_PCH_DMIC, 63 }, 64 { 65 .callback = sof_sdw_quirk_cb, 66 .matches = { 67 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 68 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6") 69 }, 70 .driver_data = (void *)RT711_JD2, 71 }, 72 { 73 /* early version of SKU 09C6 */ 74 .callback = sof_sdw_quirk_cb, 75 .matches = { 76 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 77 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983") 78 }, 79 .driver_data = (void *)RT711_JD2, 80 }, 81 { 82 .callback = sof_sdw_quirk_cb, 83 .matches = { 84 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 85 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), 86 }, 87 .driver_data = (void *)(RT711_JD2 | 88 SOF_SDW_FOUR_SPK), 89 }, 90 { 91 .callback = sof_sdw_quirk_cb, 92 .matches = { 93 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 94 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), 95 }, 96 .driver_data = (void *)(RT711_JD2 | 97 SOF_SDW_FOUR_SPK), 98 }, 99 /* IceLake devices */ 100 { 101 .callback = sof_sdw_quirk_cb, 102 .matches = { 103 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 104 DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), 105 }, 106 .driver_data = (void *)SOF_SDW_PCH_DMIC, 107 }, 108 /* TigerLake devices */ 109 { 110 .callback = sof_sdw_quirk_cb, 111 .matches = { 112 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 113 DMI_MATCH(DMI_PRODUCT_NAME, 114 "Tiger Lake Client Platform"), 115 }, 116 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 117 RT711_JD1 | 118 SOF_SDW_PCH_DMIC | 119 SOF_SSP_PORT(SOF_I2S_SSP2)), 120 }, 121 { 122 .callback = sof_sdw_quirk_cb, 123 .matches = { 124 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 125 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E") 126 }, 127 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 128 RT711_JD2), 129 }, 130 { 131 /* another SKU of Dell Latitude 9520 */ 132 .callback = sof_sdw_quirk_cb, 133 .matches = { 134 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 135 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F") 136 }, 137 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 138 RT711_JD2), 139 }, 140 { 141 /* Dell XPS 9710 */ 142 .callback = sof_sdw_quirk_cb, 143 .matches = { 144 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 145 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D") 146 }, 147 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 148 RT711_JD2 | 149 SOF_SDW_FOUR_SPK), 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 SOF_SDW_FOUR_SPK), 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 SOF_SDW_PCH_DMIC | 169 SOF_SDW_FOUR_SPK | 170 SOF_BT_OFFLOAD_SSP(2) | 171 SOF_SSP_BT_OFFLOAD_PRESENT), 172 }, 173 { 174 .callback = sof_sdw_quirk_cb, 175 .matches = { 176 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 177 DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"), 178 }, 179 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 180 SOF_SDW_PCH_DMIC | 181 SOF_SDW_FOUR_SPK), 182 }, 183 { 184 /* 185 * this entry covers multiple HP SKUs. The family name 186 * does not seem robust enough, so we use a partial 187 * match that ignores the product name suffix 188 * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx) 189 */ 190 .callback = sof_sdw_quirk_cb, 191 .matches = { 192 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 193 DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"), 194 }, 195 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 196 SOF_SDW_PCH_DMIC | 197 RT711_JD1), 198 }, 199 { 200 /* 201 * this entry covers HP Spectre x360 where the DMI information 202 * changed somehow 203 */ 204 .callback = sof_sdw_quirk_cb, 205 .matches = { 206 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 207 DMI_MATCH(DMI_BOARD_NAME, "8709"), 208 }, 209 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 210 SOF_SDW_PCH_DMIC | 211 RT711_JD1), 212 }, 213 { 214 /* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */ 215 .callback = sof_sdw_quirk_cb, 216 .matches = { 217 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), 218 DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"), 219 }, 220 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 221 SOF_SDW_PCH_DMIC | 222 RT711_JD1), 223 }, 224 { 225 /* NUC15 LAPBC710 skews */ 226 .callback = sof_sdw_quirk_cb, 227 .matches = { 228 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), 229 DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"), 230 }, 231 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 232 SOF_SDW_PCH_DMIC | 233 RT711_JD1), 234 }, 235 { 236 /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */ 237 .callback = sof_sdw_quirk_cb, 238 .matches = { 239 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), 240 DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"), 241 }, 242 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 243 SOF_SDW_PCH_DMIC | 244 RT711_JD2_100K), 245 }, 246 /* TigerLake-SDCA devices */ 247 { 248 .callback = sof_sdw_quirk_cb, 249 .matches = { 250 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 251 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32") 252 }, 253 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 254 RT711_JD2 | 255 SOF_SDW_FOUR_SPK), 256 }, 257 { 258 .callback = sof_sdw_quirk_cb, 259 .matches = { 260 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 261 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45") 262 }, 263 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 264 RT711_JD2), 265 }, 266 /* AlderLake devices */ 267 { 268 .callback = sof_sdw_quirk_cb, 269 .matches = { 270 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 271 DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"), 272 }, 273 .driver_data = (void *)(RT711_JD2_100K | 274 SOF_SDW_TGL_HDMI | 275 SOF_BT_OFFLOAD_SSP(2) | 276 SOF_SSP_BT_OFFLOAD_PRESENT), 277 }, 278 { 279 .callback = sof_sdw_quirk_cb, 280 .matches = { 281 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 282 DMI_MATCH(DMI_PRODUCT_NAME, "Brya"), 283 }, 284 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 285 SOF_SDW_PCH_DMIC | 286 SOF_SDW_FOUR_SPK | 287 SOF_BT_OFFLOAD_SSP(2) | 288 SOF_SSP_BT_OFFLOAD_PRESENT), 289 }, 290 { 291 .callback = sof_sdw_quirk_cb, 292 .matches = { 293 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 294 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0") 295 }, 296 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 297 RT711_JD2 | 298 SOF_SDW_FOUR_SPK), 299 }, 300 { 301 .callback = sof_sdw_quirk_cb, 302 .matches = { 303 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 304 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"), 305 }, 306 /* No Jack */ 307 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 308 SOF_SDW_FOUR_SPK), 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, "0AFE") 315 }, 316 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 317 RT711_JD2 | 318 SOF_SDW_FOUR_SPK), 319 }, 320 { 321 .callback = sof_sdw_quirk_cb, 322 .matches = { 323 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 324 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF") 325 }, 326 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 327 RT711_JD2 | 328 SOF_SDW_FOUR_SPK), 329 }, 330 { 331 .callback = sof_sdw_quirk_cb, 332 .matches = { 333 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 334 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00") 335 }, 336 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 337 RT711_JD2 | 338 SOF_SDW_FOUR_SPK), 339 }, 340 { 341 .callback = sof_sdw_quirk_cb, 342 .matches = { 343 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 344 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01") 345 }, 346 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 347 RT711_JD2 | 348 SOF_SDW_FOUR_SPK), 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, "0B11") 355 }, 356 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 357 RT711_JD2 | 358 SOF_SDW_FOUR_SPK), 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, "0B12") 365 }, 366 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 367 RT711_JD2 | 368 SOF_SDW_FOUR_SPK), 369 }, 370 { 371 .callback = sof_sdw_quirk_cb, 372 .matches = { 373 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 374 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"), 375 }, 376 /* No Jack */ 377 .driver_data = (void *)SOF_SDW_TGL_HDMI, 378 }, 379 { 380 .callback = sof_sdw_quirk_cb, 381 .matches = { 382 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 383 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"), 384 }, 385 /* No Jack */ 386 .driver_data = (void *)SOF_SDW_TGL_HDMI, 387 }, 388 389 { 390 .callback = sof_sdw_quirk_cb, 391 .matches = { 392 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 393 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"), 394 }, 395 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 396 RT711_JD2 | 397 SOF_SDW_FOUR_SPK), 398 }, 399 { 400 .callback = sof_sdw_quirk_cb, 401 .matches = { 402 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 403 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"), 404 }, 405 /* No Jack */ 406 .driver_data = (void *)SOF_SDW_TGL_HDMI, 407 }, 408 { 409 .callback = sof_sdw_quirk_cb, 410 .matches = { 411 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 412 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"), 413 }, 414 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 415 RT711_JD2), 416 }, 417 /* RaptorLake devices */ 418 { 419 .callback = sof_sdw_quirk_cb, 420 .matches = { 421 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 422 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA") 423 }, 424 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 425 RT711_JD2 | 426 SOF_SDW_FOUR_SPK), 427 }, 428 { 429 .callback = sof_sdw_quirk_cb, 430 .matches = { 431 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 432 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"), 433 }, 434 /* No Jack */ 435 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 436 SOF_SDW_FOUR_SPK), 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, "0C11") 443 }, 444 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 445 RT711_JD2 | 446 SOF_SDW_FOUR_SPK), 447 }, 448 { 449 .callback = sof_sdw_quirk_cb, 450 .matches = { 451 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 452 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40") 453 }, 454 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 455 RT711_JD2 | 456 SOF_SDW_FOUR_SPK), 457 }, 458 { 459 .callback = sof_sdw_quirk_cb, 460 .matches = { 461 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 462 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F") 463 }, 464 .driver_data = (void *)(SOF_SDW_TGL_HDMI | 465 RT711_JD2 | 466 SOF_SDW_FOUR_SPK), 467 }, 468 /* MeteorLake devices */ 469 { 470 .callback = sof_sdw_quirk_cb, 471 .matches = { 472 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"), 473 }, 474 .driver_data = (void *)(RT711_JD1), 475 }, 476 { 477 .callback = sof_sdw_quirk_cb, 478 .matches = { 479 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 480 DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"), 481 }, 482 .driver_data = (void *)(RT711_JD2_100K), 483 }, 484 { 485 .callback = sof_sdw_quirk_cb, 486 .matches = { 487 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 488 DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), 489 }, 490 .driver_data = (void *)(SOF_SDW_PCH_DMIC | 491 SOF_BT_OFFLOAD_SSP(1) | 492 SOF_SSP_BT_OFFLOAD_PRESENT), 493 }, 494 /* LunarLake devices */ 495 { 496 .callback = sof_sdw_quirk_cb, 497 .matches = { 498 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 499 DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"), 500 }, 501 .driver_data = (void *)(RT711_JD2), 502 }, 503 {} 504 }; 505 506 static struct snd_soc_dai_link_component dmic_component[] = { 507 { 508 .name = "dmic-codec", 509 .dai_name = "dmic-hifi", 510 } 511 }; 512 513 static struct snd_soc_dai_link_component platform_component[] = { 514 { 515 /* name might be overridden during probe */ 516 .name = "0000:00:1f.3" 517 } 518 }; 519 520 /* these wrappers are only needed to avoid typecast compilation errors */ 521 int sdw_startup(struct snd_pcm_substream *substream) 522 { 523 return sdw_startup_stream(substream); 524 } 525 526 int sdw_prepare(struct snd_pcm_substream *substream) 527 { 528 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 529 struct sdw_stream_runtime *sdw_stream; 530 struct snd_soc_dai *dai; 531 532 /* Find stream from first CPU DAI */ 533 dai = asoc_rtd_to_cpu(rtd, 0); 534 535 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 536 if (IS_ERR(sdw_stream)) { 537 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 538 return PTR_ERR(sdw_stream); 539 } 540 541 return sdw_prepare_stream(sdw_stream); 542 } 543 544 int sdw_trigger(struct snd_pcm_substream *substream, int cmd) 545 { 546 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 547 struct sdw_stream_runtime *sdw_stream; 548 struct snd_soc_dai *dai; 549 int ret; 550 551 /* Find stream from first CPU DAI */ 552 dai = asoc_rtd_to_cpu(rtd, 0); 553 554 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 555 if (IS_ERR(sdw_stream)) { 556 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 557 return PTR_ERR(sdw_stream); 558 } 559 560 switch (cmd) { 561 case SNDRV_PCM_TRIGGER_START: 562 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 563 case SNDRV_PCM_TRIGGER_RESUME: 564 ret = sdw_enable_stream(sdw_stream); 565 break; 566 567 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 568 case SNDRV_PCM_TRIGGER_SUSPEND: 569 case SNDRV_PCM_TRIGGER_STOP: 570 ret = sdw_disable_stream(sdw_stream); 571 break; 572 default: 573 ret = -EINVAL; 574 break; 575 } 576 577 if (ret) 578 dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); 579 580 return ret; 581 } 582 583 int sdw_hw_params(struct snd_pcm_substream *substream, 584 struct snd_pcm_hw_params *params) 585 { 586 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 587 int ch = params_channels(params); 588 struct snd_soc_dai *codec_dai; 589 struct snd_soc_dai *cpu_dai; 590 unsigned int ch_mask; 591 int num_codecs; 592 int step; 593 int i; 594 int j; 595 596 if (!rtd->dai_link->codec_ch_maps) 597 return 0; 598 599 /* Identical data will be sent to all codecs in playback */ 600 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 601 ch_mask = GENMASK(ch - 1, 0); 602 step = 0; 603 } else { 604 num_codecs = rtd->dai_link->num_codecs; 605 606 if (ch < num_codecs || ch % num_codecs != 0) { 607 dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", 608 ch, num_codecs); 609 return -EINVAL; 610 } 611 612 ch_mask = GENMASK(ch / num_codecs - 1, 0); 613 step = hweight_long(ch_mask); 614 615 } 616 617 /* 618 * The captured data will be combined from each cpu DAI if the dai 619 * link has more than one codec DAIs. Set codec channel mask and 620 * ASoC will set the corresponding channel numbers for each cpu dai. 621 */ 622 for_each_rtd_cpu_dais(rtd, i, cpu_dai) { 623 for_each_rtd_codec_dais(rtd, j, codec_dai) { 624 if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id != i) 625 continue; 626 rtd->dai_link->codec_ch_maps[j].ch_mask = ch_mask << (j * step); 627 } 628 } 629 return 0; 630 } 631 632 int sdw_hw_free(struct snd_pcm_substream *substream) 633 { 634 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 635 struct sdw_stream_runtime *sdw_stream; 636 struct snd_soc_dai *dai; 637 638 /* Find stream from first CPU DAI */ 639 dai = asoc_rtd_to_cpu(rtd, 0); 640 641 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 642 if (IS_ERR(sdw_stream)) { 643 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 644 return PTR_ERR(sdw_stream); 645 } 646 647 return sdw_deprepare_stream(sdw_stream); 648 } 649 650 void sdw_shutdown(struct snd_pcm_substream *substream) 651 { 652 sdw_shutdown_stream(substream); 653 } 654 655 static const struct snd_soc_ops sdw_ops = { 656 .startup = sdw_startup, 657 .prepare = sdw_prepare, 658 .trigger = sdw_trigger, 659 .hw_params = sdw_hw_params, 660 .hw_free = sdw_hw_free, 661 .shutdown = sdw_shutdown, 662 }; 663 664 static struct sof_sdw_codec_info codec_info_list[] = { 665 { 666 .part_id = 0x700, 667 .dais = { 668 { 669 .direction = {true, true}, 670 .dai_name = "rt700-aif1", 671 .dai_type = SOF_SDW_DAI_TYPE_JACK, 672 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 673 .init = sof_sdw_rt700_init, 674 }, 675 }, 676 .dai_num = 1, 677 }, 678 { 679 .part_id = 0x711, 680 .version_id = 3, 681 .dais = { 682 { 683 .direction = {true, true}, 684 .dai_name = "rt711-sdca-aif1", 685 .dai_type = SOF_SDW_DAI_TYPE_JACK, 686 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 687 .init = sof_sdw_rt_sdca_jack_init, 688 .exit = sof_sdw_rt_sdca_jack_exit, 689 }, 690 }, 691 .dai_num = 1, 692 }, 693 { 694 .part_id = 0x711, 695 .version_id = 2, 696 .dais = { 697 { 698 .direction = {true, true}, 699 .dai_name = "rt711-aif1", 700 .dai_type = SOF_SDW_DAI_TYPE_JACK, 701 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 702 .init = sof_sdw_rt711_init, 703 .exit = sof_sdw_rt711_exit, 704 }, 705 }, 706 .dai_num = 1, 707 }, 708 { 709 .part_id = 0x712, 710 .version_id = 3, 711 .dais = { 712 { 713 .direction = {true, true}, 714 .dai_name = "rt712-sdca-aif1", 715 .dai_type = SOF_SDW_DAI_TYPE_JACK, 716 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 717 .init = sof_sdw_rt_sdca_jack_init, 718 .exit = sof_sdw_rt_sdca_jack_exit, 719 }, 720 { 721 .direction = {true, false}, 722 .dai_name = "rt712-sdca-aif2", 723 .dai_type = SOF_SDW_DAI_TYPE_AMP, 724 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, 725 .init = sof_sdw_rt712_spk_init, 726 }, 727 }, 728 .dai_num = 2, 729 }, 730 { 731 .part_id = 0x1712, 732 .version_id = 3, 733 .dais = { 734 { 735 .direction = {false, true}, 736 .dai_name = "rt712-sdca-dmic-aif1", 737 .dai_type = SOF_SDW_DAI_TYPE_MIC, 738 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, 739 .init = sof_sdw_rt712_sdca_dmic_init, 740 }, 741 }, 742 .dai_num = 1, 743 }, 744 { 745 .part_id = 0x713, 746 .version_id = 3, 747 .dais = { 748 { 749 .direction = {true, true}, 750 .dai_name = "rt712-sdca-aif1", 751 .dai_type = SOF_SDW_DAI_TYPE_JACK, 752 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 753 .init = sof_sdw_rt_sdca_jack_init, 754 .exit = sof_sdw_rt_sdca_jack_exit, 755 }, 756 }, 757 .dai_num = 1, 758 }, 759 { 760 .part_id = 0x1713, 761 .version_id = 3, 762 .dais = { 763 { 764 .direction = {false, true}, 765 .dai_name = "rt712-sdca-dmic-aif1", 766 .dai_type = SOF_SDW_DAI_TYPE_MIC, 767 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, 768 .init = sof_sdw_rt712_sdca_dmic_init, 769 }, 770 }, 771 .dai_num = 1, 772 }, 773 { 774 .part_id = 0x1308, 775 .acpi_id = "10EC1308", 776 .dais = { 777 { 778 .direction = {true, false}, 779 .dai_name = "rt1308-aif", 780 .dai_type = SOF_SDW_DAI_TYPE_AMP, 781 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, 782 .init = sof_sdw_rt_amp_init, 783 .exit = sof_sdw_rt_amp_exit, 784 }, 785 }, 786 .dai_num = 1, 787 .ops = &sof_sdw_rt1308_i2s_ops, 788 }, 789 { 790 .part_id = 0x1316, 791 .dais = { 792 { 793 .direction = {true, true}, 794 .dai_name = "rt1316-aif", 795 .dai_type = SOF_SDW_DAI_TYPE_AMP, 796 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, 797 .init = sof_sdw_rt_amp_init, 798 .exit = sof_sdw_rt_amp_exit, 799 }, 800 }, 801 .dai_num = 1, 802 }, 803 { 804 .part_id = 0x1318, 805 .dais = { 806 { 807 .direction = {true, true}, 808 .dai_name = "rt1318-aif", 809 .dai_type = SOF_SDW_DAI_TYPE_AMP, 810 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, 811 .init = sof_sdw_rt_amp_init, 812 .exit = sof_sdw_rt_amp_exit, 813 }, 814 }, 815 .dai_num = 1, 816 }, 817 { 818 .part_id = 0x714, 819 .version_id = 3, 820 .ignore_pch_dmic = true, 821 .dais = { 822 { 823 .direction = {false, true}, 824 .dai_name = "rt715-aif2", 825 .dai_type = SOF_SDW_DAI_TYPE_MIC, 826 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, 827 .init = sof_sdw_rt715_sdca_init, 828 }, 829 }, 830 .dai_num = 1, 831 }, 832 { 833 .part_id = 0x715, 834 .version_id = 3, 835 .ignore_pch_dmic = true, 836 .dais = { 837 { 838 .direction = {false, true}, 839 .dai_name = "rt715-aif2", 840 .dai_type = SOF_SDW_DAI_TYPE_MIC, 841 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, 842 .init = sof_sdw_rt715_sdca_init, 843 }, 844 }, 845 .dai_num = 1, 846 }, 847 { 848 .part_id = 0x714, 849 .version_id = 2, 850 .ignore_pch_dmic = true, 851 .dais = { 852 { 853 .direction = {false, true}, 854 .dai_name = "rt715-aif2", 855 .dai_type = SOF_SDW_DAI_TYPE_MIC, 856 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, 857 .init = sof_sdw_rt715_init, 858 }, 859 }, 860 .dai_num = 1, 861 }, 862 { 863 .part_id = 0x715, 864 .version_id = 2, 865 .ignore_pch_dmic = true, 866 .dais = { 867 { 868 .direction = {false, true}, 869 .dai_name = "rt715-aif2", 870 .dai_type = SOF_SDW_DAI_TYPE_MIC, 871 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, 872 .init = sof_sdw_rt715_init, 873 }, 874 }, 875 .dai_num = 1, 876 }, 877 { 878 .part_id = 0x8373, 879 .dais = { 880 { 881 .direction = {true, true}, 882 .dai_name = "max98373-aif1", 883 .dai_type = SOF_SDW_DAI_TYPE_AMP, 884 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, 885 .init = sof_sdw_maxim_init, 886 }, 887 }, 888 .dai_num = 1, 889 }, 890 { 891 .part_id = 0x8363, 892 .dais = { 893 { 894 .direction = {true, false}, 895 .dai_name = "max98363-aif1", 896 .dai_type = SOF_SDW_DAI_TYPE_AMP, 897 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, 898 .init = sof_sdw_maxim_init, 899 }, 900 }, 901 .dai_num = 1, 902 }, 903 { 904 .part_id = 0x5682, 905 .dais = { 906 { 907 .direction = {true, true}, 908 .dai_name = "rt5682-sdw", 909 .dai_type = SOF_SDW_DAI_TYPE_JACK, 910 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 911 .init = sof_sdw_rt5682_init, 912 }, 913 }, 914 .dai_num = 1, 915 }, 916 { 917 .part_id = 0x3556, 918 .dais = { 919 { 920 .direction = {true, true}, 921 .dai_name = "cs35l56-sdw1", 922 .dai_type = SOF_SDW_DAI_TYPE_AMP, 923 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, 924 .init = sof_sdw_cs_amp_init, 925 }, 926 }, 927 .dai_num = 1, 928 }, 929 { 930 .part_id = 0x4242, 931 .dais = { 932 { 933 .direction = {true, true}, 934 .dai_name = "cs42l42-sdw", 935 .dai_type = SOF_SDW_DAI_TYPE_JACK, 936 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 937 .init = sof_sdw_cs42l42_init, 938 }, 939 }, 940 .dai_num = 1, 941 }, 942 { 943 .part_id = 0xaaaa, /* generic codec mockup */ 944 .version_id = 0, 945 .dais = { 946 { 947 .direction = {true, true}, 948 .dai_name = "sdw-mockup-aif1", 949 .dai_type = SOF_SDW_DAI_TYPE_JACK, 950 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 951 .init = NULL, 952 }, 953 }, 954 .dai_num = 1, 955 }, 956 { 957 .part_id = 0xaa55, /* headset codec mockup */ 958 .version_id = 0, 959 .dais = { 960 { 961 .direction = {true, true}, 962 .dai_name = "sdw-mockup-aif1", 963 .dai_type = SOF_SDW_DAI_TYPE_JACK, 964 .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, 965 .init = NULL, 966 }, 967 }, 968 .dai_num = 1, 969 }, 970 { 971 .part_id = 0x55aa, /* amplifier mockup */ 972 .version_id = 0, 973 .dais = { 974 { 975 .direction = {true, true}, 976 .dai_name = "sdw-mockup-aif1", 977 .dai_type = SOF_SDW_DAI_TYPE_AMP, 978 .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, 979 .init = NULL, 980 }, 981 }, 982 .dai_num = 1, 983 }, 984 { 985 .part_id = 0x5555, 986 .version_id = 0, 987 .dais = { 988 { 989 .dai_name = "sdw-mockup-aif1", 990 .direction = {false, true}, 991 .dai_type = SOF_SDW_DAI_TYPE_MIC, 992 .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, 993 .init = NULL, 994 }, 995 }, 996 .dai_num = 1, 997 }, 998 }; 999 1000 static inline int find_codec_info_part(const u64 adr) 1001 { 1002 unsigned int part_id, sdw_version; 1003 int i; 1004 1005 part_id = SDW_PART_ID(adr); 1006 sdw_version = SDW_VERSION(adr); 1007 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1008 /* 1009 * A codec info is for all sdw version with the part id if 1010 * version_id is not specified in the codec info. 1011 */ 1012 if (part_id == codec_info_list[i].part_id && 1013 (!codec_info_list[i].version_id || 1014 sdw_version == codec_info_list[i].version_id)) 1015 return i; 1016 1017 return -EINVAL; 1018 1019 } 1020 1021 static inline int find_codec_info_acpi(const u8 *acpi_id) 1022 { 1023 int i; 1024 1025 if (!acpi_id[0]) 1026 return -EINVAL; 1027 1028 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1029 if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) 1030 return i; 1031 1032 return -EINVAL; 1033 } 1034 1035 /* 1036 * get BE dailink number and CPU DAI number based on sdw link adr. 1037 * Since some sdw slaves may be aggregated, the CPU DAI number 1038 * may be larger than the number of BE dailinks. 1039 */ 1040 static int get_dailink_info(struct device *dev, 1041 const struct snd_soc_acpi_link_adr *adr_link, 1042 int *sdw_be_num, int *sdw_cpu_dai_num, int *codecs_num) 1043 { 1044 bool group_visited[SDW_MAX_GROUPS]; 1045 bool no_aggregation; 1046 int i; 1047 int j; 1048 1049 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; 1050 *sdw_cpu_dai_num = 0; 1051 *sdw_be_num = 0; 1052 1053 if (!adr_link) 1054 return -EINVAL; 1055 1056 for (i = 0; i < SDW_MAX_GROUPS; i++) 1057 group_visited[i] = false; 1058 1059 for (; adr_link->num_adr; adr_link++) { 1060 const struct snd_soc_acpi_endpoint *endpoint; 1061 struct sof_sdw_codec_info *codec_info; 1062 int codec_index; 1063 int stream; 1064 u64 adr; 1065 1066 /* make sure the link mask has a single bit set */ 1067 if (!is_power_of_2(adr_link->mask)) 1068 return -EINVAL; 1069 1070 for (i = 0; i < adr_link->num_adr; i++) { 1071 adr = adr_link->adr_d[i].adr; 1072 codec_index = find_codec_info_part(adr); 1073 if (codec_index < 0) 1074 return codec_index; 1075 1076 codec_info = &codec_info_list[codec_index]; 1077 1078 *codecs_num += codec_info->dai_num; 1079 1080 if (!adr_link->adr_d[i].name_prefix) { 1081 dev_err(dev, "codec 0x%llx does not have a name prefix\n", 1082 adr_link->adr_d[i].adr); 1083 return -EINVAL; 1084 } 1085 1086 endpoint = adr_link->adr_d[i].endpoints; 1087 if (endpoint->aggregated && !endpoint->group_id) { 1088 dev_err(dev, "invalid group id on link %x\n", 1089 adr_link->mask); 1090 return -EINVAL; 1091 } 1092 1093 for (j = 0; j < codec_info->dai_num; j++) { 1094 /* count DAI number for playback and capture */ 1095 for_each_pcm_streams(stream) { 1096 if (!codec_info->dais[j].direction[stream]) 1097 continue; 1098 1099 (*sdw_cpu_dai_num)++; 1100 1101 /* count BE for each non-aggregated slave or group */ 1102 if (!endpoint->aggregated || no_aggregation || 1103 !group_visited[endpoint->group_id]) 1104 (*sdw_be_num)++; 1105 } 1106 } 1107 1108 if (endpoint->aggregated) 1109 group_visited[endpoint->group_id] = true; 1110 } 1111 } 1112 1113 return 0; 1114 } 1115 1116 static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, 1117 int be_id, char *name, int playback, int capture, 1118 struct snd_soc_dai_link_component *cpus, int cpus_num, 1119 struct snd_soc_dai_link_component *codecs, int codecs_num, 1120 int (*init)(struct snd_soc_pcm_runtime *rtd), 1121 const struct snd_soc_ops *ops) 1122 { 1123 dev_dbg(dev, "create dai link %s, id %d\n", name, be_id); 1124 dai_links->id = be_id; 1125 dai_links->name = name; 1126 dai_links->platforms = platform_component; 1127 dai_links->num_platforms = ARRAY_SIZE(platform_component); 1128 dai_links->no_pcm = 1; 1129 dai_links->cpus = cpus; 1130 dai_links->num_cpus = cpus_num; 1131 dai_links->codecs = codecs; 1132 dai_links->num_codecs = codecs_num; 1133 dai_links->dpcm_playback = playback; 1134 dai_links->dpcm_capture = capture; 1135 dai_links->init = init; 1136 dai_links->ops = ops; 1137 } 1138 1139 static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, 1140 unsigned int sdw_version, 1141 unsigned int mfg_id, 1142 unsigned int part_id, 1143 unsigned int class_id, 1144 int index_in_link) 1145 { 1146 int i; 1147 1148 for (i = 0; i < adr_link->num_adr; i++) { 1149 unsigned int sdw1_version, mfg1_id, part1_id, class1_id; 1150 u64 adr; 1151 1152 /* skip itself */ 1153 if (i == index_in_link) 1154 continue; 1155 1156 adr = adr_link->adr_d[i].adr; 1157 1158 sdw1_version = SDW_VERSION(adr); 1159 mfg1_id = SDW_MFG_ID(adr); 1160 part1_id = SDW_PART_ID(adr); 1161 class1_id = SDW_CLASS_ID(adr); 1162 1163 if (sdw_version == sdw1_version && 1164 mfg_id == mfg1_id && 1165 part_id == part1_id && 1166 class_id == class1_id) 1167 return false; 1168 } 1169 1170 return true; 1171 } 1172 1173 static int fill_sdw_codec_dlc(struct device *dev, 1174 const struct snd_soc_acpi_link_adr *adr_link, 1175 struct snd_soc_dai_link_component *codec, 1176 int adr_index, int dai_index) 1177 { 1178 unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id; 1179 u64 adr = adr_link->adr_d[adr_index].adr; 1180 int codec_index; 1181 1182 codec_index = find_codec_info_part(adr); 1183 if (codec_index < 0) 1184 return codec_index; 1185 1186 sdw_version = SDW_VERSION(adr); 1187 link_id = SDW_DISCO_LINK_ID(adr); 1188 unique_id = SDW_UNIQUE_ID(adr); 1189 mfg_id = SDW_MFG_ID(adr); 1190 part_id = SDW_PART_ID(adr); 1191 class_id = SDW_CLASS_ID(adr); 1192 1193 if (codec_info_list[codec_index].codec_name) 1194 codec->name = devm_kstrdup(dev, 1195 codec_info_list[codec_index].codec_name, 1196 GFP_KERNEL); 1197 else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, 1198 class_id, adr_index)) 1199 codec->name = devm_kasprintf(dev, GFP_KERNEL, 1200 "sdw:%01x:%04x:%04x:%02x", link_id, 1201 mfg_id, part_id, class_id); 1202 else 1203 codec->name = devm_kasprintf(dev, GFP_KERNEL, 1204 "sdw:%01x:%04x:%04x:%02x:%01x", link_id, 1205 mfg_id, part_id, class_id, unique_id); 1206 1207 if (!codec->name) 1208 return -ENOMEM; 1209 1210 codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; 1211 1212 return 0; 1213 } 1214 1215 static int set_codec_init_func(struct snd_soc_card *card, 1216 const struct snd_soc_acpi_link_adr *adr_link, 1217 struct snd_soc_dai_link *dai_links, 1218 bool playback, int group_id, int adr_index, int dai_index) 1219 { 1220 int i = adr_index; 1221 1222 do { 1223 /* 1224 * Initialize the codec. If codec is part of an aggregated 1225 * group (group_id>0), initialize all codecs belonging to 1226 * same group. 1227 * The first link should start with adr_link->adr_d[adr_index] 1228 * because that is the device that we want to initialize and 1229 * we should end immediately if it is not aggregated (group_id=0) 1230 */ 1231 for ( ; i < adr_link->num_adr; i++) { 1232 int codec_index; 1233 1234 codec_index = find_codec_info_part(adr_link->adr_d[i].adr); 1235 if (codec_index < 0) 1236 return codec_index; 1237 1238 /* The group_id is > 0 iff the codec is aggregated */ 1239 if (adr_link->adr_d[i].endpoints->group_id != group_id) 1240 continue; 1241 1242 if (codec_info_list[codec_index].dais[dai_index].init) 1243 codec_info_list[codec_index].dais[dai_index].init(card, 1244 adr_link, 1245 dai_links, 1246 &codec_info_list[codec_index], 1247 playback); 1248 if (!group_id) 1249 return 0; 1250 } 1251 1252 i = 0; 1253 adr_link++; 1254 } while (adr_link->mask); 1255 1256 return 0; 1257 } 1258 1259 /* 1260 * check endpoint status in slaves and gather link ID for all slaves in 1261 * the same group to generate different CPU DAI. Now only support 1262 * one sdw link with all slaves set with only single group id. 1263 * 1264 * one slave on one sdw link with aggregated = 0 1265 * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI 1266 * 1267 * two or more slaves on one sdw link with aggregated = 0 1268 * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs 1269 * 1270 * multiple links with multiple slaves with aggregated = 1 1271 * one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs 1272 */ 1273 static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, 1274 struct device *dev, int *cpu_dai_id, int *cpu_dai_num, 1275 int *codec_num, unsigned int *group_id, 1276 int adr_index) 1277 { 1278 bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; 1279 int i; 1280 1281 if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) { 1282 cpu_dai_id[0] = ffs(adr_link->mask) - 1; 1283 *cpu_dai_num = 1; 1284 *codec_num = 1; 1285 *group_id = 0; 1286 return 0; 1287 } 1288 1289 *codec_num = 0; 1290 *cpu_dai_num = 0; 1291 *group_id = adr_link->adr_d[adr_index].endpoints->group_id; 1292 1293 /* Count endpoints with the same group_id in the adr_link */ 1294 for (; adr_link && adr_link->num_adr; adr_link++) { 1295 unsigned int link_codecs = 0; 1296 1297 for (i = 0; i < adr_link->num_adr; i++) { 1298 if (adr_link->adr_d[i].endpoints->aggregated && 1299 adr_link->adr_d[i].endpoints->group_id == *group_id) 1300 link_codecs++; 1301 } 1302 1303 if (link_codecs) { 1304 *codec_num += link_codecs; 1305 1306 if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) { 1307 dev_err(dev, "cpu_dai_id array overflowed\n"); 1308 return -EINVAL; 1309 } 1310 1311 cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; 1312 } 1313 } 1314 1315 return 0; 1316 } 1317 1318 static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps, 1319 int codec_num, int cpu_num) 1320 { 1321 int step; 1322 int i; 1323 1324 step = codec_num / cpu_num; 1325 for (i = 0; i < codec_num; i++) 1326 sdw_codec_ch_maps[i].connected_cpu_id = i / step; 1327 } 1328 1329 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; 1330 1331 static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, 1332 struct snd_soc_dai_link *dai_links, 1333 int sdw_be_num, int sdw_cpu_dai_num, 1334 struct snd_soc_dai_link_component *cpus, 1335 const struct snd_soc_acpi_link_adr *adr_link, 1336 int *cpu_id, struct snd_soc_codec_conf *codec_conf, 1337 int codec_count, int *be_id, 1338 int *codec_conf_index, 1339 bool *ignore_pch_dmic, 1340 bool append_dai_type, 1341 int adr_index, 1342 int dai_index) 1343 { 1344 struct device *dev = card->dev; 1345 const struct snd_soc_acpi_link_adr *adr_link_next; 1346 struct snd_soc_dai_link_component *codecs; 1347 struct sof_sdw_codec_info *codec_info; 1348 int cpu_dai_id[SDW_MAX_CPU_DAIS]; 1349 int cpu_dai_num, cpu_dai_index; 1350 unsigned int group_id; 1351 int codec_dlc_index = 0; 1352 int codec_index; 1353 int codec_num; 1354 int stream; 1355 int i = 0; 1356 int j, k; 1357 int ret; 1358 1359 ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, 1360 &group_id, adr_index); 1361 if (ret) 1362 return ret; 1363 1364 codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL); 1365 if (!codecs) 1366 return -ENOMEM; 1367 1368 /* generate codec name on different links in the same group */ 1369 j = adr_index; 1370 for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && 1371 i < cpu_dai_num; adr_link_next++) { 1372 /* skip the link excluded by this processed group */ 1373 if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) 1374 continue; 1375 1376 /* j reset after loop, adr_index only applies to first link */ 1377 for (; j < adr_link_next->num_adr && codec_dlc_index < codec_num; j++) { 1378 const struct snd_soc_acpi_endpoint *endpoints; 1379 1380 endpoints = adr_link_next->adr_d[j].endpoints; 1381 1382 if (group_id && (!endpoints->aggregated || 1383 endpoints->group_id != group_id)) 1384 continue; 1385 1386 /* sanity check */ 1387 if (*codec_conf_index >= codec_count) { 1388 dev_err(dev, "codec_conf array overflowed\n"); 1389 return -EINVAL; 1390 } 1391 1392 ret = fill_sdw_codec_dlc(dev, adr_link_next, 1393 &codecs[codec_dlc_index], 1394 j, dai_index); 1395 if (ret) 1396 return ret; 1397 1398 codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index]; 1399 codec_conf[*codec_conf_index].name_prefix = 1400 adr_link_next->adr_d[j].name_prefix; 1401 1402 codec_dlc_index++; 1403 (*codec_conf_index)++; 1404 } 1405 j = 0; 1406 1407 /* check next link to create codec dai in the processed group */ 1408 i++; 1409 } 1410 1411 /* find codec info to create BE DAI */ 1412 codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr); 1413 if (codec_index < 0) 1414 return codec_index; 1415 codec_info = &codec_info_list[codec_index]; 1416 1417 if (codec_info->ignore_pch_dmic) 1418 *ignore_pch_dmic = true; 1419 1420 cpu_dai_index = *cpu_id; 1421 for_each_pcm_streams(stream) { 1422 struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps; 1423 char *name, *cpu_name; 1424 int playback, capture; 1425 static const char * const sdw_stream_name[] = { 1426 "SDW%d-Playback", 1427 "SDW%d-Capture", 1428 "SDW%d-Playback-%s", 1429 "SDW%d-Capture-%s", 1430 }; 1431 1432 if (!codec_info->dais[dai_index].direction[stream]) 1433 continue; 1434 1435 *be_id = codec_info->dais[dai_index].dailink[stream]; 1436 if (*be_id < 0) { 1437 dev_err(dev, "Invalid dailink id %d\n", *be_id); 1438 return -EINVAL; 1439 } 1440 1441 sdw_codec_ch_maps = devm_kcalloc(dev, codec_num, 1442 sizeof(*sdw_codec_ch_maps), GFP_KERNEL); 1443 if (!sdw_codec_ch_maps) 1444 return -ENOMEM; 1445 1446 /* create stream name according to first link id */ 1447 if (append_dai_type) { 1448 name = devm_kasprintf(dev, GFP_KERNEL, 1449 sdw_stream_name[stream + 2], cpu_dai_id[0], 1450 type_strings[codec_info->dais[dai_index].dai_type]); 1451 } else { 1452 name = devm_kasprintf(dev, GFP_KERNEL, 1453 sdw_stream_name[stream], cpu_dai_id[0]); 1454 } 1455 if (!name) 1456 return -ENOMEM; 1457 1458 /* 1459 * generate CPU DAI name base on the sdw link ID and 1460 * PIN ID with offset of 2 according to sdw dai driver. 1461 */ 1462 for (k = 0; k < cpu_dai_num; k++) { 1463 cpu_name = devm_kasprintf(dev, GFP_KERNEL, 1464 "SDW%d Pin%d", cpu_dai_id[k], 1465 sdw_pin_index[cpu_dai_id[k]]++); 1466 if (!cpu_name) 1467 return -ENOMEM; 1468 1469 if (cpu_dai_index >= sdw_cpu_dai_num) { 1470 dev_err(dev, "invalid cpu dai index %d\n", 1471 cpu_dai_index); 1472 return -EINVAL; 1473 } 1474 1475 cpus[cpu_dai_index++].dai_name = cpu_name; 1476 } 1477 1478 /* 1479 * We create sdw dai links at first stage, so link index should 1480 * not be larger than sdw_be_num 1481 */ 1482 if (*link_index >= sdw_be_num) { 1483 dev_err(dev, "invalid dai link index %d\n", *link_index); 1484 return -EINVAL; 1485 } 1486 1487 if (*cpu_id >= sdw_cpu_dai_num) { 1488 dev_err(dev, "invalid cpu dai index %d\n", *cpu_id); 1489 return -EINVAL; 1490 } 1491 1492 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); 1493 capture = (stream == SNDRV_PCM_STREAM_CAPTURE); 1494 init_dai_link(dev, dai_links + *link_index, (*be_id)++, name, 1495 playback, capture, 1496 cpus + *cpu_id, cpu_dai_num, 1497 codecs, codec_num, 1498 NULL, &sdw_ops); 1499 1500 /* 1501 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations 1502 * based on wait_for_completion(), tag them as 'nonatomic'. 1503 */ 1504 dai_links[*link_index].nonatomic = true; 1505 1506 set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); 1507 dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps; 1508 ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, 1509 playback, group_id, adr_index, dai_index); 1510 if (ret < 0) { 1511 dev_err(dev, "failed to init codec %d\n", codec_index); 1512 return ret; 1513 } 1514 1515 *cpu_id += cpu_dai_num; 1516 } 1517 1518 return 0; 1519 } 1520 1521 #define IDISP_CODEC_MASK 0x4 1522 1523 static int sof_card_dai_links_create(struct snd_soc_card *card) 1524 { 1525 struct device *dev = card->dev; 1526 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 1527 int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, hdmi_num = 0, bt_num = 0; 1528 struct mc_private *ctx = snd_soc_card_get_drvdata(card); 1529 struct snd_soc_dai_link_component *idisp_components; 1530 struct snd_soc_dai_link_component *ssp_components; 1531 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1532 const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; 1533 bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION); 1534 struct snd_soc_dai_link_component *cpus; 1535 struct snd_soc_codec_conf *codec_conf; 1536 bool append_dai_type = false; 1537 bool ignore_pch_dmic = false; 1538 int codec_conf_num = 0; 1539 int codec_conf_index = 0; 1540 bool group_generated[SDW_MAX_GROUPS] = { }; 1541 int ssp_codec_index, ssp_mask; 1542 struct snd_soc_dai_link *dai_links; 1543 int num_links, link_index = 0; 1544 char *name, *cpu_name; 1545 int total_cpu_dai_num; 1546 int sdw_cpu_dai_num; 1547 int i, j, be_id = 0; 1548 int codec_index; 1549 int cpu_id = 0; 1550 int ret; 1551 1552 ret = get_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num, 1553 &codec_conf_num); 1554 if (ret < 0) { 1555 dev_err(dev, "failed to get sdw link info %d\n", ret); 1556 return ret; 1557 } 1558 1559 /* 1560 * on generic tgl platform, I2S or sdw mode is supported 1561 * based on board rework. A ACPI device is registered in 1562 * system only when I2S mode is supported, not sdw mode. 1563 * Here check ACPI ID to confirm I2S is supported. 1564 */ 1565 ssp_codec_index = find_codec_info_acpi(mach->id); 1566 if (ssp_codec_index >= 0) { 1567 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); 1568 ssp_num = hweight_long(ssp_mask); 1569 } 1570 1571 if (mach_params->codec_mask & IDISP_CODEC_MASK) { 1572 ctx->idisp_codec = true; 1573 1574 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) 1575 hdmi_num = SOF_TGL_HDMI_COUNT; 1576 else 1577 hdmi_num = SOF_PRE_TGL_HDMI_COUNT; 1578 } 1579 1580 /* enable dmic01 & dmic16k */ 1581 if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) 1582 dmic_num = 2; 1583 1584 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) 1585 bt_num = 1; 1586 1587 dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", 1588 sdw_be_num, ssp_num, dmic_num, hdmi_num, bt_num); 1589 1590 /* allocate BE dailinks */ 1591 num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num; 1592 dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); 1593 if (!dai_links) 1594 return -ENOMEM; 1595 1596 /* allocated CPU DAIs */ 1597 total_cpu_dai_num = sdw_cpu_dai_num + ssp_num + dmic_num + hdmi_num + bt_num; 1598 cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL); 1599 if (!cpus) 1600 return -ENOMEM; 1601 1602 /* allocate codec conf, will be populated when dailinks are created */ 1603 codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf), 1604 GFP_KERNEL); 1605 if (!codec_conf) 1606 return -ENOMEM; 1607 1608 /* SDW */ 1609 if (!sdw_be_num) 1610 goto SSP; 1611 1612 for (i = 0; i < SDW_MAX_LINKS; i++) 1613 sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; 1614 1615 for (; adr_link->num_adr; adr_link++) { 1616 /* 1617 * If there are two or more different devices on the same sdw link, we have to 1618 * append the codec type to the dai link name to prevent duplicated dai link name. 1619 * The same type devices on the same sdw link will be in the same 1620 * snd_soc_acpi_adr_device array. They won't be described in different adr_links. 1621 */ 1622 for (i = 0; i < adr_link->num_adr; i++) { 1623 /* find codec info to get dai_num */ 1624 codec_index = find_codec_info_part(adr_link->adr_d[i].adr); 1625 if (codec_index < 0) 1626 return codec_index; 1627 if (codec_info_list[codec_index].dai_num > 1) { 1628 append_dai_type = true; 1629 goto out; 1630 } 1631 for (j = 0; j < i; j++) { 1632 if ((SDW_PART_ID(adr_link->adr_d[i].adr) != 1633 SDW_PART_ID(adr_link->adr_d[j].adr)) || 1634 (SDW_MFG_ID(adr_link->adr_d[i].adr) != 1635 SDW_MFG_ID(adr_link->adr_d[j].adr))) { 1636 append_dai_type = true; 1637 goto out; 1638 } 1639 } 1640 } 1641 } 1642 out: 1643 1644 /* generate DAI links by each sdw link */ 1645 for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) { 1646 for (i = 0; i < adr_link->num_adr; i++) { 1647 const struct snd_soc_acpi_endpoint *endpoint; 1648 1649 endpoint = adr_link->adr_d[i].endpoints; 1650 1651 /* this group has been generated */ 1652 if (endpoint->aggregated && 1653 group_generated[endpoint->group_id]) 1654 continue; 1655 1656 /* find codec info to get dai_num */ 1657 codec_index = find_codec_info_part(adr_link->adr_d[i].adr); 1658 if (codec_index < 0) 1659 return codec_index; 1660 1661 for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { 1662 ret = create_sdw_dailink(card, &link_index, dai_links, 1663 sdw_be_num, sdw_cpu_dai_num, cpus, 1664 adr_link, &cpu_id, 1665 codec_conf, codec_conf_num, 1666 &be_id, &codec_conf_index, 1667 &ignore_pch_dmic, append_dai_type, i, j); 1668 if (ret < 0) { 1669 dev_err(dev, "failed to create dai link %d\n", link_index); 1670 return ret; 1671 } 1672 } 1673 1674 if (aggregation && endpoint->aggregated) 1675 group_generated[endpoint->group_id] = true; 1676 } 1677 } 1678 1679 SSP: 1680 /* SSP */ 1681 if (!ssp_num) 1682 goto DMIC; 1683 1684 for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) { 1685 struct sof_sdw_codec_info *info; 1686 int playback, capture; 1687 char *codec_name; 1688 1689 if (!(ssp_mask & 0x1)) 1690 continue; 1691 1692 name = devm_kasprintf(dev, GFP_KERNEL, 1693 "SSP%d-Codec", i); 1694 if (!name) 1695 return -ENOMEM; 1696 1697 cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); 1698 if (!cpu_name) 1699 return -ENOMEM; 1700 1701 ssp_components = devm_kzalloc(dev, sizeof(*ssp_components), 1702 GFP_KERNEL); 1703 if (!ssp_components) 1704 return -ENOMEM; 1705 1706 info = &codec_info_list[ssp_codec_index]; 1707 codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", 1708 info->acpi_id, j++); 1709 if (!codec_name) 1710 return -ENOMEM; 1711 1712 ssp_components->name = codec_name; 1713 /* TODO: support multi codec dai on SSP when it is needed */ 1714 ssp_components->dai_name = info->dais[0].dai_name; 1715 cpus[cpu_id].dai_name = cpu_name; 1716 1717 playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; 1718 capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; 1719 init_dai_link(dev, dai_links + link_index, be_id, name, 1720 playback, capture, 1721 cpus + cpu_id, 1, 1722 ssp_components, 1, 1723 NULL, info->ops); 1724 1725 ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0); 1726 if (ret < 0) 1727 return ret; 1728 1729 INC_ID(be_id, cpu_id, link_index); 1730 } 1731 1732 DMIC: 1733 /* dmic */ 1734 if (dmic_num > 0) { 1735 if (ignore_pch_dmic) { 1736 dev_warn(dev, "Ignoring PCH DMIC\n"); 1737 goto HDMI; 1738 } 1739 cpus[cpu_id].dai_name = "DMIC01 Pin"; 1740 init_dai_link(dev, dai_links + link_index, be_id, "dmic01", 1741 0, 1, // DMIC only supports capture 1742 cpus + cpu_id, 1, 1743 dmic_component, 1, 1744 sof_sdw_dmic_init, NULL); 1745 INC_ID(be_id, cpu_id, link_index); 1746 1747 cpus[cpu_id].dai_name = "DMIC16k Pin"; 1748 init_dai_link(dev, dai_links + link_index, be_id, "dmic16k", 1749 0, 1, // DMIC only supports capture 1750 cpus + cpu_id, 1, 1751 dmic_component, 1, 1752 /* don't call sof_sdw_dmic_init() twice */ 1753 NULL, NULL); 1754 INC_ID(be_id, cpu_id, link_index); 1755 } 1756 1757 HDMI: 1758 /* HDMI */ 1759 if (hdmi_num > 0) { 1760 idisp_components = devm_kcalloc(dev, hdmi_num, 1761 sizeof(*idisp_components), 1762 GFP_KERNEL); 1763 if (!idisp_components) 1764 return -ENOMEM; 1765 } 1766 1767 for (i = 0; i < hdmi_num; i++) { 1768 name = devm_kasprintf(dev, GFP_KERNEL, 1769 "iDisp%d", i + 1); 1770 if (!name) 1771 return -ENOMEM; 1772 1773 if (ctx->idisp_codec) { 1774 idisp_components[i].name = "ehdaudio0D2"; 1775 idisp_components[i].dai_name = devm_kasprintf(dev, 1776 GFP_KERNEL, 1777 "intel-hdmi-hifi%d", 1778 i + 1); 1779 if (!idisp_components[i].dai_name) 1780 return -ENOMEM; 1781 } else { 1782 idisp_components[i] = asoc_dummy_dlc; 1783 } 1784 1785 cpu_name = devm_kasprintf(dev, GFP_KERNEL, 1786 "iDisp%d Pin", i + 1); 1787 if (!cpu_name) 1788 return -ENOMEM; 1789 1790 cpus[cpu_id].dai_name = cpu_name; 1791 init_dai_link(dev, dai_links + link_index, be_id, name, 1792 1, 0, // HDMI only supports playback 1793 cpus + cpu_id, 1, 1794 idisp_components + i, 1, 1795 sof_sdw_hdmi_init, NULL); 1796 INC_ID(be_id, cpu_id, link_index); 1797 } 1798 1799 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { 1800 int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> 1801 SOF_BT_OFFLOAD_SSP_SHIFT; 1802 1803 name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); 1804 if (!name) 1805 return -ENOMEM; 1806 1807 cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); 1808 if (!cpu_name) 1809 return -ENOMEM; 1810 1811 cpus[cpu_id].dai_name = cpu_name; 1812 init_dai_link(dev, dai_links + link_index, be_id, name, 1, 1, 1813 cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL); 1814 } 1815 1816 card->dai_link = dai_links; 1817 card->num_links = num_links; 1818 1819 card->codec_conf = codec_conf; 1820 card->num_configs = codec_conf_num; 1821 1822 return 0; 1823 } 1824 1825 static int sof_sdw_card_late_probe(struct snd_soc_card *card) 1826 { 1827 struct mc_private *ctx = snd_soc_card_get_drvdata(card); 1828 int ret = 0; 1829 int i; 1830 1831 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { 1832 if (codec_info_list[i].codec_card_late_probe) { 1833 ret = codec_info_list[i].codec_card_late_probe(card); 1834 1835 if (ret < 0) 1836 return ret; 1837 } 1838 } 1839 1840 if (ctx->idisp_codec) 1841 ret = sof_sdw_hdmi_card_late_probe(card); 1842 1843 return ret; 1844 } 1845 1846 /* SoC card */ 1847 static const char sdw_card_long_name[] = "Intel Soundwire SOF"; 1848 1849 static struct snd_soc_card card_sof_sdw = { 1850 .name = "soundwire", 1851 .owner = THIS_MODULE, 1852 .late_probe = sof_sdw_card_late_probe, 1853 }; 1854 1855 /* helper to get the link that the codec DAI is used */ 1856 static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card, 1857 const char *dai_name) 1858 { 1859 struct snd_soc_dai_link *dai_link; 1860 int i; 1861 int j; 1862 1863 for_each_card_prelinks(card, i, dai_link) { 1864 for (j = 0; j < dai_link->num_codecs; j++) { 1865 /* Check each codec in a link */ 1866 if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) 1867 return dai_link; 1868 } 1869 } 1870 return NULL; 1871 } 1872 1873 static void mc_dailink_exit_loop(struct snd_soc_card *card) 1874 { 1875 struct snd_soc_dai_link *dai_link; 1876 int ret; 1877 int i, j; 1878 1879 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { 1880 for (j = 0; j < codec_info_list[i].dai_num; j++) { 1881 /* Check each dai in codec_info_lis to see if it is used in the link */ 1882 if (!codec_info_list[i].dais[j].exit) 1883 continue; 1884 /* 1885 * We don't need to call .exit function if there is no matched 1886 * dai link found. 1887 */ 1888 dai_link = mc_find_codec_dai_used(card, 1889 codec_info_list[i].dais[j].dai_name); 1890 if (dai_link) { 1891 /* Do the .exit function if the codec dai is used in the link */ 1892 ret = codec_info_list[i].dais[j].exit(card, dai_link); 1893 if (ret) 1894 dev_warn(card->dev, 1895 "codec exit failed %d\n", 1896 ret); 1897 break; 1898 } 1899 } 1900 } 1901 } 1902 1903 static int mc_probe(struct platform_device *pdev) 1904 { 1905 struct snd_soc_card *card = &card_sof_sdw; 1906 struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); 1907 struct mc_private *ctx; 1908 int amp_num = 0, i; 1909 int ret; 1910 1911 card->dev = &pdev->dev; 1912 1913 dev_dbg(card->dev, "Entry\n"); 1914 1915 ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL); 1916 if (!ctx) 1917 return -ENOMEM; 1918 1919 INIT_LIST_HEAD(&ctx->hdmi_pcm_list); 1920 1921 snd_soc_card_set_drvdata(card, ctx); 1922 1923 dmi_check_system(sof_sdw_quirk_table); 1924 1925 if (quirk_override != -1) { 1926 dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", 1927 sof_sdw_quirk, quirk_override); 1928 sof_sdw_quirk = quirk_override; 1929 } 1930 1931 log_quirks(card->dev); 1932 1933 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ 1934 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1935 codec_info_list[i].amp_num = 0; 1936 1937 if (mach->mach_params.subsystem_id_set) { 1938 snd_soc_card_set_pci_ssid(card, 1939 mach->mach_params.subsystem_vendor, 1940 mach->mach_params.subsystem_device); 1941 } 1942 1943 ret = sof_card_dai_links_create(card); 1944 if (ret < 0) 1945 return ret; 1946 1947 /* 1948 * the default amp_num is zero for each codec and 1949 * amp_num will only be increased for active amp 1950 * codecs on used platform 1951 */ 1952 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1953 amp_num += codec_info_list[i].amp_num; 1954 1955 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 1956 "cfg-spk:%d cfg-amp:%d", 1957 (sof_sdw_quirk & SOF_SDW_FOUR_SPK) 1958 ? 4 : 2, amp_num); 1959 if (!card->components) 1960 return -ENOMEM; 1961 1962 if (mach->mach_params.dmic_num) { 1963 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 1964 "%s mic:dmic cfg-mics:%d", 1965 card->components, 1966 mach->mach_params.dmic_num); 1967 if (!card->components) 1968 return -ENOMEM; 1969 } 1970 1971 card->long_name = sdw_card_long_name; 1972 1973 /* Register the card */ 1974 ret = devm_snd_soc_register_card(card->dev, card); 1975 if (ret) { 1976 dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); 1977 mc_dailink_exit_loop(card); 1978 return ret; 1979 } 1980 1981 platform_set_drvdata(pdev, card); 1982 1983 return ret; 1984 } 1985 1986 static void mc_remove(struct platform_device *pdev) 1987 { 1988 struct snd_soc_card *card = platform_get_drvdata(pdev); 1989 1990 mc_dailink_exit_loop(card); 1991 } 1992 1993 static const struct platform_device_id mc_id_table[] = { 1994 { "sof_sdw", }, 1995 {} 1996 }; 1997 MODULE_DEVICE_TABLE(platform, mc_id_table); 1998 1999 static struct platform_driver sof_sdw_driver = { 2000 .driver = { 2001 .name = "sof_sdw", 2002 .pm = &snd_soc_pm_ops, 2003 }, 2004 .probe = mc_probe, 2005 .remove_new = mc_remove, 2006 .id_table = mc_id_table, 2007 }; 2008 2009 module_platform_driver(sof_sdw_driver); 2010 2011 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver"); 2012 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>"); 2013 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>"); 2014 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); 2015 MODULE_LICENSE("GPL v2"); 2016 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); 2017 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); 2018