1 // SPDX-License-Identifier: GPL-2.0-only 2 // This file incorporates work covered by the following copyright notice: 3 // Copyright (c) 2020 Intel Corporation 4 // Copyright(c) 2024 Advanced Micro Devices, Inc. 5 /* 6 * soc-sdw-utils.c - common SoundWire machine driver helper functions 7 */ 8 9 #include <linux/device.h> 10 #include <linux/module.h> 11 #include <linux/soundwire/sdw.h> 12 #include <linux/soundwire/sdw_type.h> 13 #include <sound/sdca_function.h> 14 #include <sound/soc_sdw_utils.h> 15 16 static const struct snd_soc_dapm_widget generic_dmic_widgets[] = { 17 SND_SOC_DAPM_MIC("DMIC", NULL), 18 }; 19 20 static const struct snd_soc_dapm_widget generic_jack_widgets[] = { 21 SND_SOC_DAPM_HP("Headphone", NULL), 22 SND_SOC_DAPM_MIC("Headset Mic", NULL), 23 }; 24 25 static const struct snd_kcontrol_new generic_jack_controls[] = { 26 SOC_DAPM_PIN_SWITCH("Headphone"), 27 SOC_DAPM_PIN_SWITCH("Headset Mic"), 28 }; 29 30 static const struct snd_soc_dapm_widget generic_spk_widgets[] = { 31 SND_SOC_DAPM_SPK("Speaker", NULL), 32 }; 33 34 static const struct snd_kcontrol_new generic_spk_controls[] = { 35 SOC_DAPM_PIN_SWITCH("Speaker"), 36 }; 37 38 static const struct snd_soc_dapm_widget lr_spk_widgets[] = { 39 SND_SOC_DAPM_SPK("Left Spk", NULL), 40 SND_SOC_DAPM_SPK("Right Spk", NULL), 41 }; 42 43 static const struct snd_soc_dapm_widget lr_4spk_widgets[] = { 44 SND_SOC_DAPM_SPK("Left Spk", NULL), 45 SND_SOC_DAPM_SPK("Right Spk", NULL), 46 SND_SOC_DAPM_SPK("Left Spk2", NULL), 47 SND_SOC_DAPM_SPK("Right Spk2", NULL), 48 }; 49 50 static const struct snd_kcontrol_new lr_spk_controls[] = { 51 SOC_DAPM_PIN_SWITCH("Left Spk"), 52 SOC_DAPM_PIN_SWITCH("Right Spk"), 53 }; 54 55 static const struct snd_kcontrol_new lr_4spk_controls[] = { 56 SOC_DAPM_PIN_SWITCH("Left Spk"), 57 SOC_DAPM_PIN_SWITCH("Right Spk"), 58 SOC_DAPM_PIN_SWITCH("Left Spk2"), 59 SOC_DAPM_PIN_SWITCH("Right Spk2"), 60 }; 61 62 static const struct snd_soc_dapm_widget rt700_widgets[] = { 63 SND_SOC_DAPM_HP("Headphones", NULL), 64 SND_SOC_DAPM_MIC("AMIC", NULL), 65 SND_SOC_DAPM_SPK("Speaker", NULL), 66 }; 67 68 static const struct snd_kcontrol_new rt700_controls[] = { 69 SOC_DAPM_PIN_SWITCH("Headphones"), 70 SOC_DAPM_PIN_SWITCH("AMIC"), 71 SOC_DAPM_PIN_SWITCH("Speaker"), 72 }; 73 74 struct asoc_sdw_codec_info codec_info_list[] = { 75 { 76 .vendor_id = 0x0102, 77 .part_id = 0x5572, 78 .name_prefix = "tac5572", 79 .dais = { 80 { 81 /* speaker */ 82 .direction = {true, false}, 83 .dai_name = "tac5xx2-aif1", 84 .dai_type = SOC_SDW_DAI_TYPE_AMP, 85 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 86 .init = asoc_sdw_ti_amp_init, 87 .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init, 88 .controls = lr_spk_controls, 89 .num_controls = ARRAY_SIZE(lr_spk_controls), 90 .widgets = lr_spk_widgets, 91 .num_widgets = ARRAY_SIZE(lr_spk_widgets), 92 }, 93 { 94 /* mic */ 95 .direction = {false, true}, 96 .dai_name = "tac5xx2-aif2", 97 .dai_type = SOC_SDW_DAI_TYPE_MIC, 98 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 99 .rtd_init = asoc_sdw_ti_dmic_rtd_init, 100 }, 101 { 102 /* UAJ */ 103 .direction = {true, true}, 104 .dai_name = "tac5xx2-aif3", 105 .dai_type = SOC_SDW_DAI_TYPE_JACK, 106 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 107 .controls = generic_jack_controls, 108 .num_controls = ARRAY_SIZE(generic_jack_controls), 109 .widgets = generic_jack_widgets, 110 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 111 .rtd_init = asoc_sdw_ti_sdca_jack_rtd_init, 112 }, 113 }, 114 .dai_num = 3, 115 }, 116 { 117 .vendor_id = 0x0102, 118 .part_id = 0x5672, 119 .name_prefix = "tac5672", 120 .dais = { 121 { 122 /* speaker with IV sense feedback */ 123 .direction = {true, true}, 124 .dai_name = "tac5xx2-aif1", 125 .dai_type = SOC_SDW_DAI_TYPE_AMP, 126 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 127 .init = asoc_sdw_ti_amp_init, 128 .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init, 129 .controls = lr_spk_controls, 130 .num_controls = ARRAY_SIZE(lr_spk_controls), 131 .widgets = lr_spk_widgets, 132 .num_widgets = ARRAY_SIZE(lr_spk_widgets), 133 }, 134 { 135 /* mic */ 136 .direction = {false, true}, 137 .dai_name = "tac5xx2-aif2", 138 .dai_type = SOC_SDW_DAI_TYPE_MIC, 139 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 140 .rtd_init = asoc_sdw_ti_dmic_rtd_init, 141 }, 142 { 143 /* UAJ */ 144 .direction = {true, true}, 145 .dai_name = "tac5xx2-aif3", 146 .dai_type = SOC_SDW_DAI_TYPE_JACK, 147 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 148 .controls = generic_jack_controls, 149 .num_controls = ARRAY_SIZE(generic_jack_controls), 150 .widgets = generic_jack_widgets, 151 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 152 .rtd_init = asoc_sdw_ti_sdca_jack_rtd_init, 153 }, 154 }, 155 .dai_num = 3, 156 }, 157 { 158 .vendor_id = 0x0102, 159 .part_id = 0x5682, 160 .name_prefix = "tac5682", 161 .dais = { 162 { 163 /* speaker with echo reference feedback */ 164 .direction = {true, true}, 165 .dai_name = "tac5xx2-aif1", 166 .dai_type = SOC_SDW_DAI_TYPE_AMP, 167 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 168 .init = asoc_sdw_ti_amp_init, 169 .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init, 170 .controls = lr_spk_controls, 171 .num_controls = ARRAY_SIZE(lr_spk_controls), 172 .widgets = lr_spk_widgets, 173 .num_widgets = ARRAY_SIZE(lr_spk_widgets), 174 }, 175 { 176 /* mic */ 177 .direction = {false, true}, 178 .dai_name = "tac5xx2-aif2", 179 .dai_type = SOC_SDW_DAI_TYPE_MIC, 180 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 181 .rtd_init = asoc_sdw_ti_dmic_rtd_init, 182 }, 183 { 184 /* UAJ */ 185 .direction = {true, true}, 186 .dai_name = "tac5xx2-aif3", 187 .dai_type = SOC_SDW_DAI_TYPE_JACK, 188 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 189 .controls = generic_jack_controls, 190 .num_controls = ARRAY_SIZE(generic_jack_controls), 191 .widgets = generic_jack_widgets, 192 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 193 .rtd_init = asoc_sdw_ti_sdca_jack_rtd_init, 194 }, 195 }, 196 .dai_num = 3, 197 }, 198 { 199 .vendor_id = 0x0102, 200 .part_id = 0x2883, 201 .name_prefix = "tas2883", 202 .dais = { 203 { 204 .direction = {true, false}, 205 .dai_name = "tac5xx2-aif1", 206 .dai_type = SOC_SDW_DAI_TYPE_AMP, 207 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 208 .init = asoc_sdw_ti_amp_init, 209 .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init, 210 .controls = lr_spk_controls, 211 .num_controls = ARRAY_SIZE(lr_spk_controls), 212 .widgets = lr_spk_widgets, 213 .num_widgets = ARRAY_SIZE(lr_spk_widgets), 214 }, 215 { 216 /* mic */ 217 .direction = {false, true}, 218 .dai_name = "tac5xx2-aif2", 219 .dai_type = SOC_SDW_DAI_TYPE_MIC, 220 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 221 .rtd_init = asoc_sdw_ti_dmic_rtd_init, 222 }, 223 }, 224 .dai_num = 2, 225 }, 226 { 227 .vendor_id = 0x0102, 228 .part_id = 0x0000, /* TAS2783A */ 229 .name_prefix = "tas2783", 230 .is_amp = true, 231 .dais = { 232 { 233 .direction = {true, true}, 234 .dai_name = "tas2783-codec", 235 .component_name = "tas2783", 236 .dai_type = SOC_SDW_DAI_TYPE_AMP, 237 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 238 .init = asoc_sdw_ti_amp_init, 239 .rtd_init = asoc_sdw_ti_spk_rtd_init, 240 .controls = lr_4spk_controls, 241 .num_controls = ARRAY_SIZE(lr_4spk_controls), 242 .widgets = lr_4spk_widgets, 243 .num_widgets = ARRAY_SIZE(lr_4spk_widgets), 244 }, 245 }, 246 .dai_num = 1, 247 }, 248 { 249 .vendor_id = 0x025d, 250 .part_id = 0x700, 251 .name_prefix = "rt700", 252 .dais = { 253 { 254 .direction = {true, true}, 255 .dai_name = "rt700-aif1", 256 .dai_type = SOC_SDW_DAI_TYPE_JACK, 257 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 258 .rtd_init = asoc_sdw_rt700_rtd_init, 259 .controls = rt700_controls, 260 .num_controls = ARRAY_SIZE(rt700_controls), 261 .widgets = rt700_widgets, 262 .num_widgets = ARRAY_SIZE(rt700_widgets), 263 }, 264 }, 265 .dai_num = 1, 266 }, 267 { 268 .vendor_id = 0x025d, 269 .part_id = 0x711, 270 .name_prefix = "rt711", 271 .version_id = 3, 272 .dais = { 273 { 274 .direction = {true, true}, 275 .dai_name = "rt711-sdca-aif1", 276 .dai_type = SOC_SDW_DAI_TYPE_JACK, 277 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 278 .init = asoc_sdw_rt_sdca_jack_init, 279 .exit = asoc_sdw_rt_sdca_jack_exit, 280 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 281 .controls = generic_jack_controls, 282 .num_controls = ARRAY_SIZE(generic_jack_controls), 283 .widgets = generic_jack_widgets, 284 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 285 }, 286 }, 287 .dai_num = 1, 288 }, 289 { 290 .vendor_id = 0x025d, 291 .part_id = 0x711, 292 .name_prefix = "rt711", 293 .version_id = 2, 294 .dais = { 295 { 296 .direction = {true, true}, 297 .dai_name = "rt711-aif1", 298 .dai_type = SOC_SDW_DAI_TYPE_JACK, 299 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 300 .init = asoc_sdw_rt711_init, 301 .exit = asoc_sdw_rt711_exit, 302 .rtd_init = asoc_sdw_rt711_rtd_init, 303 .controls = generic_jack_controls, 304 .num_controls = ARRAY_SIZE(generic_jack_controls), 305 .widgets = generic_jack_widgets, 306 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 307 }, 308 }, 309 .dai_num = 1, 310 }, 311 { 312 .vendor_id = 0x025d, 313 .part_id = 0x712, 314 .name_prefix = "rt712", 315 .version_id = 3, 316 .dais = { 317 { 318 .direction = {true, true}, 319 .dai_name = "rt712-sdca-aif1", 320 .dai_type = SOC_SDW_DAI_TYPE_JACK, 321 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 322 .init = asoc_sdw_rt_sdca_jack_init, 323 .exit = asoc_sdw_rt_sdca_jack_exit, 324 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 325 .controls = generic_jack_controls, 326 .num_controls = ARRAY_SIZE(generic_jack_controls), 327 .widgets = generic_jack_widgets, 328 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 329 }, 330 { 331 .direction = {true, false}, 332 .dai_name = "rt712-sdca-aif2", 333 .component_name = "rt712", 334 .dai_type = SOC_SDW_DAI_TYPE_AMP, 335 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 336 .init = asoc_sdw_rt_amp_init, 337 .exit = asoc_sdw_rt_amp_exit, 338 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, 339 .controls = generic_spk_controls, 340 .num_controls = ARRAY_SIZE(generic_spk_controls), 341 .widgets = generic_spk_widgets, 342 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 343 }, 344 { 345 .direction = {false, true}, 346 .dai_name = "rt712-sdca-aif3", 347 .dai_type = SOC_SDW_DAI_TYPE_MIC, 348 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 349 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 350 .quirk = SOC_SDW_CODEC_MIC, 351 .quirk_exclude = true, 352 }, 353 }, 354 .dai_num = 3, 355 }, 356 { 357 .vendor_id = 0x025d, 358 .part_id = 0x1712, 359 .name_prefix = "rt712-dmic", 360 .version_id = 3, 361 .dais = { 362 { 363 .direction = {false, true}, 364 .dai_name = "rt712-sdca-dmic-aif1", 365 .dai_type = SOC_SDW_DAI_TYPE_MIC, 366 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 367 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 368 }, 369 }, 370 .dai_num = 1, 371 }, 372 { 373 .vendor_id = 0x025d, 374 .part_id = 0x713, 375 .name_prefix = "rt713", 376 .version_id = 3, 377 .dais = { 378 { 379 .direction = {true, true}, 380 .dai_name = "rt712-sdca-aif1", 381 .dai_type = SOC_SDW_DAI_TYPE_JACK, 382 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 383 .init = asoc_sdw_rt_sdca_jack_init, 384 .exit = asoc_sdw_rt_sdca_jack_exit, 385 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 386 .controls = generic_jack_controls, 387 .num_controls = ARRAY_SIZE(generic_jack_controls), 388 .widgets = generic_jack_widgets, 389 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 390 }, 391 { 392 .direction = {false, true}, 393 .dai_name = "rt712-sdca-aif3", 394 .dai_type = SOC_SDW_DAI_TYPE_MIC, 395 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 396 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 397 }, 398 }, 399 .dai_num = 2, 400 }, 401 { 402 .vendor_id = 0x025d, 403 .part_id = 0x1713, 404 .name_prefix = "rt713-dmic", 405 .version_id = 3, 406 .dais = { 407 { 408 .direction = {false, true}, 409 .dai_name = "rt712-sdca-dmic-aif1", 410 .dai_type = SOC_SDW_DAI_TYPE_MIC, 411 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 412 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 413 }, 414 }, 415 .dai_num = 1, 416 }, 417 { 418 .vendor_id = 0x025d, 419 .part_id = 0x1308, 420 .name_prefix = "rt1308", 421 .acpi_id = "10EC1308", 422 .is_amp = true, 423 .dais = { 424 { 425 .direction = {true, false}, 426 .dai_name = "rt1308-aif", 427 .component_name = "rt1308", 428 .dai_type = SOC_SDW_DAI_TYPE_AMP, 429 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 430 .init = asoc_sdw_rt_amp_init, 431 .exit = asoc_sdw_rt_amp_exit, 432 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 433 .controls = generic_spk_controls, 434 .num_controls = ARRAY_SIZE(generic_spk_controls), 435 .widgets = generic_spk_widgets, 436 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 437 }, 438 }, 439 .dai_num = 1, 440 .ops = &soc_sdw_rt1308_i2s_ops, 441 }, 442 { 443 .vendor_id = 0x025d, 444 .part_id = 0x1316, 445 .name_prefix = "rt1316", 446 .is_amp = true, 447 .dais = { 448 { 449 .direction = {true, true}, 450 .dai_name = "rt1316-aif", 451 .component_name = "rt1316", 452 .dai_type = SOC_SDW_DAI_TYPE_AMP, 453 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 454 .init = asoc_sdw_rt_amp_init, 455 .exit = asoc_sdw_rt_amp_exit, 456 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 457 .controls = generic_spk_controls, 458 .num_controls = ARRAY_SIZE(generic_spk_controls), 459 .widgets = generic_spk_widgets, 460 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 461 }, 462 }, 463 .dai_num = 1, 464 }, 465 { 466 .vendor_id = 0x025d, 467 .part_id = 0x1318, 468 .name_prefix = "rt1318", 469 .is_amp = true, 470 .dais = { 471 { 472 .direction = {true, true}, 473 .dai_name = "rt1318-aif", 474 .component_name = "rt1318", 475 .dai_type = SOC_SDW_DAI_TYPE_AMP, 476 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 477 .init = asoc_sdw_rt_amp_init, 478 .exit = asoc_sdw_rt_amp_exit, 479 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 480 .controls = generic_spk_controls, 481 .num_controls = ARRAY_SIZE(generic_spk_controls), 482 .widgets = generic_spk_widgets, 483 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 484 }, 485 }, 486 .dai_num = 1, 487 }, 488 { 489 .vendor_id = 0x025d, 490 .part_id = 0x1320, 491 .name_prefix = "rt1320", 492 .is_amp = true, 493 .dais = { 494 { 495 .direction = {true, false}, 496 .dai_name = "rt1320-aif1", 497 .component_name = "rt1320", 498 .dai_type = SOC_SDW_DAI_TYPE_AMP, 499 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 500 .init = asoc_sdw_rt_amp_init, 501 .exit = asoc_sdw_rt_amp_exit, 502 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 503 .controls = generic_spk_controls, 504 .num_controls = ARRAY_SIZE(generic_spk_controls), 505 .widgets = generic_spk_widgets, 506 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 507 }, 508 { 509 .direction = {false, true}, 510 .dai_name = "rt1320-aif2", 511 .component_name = "rt1320", 512 .dai_type = SOC_SDW_DAI_TYPE_MIC, 513 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 514 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 515 .widgets = generic_dmic_widgets, 516 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 517 }, 518 }, 519 .dai_num = 2, 520 }, 521 { 522 .vendor_id = 0x025d, 523 .part_id = 0x1321, 524 .name_prefix = "rt1320", 525 .is_amp = true, 526 .dais = { 527 { 528 .direction = {true, false}, 529 .dai_name = "rt1320-aif1", 530 .component_name = "rt1320", 531 .dai_type = SOC_SDW_DAI_TYPE_AMP, 532 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 533 .init = asoc_sdw_rt_amp_init, 534 .exit = asoc_sdw_rt_amp_exit, 535 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 536 .controls = generic_spk_controls, 537 .num_controls = ARRAY_SIZE(generic_spk_controls), 538 .widgets = generic_spk_widgets, 539 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 540 }, 541 { 542 .direction = {false, true}, 543 .dai_name = "rt1320-aif2", 544 .component_name = "rt1320", 545 .dai_type = SOC_SDW_DAI_TYPE_MIC, 546 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 547 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 548 .widgets = generic_dmic_widgets, 549 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 550 }, 551 }, 552 .dai_num = 2, 553 }, 554 { 555 .vendor_id = 0x025d, 556 .part_id = 0x714, 557 .name_prefix = "rt714", 558 .version_id = 3, 559 .ignore_internal_dmic = true, 560 .dais = { 561 { 562 .direction = {false, true}, 563 .dai_name = "rt715-sdca-aif2", 564 .dai_type = SOC_SDW_DAI_TYPE_MIC, 565 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 566 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 567 }, 568 }, 569 .dai_num = 1, 570 }, 571 { 572 .vendor_id = 0x025d, 573 .part_id = 0x715, 574 .name_prefix = "rt715", 575 .version_id = 3, 576 .ignore_internal_dmic = true, 577 .dais = { 578 { 579 .direction = {false, true}, 580 .dai_name = "rt715-sdca-aif2", 581 .dai_type = SOC_SDW_DAI_TYPE_MIC, 582 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 583 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 584 }, 585 }, 586 .dai_num = 1, 587 }, 588 { 589 .vendor_id = 0x025d, 590 .part_id = 0x714, 591 .name_prefix = "rt714", 592 .version_id = 2, 593 .ignore_internal_dmic = true, 594 .dais = { 595 { 596 .direction = {false, true}, 597 .dai_name = "rt715-aif2", 598 .dai_type = SOC_SDW_DAI_TYPE_MIC, 599 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 600 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 601 }, 602 }, 603 .dai_num = 1, 604 }, 605 { 606 .vendor_id = 0x025d, 607 .part_id = 0x715, 608 .name_prefix = "rt715", 609 .version_id = 2, 610 .ignore_internal_dmic = true, 611 .dais = { 612 { 613 .direction = {false, true}, 614 .dai_name = "rt715-aif2", 615 .dai_type = SOC_SDW_DAI_TYPE_MIC, 616 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 617 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 618 }, 619 }, 620 .dai_num = 1, 621 }, 622 { 623 .vendor_id = 0x025d, 624 .part_id = 0x721, 625 .name_prefix = "rt721", 626 .version_id = 3, 627 .dais = { 628 { 629 .direction = {true, true}, 630 .dai_name = "rt721-sdca-aif1", 631 .dai_type = SOC_SDW_DAI_TYPE_JACK, 632 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 633 .init = asoc_sdw_rt_sdca_jack_init, 634 .exit = asoc_sdw_rt_sdca_jack_exit, 635 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 636 .controls = generic_jack_controls, 637 .num_controls = ARRAY_SIZE(generic_jack_controls), 638 .widgets = generic_jack_widgets, 639 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 640 }, 641 { 642 .direction = {true, false}, 643 .dai_name = "rt721-sdca-aif2", 644 .component_name = "rt721", 645 .dai_type = SOC_SDW_DAI_TYPE_AMP, 646 /* No feedback capability is provided by rt721-sdca codec driver*/ 647 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 648 .init = asoc_sdw_rt_amp_init, 649 .exit = asoc_sdw_rt_amp_exit, 650 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, 651 .controls = generic_spk_controls, 652 .num_controls = ARRAY_SIZE(generic_spk_controls), 653 .widgets = generic_spk_widgets, 654 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 655 }, 656 { 657 .direction = {false, true}, 658 .dai_name = "rt721-sdca-aif3", 659 .dai_type = SOC_SDW_DAI_TYPE_MIC, 660 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 661 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 662 .quirk = SOC_SDW_CODEC_MIC, 663 .quirk_exclude = true, 664 }, 665 }, 666 .dai_num = 3, 667 }, 668 { 669 .vendor_id = 0x025d, 670 .part_id = 0x722, 671 .name_prefix = "rt722", 672 .version_id = 3, 673 .dais = { 674 { 675 .direction = {true, true}, 676 .dai_name = "rt722-sdca-aif1", 677 .dai_type = SOC_SDW_DAI_TYPE_JACK, 678 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 679 .init = asoc_sdw_rt_sdca_jack_init, 680 .exit = asoc_sdw_rt_sdca_jack_exit, 681 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 682 .controls = generic_jack_controls, 683 .num_controls = ARRAY_SIZE(generic_jack_controls), 684 .widgets = generic_jack_widgets, 685 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 686 }, 687 { 688 .direction = {true, false}, 689 .dai_name = "rt722-sdca-aif2", 690 .component_name = "rt722", 691 .dai_type = SOC_SDW_DAI_TYPE_AMP, 692 /* No feedback capability is provided by rt722-sdca codec driver*/ 693 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 694 .init = asoc_sdw_rt_amp_init, 695 .exit = asoc_sdw_rt_amp_exit, 696 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, 697 .controls = generic_spk_controls, 698 .num_controls = ARRAY_SIZE(generic_spk_controls), 699 .widgets = generic_spk_widgets, 700 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 701 .quirk = SOC_SDW_CODEC_SPKR, 702 .quirk_exclude = true, 703 }, 704 { 705 .direction = {false, true}, 706 .dai_name = "rt722-sdca-aif3", 707 .dai_type = SOC_SDW_DAI_TYPE_MIC, 708 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 709 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 710 .quirk = SOC_SDW_CODEC_MIC, 711 .quirk_exclude = true, 712 }, 713 }, 714 .dai_num = 3, 715 }, 716 { 717 .vendor_id = 0x019f, 718 .part_id = 0x8373, 719 .name_prefix = "Left", 720 .is_amp = true, 721 .dais = { 722 { 723 .direction = {true, true}, 724 .dai_name = "max98373-aif1", 725 .component_name = "mx8373", 726 .dai_type = SOC_SDW_DAI_TYPE_AMP, 727 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 728 .init = asoc_sdw_maxim_init, 729 .rtd_init = asoc_sdw_maxim_spk_rtd_init, 730 .controls = lr_spk_controls, 731 .num_controls = ARRAY_SIZE(lr_spk_controls), 732 .widgets = lr_spk_widgets, 733 .num_widgets = ARRAY_SIZE(lr_spk_widgets), 734 }, 735 }, 736 .dai_num = 1, 737 }, 738 { 739 .vendor_id = 0x019f, 740 .part_id = 0x8363, 741 .name_prefix = "Left", 742 .is_amp = true, 743 .dais = { 744 { 745 .direction = {true, false}, 746 .dai_name = "max98363-aif1", 747 .component_name = "mx8363", 748 .dai_type = SOC_SDW_DAI_TYPE_AMP, 749 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 750 .init = asoc_sdw_maxim_init, 751 .rtd_init = asoc_sdw_maxim_spk_rtd_init, 752 .controls = lr_spk_controls, 753 .num_controls = ARRAY_SIZE(lr_spk_controls), 754 .widgets = lr_spk_widgets, 755 .num_widgets = ARRAY_SIZE(lr_spk_widgets), 756 }, 757 }, 758 .dai_num = 1, 759 }, 760 { 761 .vendor_id = 0x025d, 762 .part_id = 0x5682, 763 .name_prefix = "rt5682", 764 .dais = { 765 { 766 .direction = {true, true}, 767 .dai_name = "rt5682-sdw", 768 .dai_type = SOC_SDW_DAI_TYPE_JACK, 769 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 770 .rtd_init = asoc_sdw_rt5682_rtd_init, 771 .controls = generic_jack_controls, 772 .num_controls = ARRAY_SIZE(generic_jack_controls), 773 .widgets = generic_jack_widgets, 774 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 775 }, 776 }, 777 .dai_num = 1, 778 }, 779 { 780 .vendor_id = 0x01fa, 781 .part_id = 0x3556, 782 .name_prefix = "AMP", 783 .is_amp = true, 784 .dais = { 785 { 786 .direction = {true, false}, 787 .dai_name = "cs35l56-sdw1", 788 .component_name = "cs35l56", 789 .dai_type = SOC_SDW_DAI_TYPE_AMP, 790 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 791 .init = asoc_sdw_cs_amp_init, 792 .rtd_init = asoc_sdw_cs_spk_rtd_init, 793 .controls = generic_spk_controls, 794 .num_controls = ARRAY_SIZE(generic_spk_controls), 795 .widgets = generic_spk_widgets, 796 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 797 }, 798 { 799 .direction = {false, true}, 800 .dai_name = "cs35l56-sdw1c", 801 .dai_type = SOC_SDW_DAI_TYPE_AMP, 802 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 803 .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, 804 }, 805 }, 806 .dai_num = 2, 807 }, 808 { 809 .vendor_id = 0x01fa, 810 .part_id = 0x3557, 811 .name_prefix = "AMP", 812 .is_amp = true, 813 .dais = { 814 { 815 .direction = {true, false}, 816 .dai_name = "cs35l56-sdw1", 817 .component_name = "cs35l56", 818 .dai_type = SOC_SDW_DAI_TYPE_AMP, 819 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 820 .init = asoc_sdw_cs_amp_init, 821 .rtd_init = asoc_sdw_cs_spk_rtd_init, 822 .controls = generic_spk_controls, 823 .num_controls = ARRAY_SIZE(generic_spk_controls), 824 .widgets = generic_spk_widgets, 825 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 826 }, 827 { 828 .direction = {false, true}, 829 .dai_name = "cs35l56-sdw1c", 830 .dai_type = SOC_SDW_DAI_TYPE_AMP, 831 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 832 .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, 833 }, 834 }, 835 .dai_num = 2, 836 }, 837 { 838 .vendor_id = 0x01fa, 839 .part_id = 0x3563, 840 .name_prefix = "AMP", 841 .is_amp = true, 842 .dais = { 843 { 844 .direction = {true, false}, 845 .dai_name = "cs35l56-sdw1", 846 .component_name = "cs35l56", 847 .dai_type = SOC_SDW_DAI_TYPE_AMP, 848 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 849 .init = asoc_sdw_cs_amp_init, 850 .rtd_init = asoc_sdw_cs_spk_rtd_init, 851 .controls = generic_spk_controls, 852 .num_controls = ARRAY_SIZE(generic_spk_controls), 853 .widgets = generic_spk_widgets, 854 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 855 }, 856 { 857 .direction = {false, true}, 858 .dai_name = "cs35l56-sdw1c", 859 .dai_type = SOC_SDW_DAI_TYPE_AMP, 860 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 861 .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, 862 }, 863 }, 864 .dai_num = 2, 865 }, 866 { 867 .vendor_id = 0x01fa, 868 .part_id = 0x4242, 869 .name_prefix = "cs42l42", 870 .dais = { 871 { 872 .direction = {true, true}, 873 .dai_name = "cs42l42-sdw", 874 .dai_type = SOC_SDW_DAI_TYPE_JACK, 875 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 876 .rtd_init = asoc_sdw_cs42l42_rtd_init, 877 .controls = generic_jack_controls, 878 .num_controls = ARRAY_SIZE(generic_jack_controls), 879 .widgets = generic_jack_widgets, 880 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 881 }, 882 }, 883 .dai_num = 1, 884 }, 885 { 886 .vendor_id = 0x01fa, 887 .part_id = 0x4243, 888 .name_prefix = "cs42l43", 889 .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, 890 .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, 891 .dais = { 892 { 893 .direction = {true, false}, 894 .codec_name = "cs42l43-codec", 895 .dai_name = "cs42l43-dp5", 896 .dai_type = SOC_SDW_DAI_TYPE_JACK, 897 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 898 .rtd_init = asoc_sdw_cs42l43_hs_rtd_init, 899 .controls = generic_jack_controls, 900 .num_controls = ARRAY_SIZE(generic_jack_controls), 901 .widgets = generic_jack_widgets, 902 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 903 }, 904 { 905 .direction = {false, true}, 906 .codec_name = "cs42l43-codec", 907 .dai_name = "cs42l43-dp1", 908 .dai_type = SOC_SDW_DAI_TYPE_MIC, 909 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 910 .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, 911 .widgets = generic_dmic_widgets, 912 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 913 .quirk = SOC_SDW_CODEC_MIC, 914 .quirk_exclude = true, 915 }, 916 { 917 .direction = {false, true}, 918 .codec_name = "cs42l43-codec", 919 .dai_name = "cs42l43-dp2", 920 .dai_type = SOC_SDW_DAI_TYPE_JACK, 921 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 922 }, 923 { 924 .direction = {true, false}, 925 .codec_name = "cs42l43-codec", 926 .component_name = "cs42l43-spk", 927 .dai_name = "cs42l43-dp6", 928 .dai_type = SOC_SDW_DAI_TYPE_AMP, 929 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 930 .init = asoc_sdw_cs42l43_spk_init, 931 .rtd_init = asoc_sdw_cs42l43_spk_rtd_init, 932 .controls = generic_spk_controls, 933 .num_controls = ARRAY_SIZE(generic_spk_controls), 934 .widgets = generic_spk_widgets, 935 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 936 .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS, 937 }, 938 }, 939 .dai_num = 4, 940 }, 941 { 942 .vendor_id = 0x01fa, 943 .part_id = 0x2A3B, 944 .name_prefix = "cs42l43", 945 .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, 946 .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, 947 .dais = { 948 { 949 .direction = {true, false}, 950 .codec_name = "cs42l43-codec", 951 .dai_name = "cs42l43-dp5", 952 .dai_type = SOC_SDW_DAI_TYPE_JACK, 953 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 954 .rtd_init = asoc_sdw_cs42l43_hs_rtd_init, 955 .controls = generic_jack_controls, 956 .num_controls = ARRAY_SIZE(generic_jack_controls), 957 .widgets = generic_jack_widgets, 958 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 959 }, 960 { 961 .direction = {false, true}, 962 .codec_name = "cs42l43-codec", 963 .dai_name = "cs42l43-dp1", 964 .dai_type = SOC_SDW_DAI_TYPE_MIC, 965 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 966 .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, 967 .widgets = generic_dmic_widgets, 968 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 969 .quirk = SOC_SDW_CODEC_MIC, 970 .quirk_exclude = true, 971 }, 972 { 973 .direction = {false, true}, 974 .codec_name = "cs42l43-codec", 975 .dai_name = "cs42l43-dp2", 976 .dai_type = SOC_SDW_DAI_TYPE_JACK, 977 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 978 }, 979 { 980 .direction = {true, false}, 981 .codec_name = "cs42l43-codec", 982 .component_name = "cs42l43-spk", 983 .dai_name = "cs42l43-dp6", 984 .dai_type = SOC_SDW_DAI_TYPE_AMP, 985 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 986 .init = asoc_sdw_cs42l43_spk_init, 987 .rtd_init = asoc_sdw_cs42l43_spk_rtd_init, 988 .controls = generic_spk_controls, 989 .num_controls = ARRAY_SIZE(generic_spk_controls), 990 .widgets = generic_spk_widgets, 991 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 992 .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS, 993 }, 994 }, 995 .dai_num = 4, 996 }, 997 { 998 .vendor_id = 0x01fa, 999 .part_id = 0x4245, 1000 .name_prefix = "cs42l45", 1001 .dais = { 1002 { 1003 .direction = {true, false}, 1004 .codec_name = "snd_soc_sdca.UAJ", 1005 .dai_name = "IT 41", 1006 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1007 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1008 .rtd_init = asoc_sdw_cs42l45_hs_rtd_init, 1009 }, 1010 { 1011 .direction = {false, true}, 1012 .codec_name = "snd_soc_sdca.SmartMic", 1013 .dai_name = "OT 113", 1014 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1015 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1016 .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init, 1017 }, 1018 { 1019 .direction = {false, true}, 1020 .codec_name = "snd_soc_sdca.UAJ", 1021 .dai_name = "OT 36", 1022 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1023 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1024 }, 1025 }, 1026 .dai_num = 3, 1027 .auxs = { 1028 { 1029 .codec_name = "snd_soc_sdca.HID", 1030 }, 1031 }, 1032 .aux_num = 1, 1033 }, 1034 { 1035 .vendor_id = 0x01fa, 1036 .part_id = 0x4249, 1037 .name_prefix = "cs42l45", /* Use same user-space as cs42l45 */ 1038 .dais = { 1039 { 1040 .direction = {true, false}, 1041 .codec_name = "snd_soc_sdca.UAJ", 1042 .dai_name = "IT 41", 1043 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1044 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1045 .rtd_init = asoc_sdw_cs42l45_hs_rtd_init, 1046 }, 1047 { 1048 .direction = {false, true}, 1049 .codec_name = "snd_soc_sdca.SmartMic", 1050 .dai_name = "OT 113", 1051 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1052 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1053 .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init, 1054 }, 1055 { 1056 .direction = {false, true}, 1057 .codec_name = "snd_soc_sdca.UAJ", 1058 .dai_name = "OT 36", 1059 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1060 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1061 }, 1062 }, 1063 .dai_num = 3, 1064 .auxs = { 1065 { 1066 .codec_name = "snd_soc_sdca.HID", 1067 }, 1068 }, 1069 .aux_num = 1, 1070 }, 1071 { 1072 .vendor_id = 0x01fa, 1073 .part_id = 0x4747, 1074 .name_prefix = "cs47l47", 1075 .dais = { 1076 { 1077 .direction = {true, false}, 1078 .codec_name = "snd_soc_sdca.UAJ", 1079 .dai_name = "IT 41", 1080 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1081 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1082 .rtd_init = asoc_sdw_cs47l47_hs_rtd_init, 1083 }, 1084 { 1085 .direction = {false, true}, 1086 .codec_name = "snd_soc_sdca.SmartMic", 1087 .dai_name = "OT 113", 1088 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1089 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1090 .rtd_init = asoc_sdw_cs47l47_dmic_rtd_init, 1091 }, 1092 { 1093 .direction = {false, true}, 1094 .codec_name = "snd_soc_sdca.UAJ", 1095 .dai_name = "OT 36", 1096 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1097 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1098 }, 1099 }, 1100 .dai_num = 3, 1101 .auxs = { 1102 { 1103 .codec_name = "snd_soc_sdca.HID", 1104 }, 1105 }, 1106 .aux_num = 1, 1107 }, 1108 { 1109 .vendor_id = 0x04b3, 1110 .part_id = 0x9356, 1111 .name_prefix = "es9356", 1112 .version_id = 3, 1113 .dais = { 1114 { 1115 .direction = {true, false}, 1116 .dai_name = "es9356-sdp-aif1", 1117 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1118 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1119 .init = asoc_sdw_es9356_init, 1120 .exit = asoc_sdw_es9356_exit, 1121 .rtd_init = asoc_sdw_es9356_rtd_init, 1122 .controls = generic_jack_controls, 1123 .num_controls = ARRAY_SIZE(generic_jack_controls), 1124 .widgets = generic_jack_widgets, 1125 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 1126 }, 1127 { 1128 .direction = {false, true}, 1129 .dai_name = "es9356-sdp-aif4", 1130 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1131 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1132 .rtd_init = asoc_sdw_es9356_dmic_rtd_init, 1133 .widgets = generic_dmic_widgets, 1134 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 1135 }, 1136 { 1137 .direction = {false, true}, 1138 .dai_name = "es9356-sdp-aif2", 1139 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1140 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1141 }, 1142 { 1143 .direction = {true, false}, 1144 .dai_name = "es9356-sdp-aif3", 1145 .component_name = "es9356", 1146 .dai_type = SOC_SDW_DAI_TYPE_AMP, 1147 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1148 .init = asoc_sdw_es9356_amp_init, 1149 .rtd_init = asoc_sdw_es9356_spk_rtd_init, 1150 .controls = generic_spk_controls, 1151 .num_controls = ARRAY_SIZE(generic_spk_controls), 1152 .widgets = generic_spk_widgets, 1153 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 1154 }, 1155 }, 1156 .dai_num = 4, 1157 }, 1158 { 1159 .vendor_id = 0x0105, 1160 .part_id = 0xaaaa, /* generic codec mockup */ 1161 .name_prefix = "sdw_mockup_mmulti-function", 1162 .version_id = 0, 1163 .dais = { 1164 { 1165 .direction = {true, true}, 1166 .dai_name = "sdw-mockup-aif1", 1167 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1168 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1169 }, 1170 { 1171 .direction = {true, false}, 1172 .dai_name = "sdw-mockup-aif1", 1173 .dai_type = SOC_SDW_DAI_TYPE_AMP, 1174 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1175 }, 1176 { 1177 .direction = {false, true}, 1178 .dai_name = "sdw-mockup-aif1", 1179 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1180 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1181 }, 1182 }, 1183 .dai_num = 3, 1184 }, 1185 { 1186 .vendor_id = 0x0105, 1187 .part_id = 0xaa55, /* headset codec mockup */ 1188 .name_prefix = "sdw_mockup_headset0", 1189 .version_id = 0, 1190 .dais = { 1191 { 1192 .direction = {true, true}, 1193 .dai_name = "sdw-mockup-aif1", 1194 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1195 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1196 }, 1197 }, 1198 .dai_num = 1, 1199 }, 1200 { 1201 .vendor_id = 0x0105, 1202 .part_id = 0x55aa, /* amplifier mockup */ 1203 .name_prefix = "sdw_mockup_amp1", 1204 .is_amp = true, 1205 .version_id = 0, 1206 .dais = { 1207 { 1208 .direction = {true, true}, 1209 .dai_name = "sdw-mockup-aif1", 1210 .dai_type = SOC_SDW_DAI_TYPE_AMP, 1211 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 1212 }, 1213 }, 1214 .dai_num = 1, 1215 }, 1216 { 1217 .vendor_id = 0x0105, 1218 .part_id = 0x5555, 1219 .name_prefix = "sdw_mockup_mic0", 1220 .version_id = 0, 1221 .dais = { 1222 { 1223 .dai_name = "sdw-mockup-aif1", 1224 .direction = {false, true}, 1225 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1226 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1227 }, 1228 }, 1229 .dai_num = 1, 1230 }, 1231 }; 1232 EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS"); 1233 1234 int asoc_sdw_get_codec_info_list_count(void) 1235 { 1236 return ARRAY_SIZE(codec_info_list); 1237 }; 1238 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS"); 1239 1240 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr) 1241 { 1242 unsigned int vendor_id, part_id, sdw_version; 1243 int i; 1244 1245 vendor_id = SDW_MFG_ID(adr); 1246 part_id = SDW_PART_ID(adr); 1247 sdw_version = SDW_VERSION(adr); 1248 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1249 /* 1250 * A codec info is for all sdw version with the part id if 1251 * version_id is not specified in the codec info. 1252 */ 1253 if (part_id == codec_info_list[i].part_id && 1254 vendor_id == codec_info_list[i].vendor_id && 1255 (!codec_info_list[i].version_id || 1256 sdw_version == codec_info_list[i].version_id)) 1257 return &codec_info_list[i]; 1258 1259 return NULL; 1260 } 1261 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS"); 1262 1263 static struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_sdw_id(const struct sdw_slave_id *id) 1264 { 1265 int i; 1266 1267 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1268 if (id->part_id == codec_info_list[i].part_id && 1269 id->mfg_id == codec_info_list[i].vendor_id && 1270 (!codec_info_list[i].version_id || 1271 id->sdw_version == codec_info_list[i].version_id)) 1272 return &codec_info_list[i]; 1273 1274 return NULL; 1275 } 1276 1277 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id) 1278 { 1279 int i; 1280 1281 if (!acpi_id[0]) 1282 return NULL; 1283 1284 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1285 if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) 1286 return &codec_info_list[i]; 1287 1288 return NULL; 1289 } 1290 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, "SND_SOC_SDW_UTILS"); 1291 1292 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index) 1293 { 1294 int i, j; 1295 1296 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { 1297 for (j = 0; j < codec_info_list[i].dai_num; j++) { 1298 if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { 1299 *dai_index = j; 1300 return &codec_info_list[i]; 1301 } 1302 } 1303 } 1304 1305 return NULL; 1306 } 1307 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS"); 1308 1309 static int asoc_sdw_find_codec_info_dai_index(const struct asoc_sdw_codec_info *codec_info, 1310 const char *dai_name) 1311 { 1312 int i; 1313 1314 for (i = 0; i < codec_info->dai_num; i++) { 1315 if (!strcmp(codec_info->dais[i].dai_name, dai_name)) 1316 return i; 1317 } 1318 1319 return -ENOENT; 1320 } 1321 1322 int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) 1323 { 1324 struct snd_soc_card *card = rtd->card; 1325 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1326 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); 1327 struct asoc_sdw_codec_info *codec_info; 1328 struct snd_soc_dai *dai; 1329 struct sdw_slave *sdw_peripheral; 1330 const char *spk_components = NULL; 1331 int dai_index; 1332 int ret; 1333 int i; 1334 1335 for_each_rtd_codec_dais(rtd, i, dai) { 1336 if (is_sdw_slave(dai->component->dev)) 1337 sdw_peripheral = dev_to_sdw_dev(dai->component->dev); 1338 else if (dai->component->dev->parent && is_sdw_slave(dai->component->dev->parent)) 1339 sdw_peripheral = dev_to_sdw_dev(dai->component->dev->parent); 1340 else 1341 continue; 1342 1343 codec_info = asoc_sdw_find_codec_info_sdw_id(&sdw_peripheral->id); 1344 if (!codec_info) 1345 return -EINVAL; 1346 1347 dai_index = asoc_sdw_find_codec_info_dai_index(codec_info, dai->name); 1348 WARN_ON(dai_index < 0); 1349 1350 /* 1351 * A codec dai can be connected to different dai links for capture and playback, 1352 * but we only need to call the rtd_init function once. 1353 * The rtd_init for each codec dai is independent. So, the order of rtd_init 1354 * doesn't matter. 1355 */ 1356 if (codec_info->dais[dai_index].rtd_init_done) 1357 continue; 1358 1359 dev_dbg(card->dev, "%#x/%s initializing for %s/%s\n", 1360 codec_info->part_id, codec_info->dais[dai_index].dai_name, 1361 dai->component->name, dai->name); 1362 1363 /* 1364 * Add card controls and dapm widgets for the first codec dai. 1365 * The controls and widgets will be used for all codec dais. 1366 */ 1367 1368 if (i > 0) 1369 goto skip_add_controls_widgets; 1370 1371 if (codec_info->dais[dai_index].controls) { 1372 ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls, 1373 codec_info->dais[dai_index].num_controls); 1374 if (ret) { 1375 dev_err(card->dev, "%#x-%#x controls addition failed: %d\n", 1376 codec_info->vendor_id, codec_info->part_id, ret); 1377 return ret; 1378 } 1379 } 1380 if (codec_info->dais[dai_index].widgets) { 1381 ret = snd_soc_dapm_new_controls(dapm, 1382 codec_info->dais[dai_index].widgets, 1383 codec_info->dais[dai_index].num_widgets); 1384 if (ret) { 1385 dev_err(card->dev, "%#x-%#x widgets addition failed: %d\n", 1386 codec_info->vendor_id, codec_info->part_id, ret); 1387 return ret; 1388 } 1389 } 1390 1391 skip_add_controls_widgets: 1392 if (codec_info->dais[dai_index].rtd_init) { 1393 ret = codec_info->dais[dai_index].rtd_init(rtd, dai); 1394 if (ret) 1395 return ret; 1396 } 1397 1398 /* Generate the spk component string for card->components string */ 1399 if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP && 1400 codec_info->dais[dai_index].component_name) { 1401 const char *component; 1402 1403 /* 1404 * For the special case of cs42l43 with sidecar amps, use only 1405 * "cs35l56-bridge" as the component name in card->components 1406 */ 1407 if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS && 1408 !strcmp(codec_info->dais[dai_index].component_name, "cs42l43-spk")) 1409 component = "cs35l56-bridge"; 1410 else 1411 component = codec_info->dais[dai_index].component_name; 1412 1413 if (!spk_components) 1414 spk_components = 1415 devm_kasprintf(card->dev, GFP_KERNEL, "%s", component); 1416 else 1417 /* Append component name to spk_components */ 1418 spk_components = 1419 devm_kasprintf(card->dev, GFP_KERNEL, 1420 "%s+%s", spk_components, component); 1421 1422 if (!spk_components) 1423 return -ENOMEM; 1424 } 1425 1426 codec_info->dais[dai_index].rtd_init_done = true; 1427 } 1428 1429 if (spk_components) { 1430 /* Update card components for speaker components */ 1431 card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s", 1432 card->components, spk_components); 1433 if (!card->components) 1434 return -ENOMEM; 1435 } 1436 1437 return 0; 1438 } 1439 EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, "SND_SOC_SDW_UTILS"); 1440 1441 /* these wrappers are only needed to avoid typecast compilation errors */ 1442 int asoc_sdw_startup(struct snd_pcm_substream *substream) 1443 { 1444 return sdw_startup_stream(substream); 1445 } 1446 EXPORT_SYMBOL_NS(asoc_sdw_startup, "SND_SOC_SDW_UTILS"); 1447 1448 int asoc_sdw_prepare(struct snd_pcm_substream *substream) 1449 { 1450 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 1451 struct sdw_stream_runtime *sdw_stream; 1452 struct snd_soc_dai *dai; 1453 1454 /* Find stream from first CPU DAI */ 1455 dai = snd_soc_rtd_to_cpu(rtd, 0); 1456 1457 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 1458 if (IS_ERR(sdw_stream)) { 1459 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 1460 return PTR_ERR(sdw_stream); 1461 } 1462 1463 return sdw_prepare_stream(sdw_stream); 1464 } 1465 EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS"); 1466 1467 int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd) 1468 { 1469 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 1470 struct sdw_stream_runtime *sdw_stream; 1471 struct snd_soc_dai *dai; 1472 int ret; 1473 1474 /* Find stream from first CPU DAI */ 1475 dai = snd_soc_rtd_to_cpu(rtd, 0); 1476 1477 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 1478 if (IS_ERR(sdw_stream)) { 1479 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 1480 return PTR_ERR(sdw_stream); 1481 } 1482 1483 switch (cmd) { 1484 case SNDRV_PCM_TRIGGER_START: 1485 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1486 case SNDRV_PCM_TRIGGER_RESUME: 1487 ret = sdw_enable_stream(sdw_stream); 1488 break; 1489 1490 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1491 case SNDRV_PCM_TRIGGER_SUSPEND: 1492 case SNDRV_PCM_TRIGGER_STOP: 1493 ret = sdw_disable_stream(sdw_stream); 1494 break; 1495 default: 1496 ret = -EINVAL; 1497 break; 1498 } 1499 1500 if (ret) 1501 dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); 1502 1503 return ret; 1504 } 1505 EXPORT_SYMBOL_NS(asoc_sdw_trigger, "SND_SOC_SDW_UTILS"); 1506 1507 int asoc_sdw_hw_params(struct snd_pcm_substream *substream, 1508 struct snd_pcm_hw_params *params) 1509 { 1510 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 1511 struct snd_soc_dai_link_ch_map *ch_maps; 1512 int ch = params_channels(params); 1513 unsigned int ch_mask; 1514 int num_codecs; 1515 int step; 1516 int i; 1517 1518 if (!rtd->dai_link->ch_maps) 1519 return 0; 1520 1521 /* Identical data will be sent to all codecs in playback */ 1522 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1523 ch_mask = GENMASK(ch - 1, 0); 1524 step = 0; 1525 } else { 1526 num_codecs = rtd->dai_link->num_codecs; 1527 1528 if (ch < num_codecs || ch % num_codecs != 0) { 1529 dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", 1530 ch, num_codecs); 1531 return -EINVAL; 1532 } 1533 1534 ch_mask = GENMASK(ch / num_codecs - 1, 0); 1535 step = hweight_long(ch_mask); 1536 } 1537 1538 /* 1539 * The captured data will be combined from each cpu DAI if the dai 1540 * link has more than one codec DAIs. Set codec channel mask and 1541 * ASoC will set the corresponding channel numbers for each cpu dai. 1542 */ 1543 for_each_link_ch_maps(rtd->dai_link, i, ch_maps) 1544 ch_maps->ch_mask = ch_mask << (i * step); 1545 1546 return 0; 1547 } 1548 EXPORT_SYMBOL_NS(asoc_sdw_hw_params, "SND_SOC_SDW_UTILS"); 1549 1550 int asoc_sdw_hw_free(struct snd_pcm_substream *substream) 1551 { 1552 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 1553 struct sdw_stream_runtime *sdw_stream; 1554 struct snd_soc_dai *dai; 1555 1556 /* Find stream from first CPU DAI */ 1557 dai = snd_soc_rtd_to_cpu(rtd, 0); 1558 1559 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 1560 if (IS_ERR(sdw_stream)) { 1561 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 1562 return PTR_ERR(sdw_stream); 1563 } 1564 1565 return sdw_deprepare_stream(sdw_stream); 1566 } 1567 EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS"); 1568 1569 void asoc_sdw_shutdown(struct snd_pcm_substream *substream) 1570 { 1571 sdw_shutdown_stream(substream); 1572 } 1573 EXPORT_SYMBOL_NS(asoc_sdw_shutdown, "SND_SOC_SDW_UTILS"); 1574 1575 static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, 1576 unsigned int sdw_version, 1577 unsigned int mfg_id, 1578 unsigned int part_id, 1579 unsigned int class_id, 1580 int index_in_link) 1581 { 1582 int i; 1583 1584 for (i = 0; i < adr_link->num_adr; i++) { 1585 unsigned int sdw1_version, mfg1_id, part1_id, class1_id; 1586 u64 adr; 1587 1588 /* skip itself */ 1589 if (i == index_in_link) 1590 continue; 1591 1592 adr = adr_link->adr_d[i].adr; 1593 1594 sdw1_version = SDW_VERSION(adr); 1595 mfg1_id = SDW_MFG_ID(adr); 1596 part1_id = SDW_PART_ID(adr); 1597 class1_id = SDW_CLASS_ID(adr); 1598 1599 if (sdw_version == sdw1_version && 1600 mfg_id == mfg1_id && 1601 part_id == part1_id && 1602 class_id == class1_id) 1603 return false; 1604 } 1605 1606 return true; 1607 } 1608 1609 static const char *_asoc_sdw_get_codec_name(struct device *dev, 1610 const struct snd_soc_acpi_link_adr *adr_link, 1611 int adr_index) 1612 { 1613 u64 adr = adr_link->adr_d[adr_index].adr; 1614 unsigned int sdw_version = SDW_VERSION(adr); 1615 unsigned int link_id = SDW_DISCO_LINK_ID(adr); 1616 unsigned int unique_id = SDW_UNIQUE_ID(adr); 1617 unsigned int mfg_id = SDW_MFG_ID(adr); 1618 unsigned int part_id = SDW_PART_ID(adr); 1619 unsigned int class_id = SDW_CLASS_ID(adr); 1620 1621 if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id, 1622 class_id, adr_index)) 1623 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", 1624 link_id, mfg_id, part_id, class_id); 1625 1626 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", 1627 link_id, mfg_id, part_id, class_id, unique_id); 1628 } 1629 1630 const char *asoc_sdw_get_codec_name(struct device *dev, 1631 const struct asoc_sdw_dai_info *dai_info, 1632 const struct snd_soc_acpi_link_adr *adr_link, 1633 int adr_index) 1634 { 1635 if (dai_info->codec_name) { 1636 struct snd_soc_component *component; 1637 1638 component = snd_soc_lookup_component_by_name(dai_info->codec_name); 1639 if (component) { 1640 dev_dbg(dev, "%s found component %s for codec_name %s\n", 1641 __func__, component->name, dai_info->codec_name); 1642 return devm_kstrdup(dev, component->name, GFP_KERNEL); 1643 } else { 1644 dev_dbg(dev, "%s component %s is not registered yet\n", 1645 __func__, dai_info->codec_name); 1646 return ERR_PTR(-EPROBE_DEFER); 1647 } 1648 } 1649 1650 return _asoc_sdw_get_codec_name(dev, adr_link, adr_index); 1651 } 1652 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS"); 1653 1654 /* helper to get the link that the codec DAI is used */ 1655 struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card, 1656 const char *dai_name) 1657 { 1658 struct snd_soc_dai_link *dai_link; 1659 int i; 1660 int j; 1661 1662 for_each_card_prelinks(card, i, dai_link) { 1663 for (j = 0; j < dai_link->num_codecs; j++) { 1664 /* Check each codec in a link */ 1665 if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) 1666 return dai_link; 1667 } 1668 } 1669 return NULL; 1670 } 1671 EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, "SND_SOC_SDW_UTILS"); 1672 1673 void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card) 1674 { 1675 struct snd_soc_dai_link *dai_link; 1676 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1677 int ret; 1678 int i, j; 1679 1680 for (i = 0; i < ctx->codec_info_list_count; i++) { 1681 for (j = 0; j < codec_info_list[i].dai_num; j++) { 1682 codec_info_list[i].dais[j].rtd_init_done = false; 1683 /* Check each dai in codec_info_lis to see if it is used in the link */ 1684 if (!codec_info_list[i].dais[j].exit) 1685 continue; 1686 /* 1687 * We don't need to call .exit function if there is no matched 1688 * dai link found. 1689 */ 1690 dai_link = asoc_sdw_mc_find_codec_dai_used(card, 1691 codec_info_list[i].dais[j].dai_name); 1692 if (dai_link) { 1693 /* Do the .exit function if the codec dai is used in the link */ 1694 ret = codec_info_list[i].dais[j].exit(card, dai_link); 1695 if (ret) 1696 dev_warn(card->dev, 1697 "codec exit failed %d\n", 1698 ret); 1699 break; 1700 } 1701 } 1702 } 1703 } 1704 EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, "SND_SOC_SDW_UTILS"); 1705 1706 int asoc_sdw_card_late_probe(struct snd_soc_card *card) 1707 { 1708 int ret = 0; 1709 int i; 1710 1711 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { 1712 if (codec_info_list[i].codec_card_late_probe) { 1713 ret = codec_info_list[i].codec_card_late_probe(card); 1714 if (ret < 0) 1715 return ret; 1716 } 1717 } 1718 return ret; 1719 } 1720 EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, "SND_SOC_SDW_UTILS"); 1721 1722 void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, 1723 int *be_id, char *name, int playback, int capture, 1724 struct snd_soc_dai_link_component *cpus, int cpus_num, 1725 struct snd_soc_dai_link_component *platform_component, 1726 int num_platforms, struct snd_soc_dai_link_component *codecs, 1727 int codecs_num, int no_pcm, 1728 int (*init)(struct snd_soc_pcm_runtime *rtd), 1729 const struct snd_soc_ops *ops) 1730 { 1731 dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); 1732 dai_links->id = (*be_id)++; 1733 dai_links->name = name; 1734 dai_links->stream_name = name; 1735 dai_links->platforms = platform_component; 1736 dai_links->num_platforms = num_platforms; 1737 dai_links->no_pcm = no_pcm; 1738 dai_links->cpus = cpus; 1739 dai_links->num_cpus = cpus_num; 1740 dai_links->codecs = codecs; 1741 dai_links->num_codecs = codecs_num; 1742 dai_links->playback_only = playback && !capture; 1743 dai_links->capture_only = !playback && capture; 1744 dai_links->init = init; 1745 dai_links->ops = ops; 1746 } 1747 EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, "SND_SOC_SDW_UTILS"); 1748 1749 int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, 1750 int *be_id, char *name, int playback, int capture, 1751 const char *cpu_dai_name, const char *platform_comp_name, 1752 const char *codec_name, const char *codec_dai_name, 1753 int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd), 1754 const struct snd_soc_ops *ops) 1755 { 1756 struct snd_soc_dai_link_component *dlc; 1757 1758 /* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */ 1759 dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL); 1760 if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name) 1761 return -ENOMEM; 1762 1763 dlc[0].dai_name = cpu_dai_name; 1764 dlc[1].name = platform_comp_name; 1765 1766 dlc[2].name = codec_name; 1767 dlc[2].dai_name = codec_dai_name; 1768 1769 asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture, 1770 &dlc[0], 1, &dlc[1], 1, &dlc[2], 1, 1771 no_pcm, init, ops); 1772 1773 return 0; 1774 } 1775 EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS"); 1776 1777 /** 1778 * is_sdca_aux_dev_present - Check if an SDCA aux device is present on the SDW peripheral 1779 * @dev: Device pointer 1780 * @aux_codec_name: Aux codec name from the codec info (e.g. "snd_soc_sdca.HID.2") 1781 * @adr_link: ACPI link address 1782 * @adr_index: Index of the ACPI link address 1783 * 1784 * Return: 1 if the aux is present, 0 if the aux is not present, or negative error code. 1785 */ 1786 static int is_sdca_aux_dev_present(struct device *dev, 1787 const char *aux_codec_name, 1788 const struct snd_soc_acpi_link_adr *adr_link, 1789 int adr_index) 1790 { 1791 struct sdw_slave *slave; 1792 struct device *sdw_dev; 1793 const char *sdw_codec_name; 1794 int ret = 0; 1795 int i; 1796 1797 if (!aux_codec_name) 1798 return 0; 1799 1800 sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index); 1801 if (!sdw_codec_name) 1802 return -ENOMEM; 1803 1804 sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); 1805 if (!sdw_dev) { 1806 dev_err(dev, "codec %s not found\n", sdw_codec_name); 1807 return -EINVAL; 1808 } 1809 1810 slave = dev_to_sdw_dev(sdw_dev); 1811 1812 if (!slave->sdca_data.interface_revision) { 1813 dev_warn(dev, "No SDCA properties, assuming aux '%s' present\n", aux_codec_name); 1814 ret = 1; 1815 goto put_dev; 1816 } 1817 1818 for (i = 0; i < slave->sdca_data.num_functions; i++) { 1819 const char *fname = slave->sdca_data.function[i].name; 1820 1821 if (fname && strstr(aux_codec_name, fname)) { 1822 ret = 1; 1823 goto put_dev; 1824 } 1825 } 1826 1827 dev_dbg(dev, "SDCA function for aux '%s' NOT FOUND on slave, skipping\n", aux_codec_name); 1828 1829 put_dev: 1830 put_device(sdw_dev); 1831 return ret; 1832 } 1833 1834 int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, 1835 int *num_devs, int *num_ends, int *num_aux) 1836 { 1837 struct device *dev = card->dev; 1838 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); 1839 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1840 const struct snd_soc_acpi_link_adr *adr_link; 1841 int i, j, ret; 1842 1843 for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { 1844 *num_devs += adr_link->num_adr; 1845 1846 for (i = 0; i < adr_link->num_adr; i++) { 1847 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; 1848 struct asoc_sdw_codec_info *codec_info; 1849 1850 *num_ends += adr_dev->num_endpoints; 1851 1852 codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); 1853 if (!codec_info) 1854 return -EINVAL; 1855 1856 for (j = 0; j < codec_info->aux_num; j++) { 1857 ret = is_sdca_aux_dev_present(dev, codec_info->auxs[j].codec_name, 1858 adr_link, i); 1859 if (ret < 0) 1860 return ret; 1861 if (ret) 1862 (*num_aux)++; 1863 } 1864 } 1865 } 1866 1867 dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); 1868 1869 return 0; 1870 } 1871 EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, "SND_SOC_SDW_UTILS"); 1872 1873 struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, 1874 const struct snd_soc_acpi_endpoint *new) 1875 { 1876 while (dailinks->initialised) { 1877 if (new->aggregated && dailinks->group_id == new->group_id) 1878 return dailinks; 1879 1880 dailinks++; 1881 } 1882 1883 INIT_LIST_HEAD(&dailinks->endpoints); 1884 dailinks->group_id = new->group_id; 1885 dailinks->initialised = true; 1886 1887 return dailinks; 1888 } 1889 EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS"); 1890 1891 int asoc_sdw_get_dai_type(u32 type) 1892 { 1893 switch (type) { 1894 case SDCA_FUNCTION_TYPE_SMART_AMP: 1895 case SDCA_FUNCTION_TYPE_SIMPLE_AMP: 1896 case SDCA_FUNCTION_TYPE_COMPANION_AMP: 1897 return SOC_SDW_DAI_TYPE_AMP; 1898 case SDCA_FUNCTION_TYPE_SMART_MIC: 1899 case SDCA_FUNCTION_TYPE_SIMPLE_MIC: 1900 case SDCA_FUNCTION_TYPE_SPEAKER_MIC: 1901 return SOC_SDW_DAI_TYPE_MIC; 1902 case SDCA_FUNCTION_TYPE_UAJ: 1903 case SDCA_FUNCTION_TYPE_RJ: 1904 case SDCA_FUNCTION_TYPE_SIMPLE_JACK: 1905 return SOC_SDW_DAI_TYPE_JACK; 1906 default: 1907 return -EINVAL; 1908 } 1909 } 1910 EXPORT_SYMBOL_NS(asoc_sdw_get_dai_type, "SND_SOC_SDW_UTILS"); 1911 1912 /** 1913 * is_sdca_endpoint_present - Check if an SDCA endpoint is present on the SDW peripheral 1914 * @dev: Device pointer 1915 * @codec_info: Codec info pointer 1916 * @adr_link: ACPI link address 1917 * @adr_index: Index of the ACPI link address 1918 * @end_index: Index of the endpoint 1919 * 1920 * Return: 1 if the endpoint is present, 0 if the endpoint is not present, or negative error code. 1921 */ 1922 static int is_sdca_endpoint_present(struct device *dev, 1923 struct asoc_sdw_codec_info *codec_info, 1924 const struct snd_soc_acpi_link_adr *adr_link, 1925 int adr_index, int end_index) 1926 { 1927 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index]; 1928 const struct snd_soc_acpi_endpoint *adr_end; 1929 const struct asoc_sdw_dai_info *dai_info; 1930 struct sdw_slave *slave; 1931 struct device *sdw_dev; 1932 const char *sdw_codec_name; 1933 int ret, i; 1934 1935 adr_end = &adr_dev->endpoints[end_index]; 1936 dai_info = &codec_info->dais[adr_end->num]; 1937 1938 sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index); 1939 if (!sdw_codec_name) 1940 return -ENOMEM; 1941 1942 sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); 1943 if (!sdw_dev) { 1944 dev_err(dev, "codec %s not found\n", sdw_codec_name); 1945 return -EINVAL; 1946 } 1947 1948 slave = dev_to_sdw_dev(sdw_dev); 1949 1950 /* Make sure BIOS provides SDCA properties */ 1951 if (!slave->sdca_data.interface_revision) { 1952 dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n"); 1953 ret = 1; 1954 goto put_device; 1955 } 1956 1957 for (i = 0; i < slave->sdca_data.num_functions; i++) { 1958 int dai_type = asoc_sdw_get_dai_type(slave->sdca_data.function[i].type); 1959 1960 if (dai_type == dai_info->dai_type) { 1961 dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n", 1962 dai_type, slave->sdca_data.function[i].name); 1963 ret = 1; 1964 goto put_device; 1965 } 1966 } 1967 1968 dev_dbg(&slave->dev, 1969 "SDCA device function for DAI type %d not supported, skip endpoint\n", 1970 dai_info->dai_type); 1971 1972 ret = 0; 1973 1974 put_device: 1975 put_device(sdw_dev); 1976 return ret; 1977 } 1978 1979 int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, 1980 struct snd_soc_aux_dev *soc_aux, 1981 struct asoc_sdw_dailink *soc_dais, 1982 struct asoc_sdw_endpoint *soc_ends, 1983 int *num_devs) 1984 { 1985 struct device *dev = card->dev; 1986 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1987 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); 1988 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1989 const struct snd_soc_acpi_link_adr *adr_link; 1990 struct asoc_sdw_endpoint *soc_end = soc_ends; 1991 int num_dais = 0; 1992 int i, j; 1993 int ret; 1994 1995 for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { 1996 int num_link_dailinks = 0; 1997 1998 if (!is_power_of_2(adr_link->mask)) { 1999 dev_err(dev, "link with multiple mask bits: 0x%x\n", 2000 adr_link->mask); 2001 return -EINVAL; 2002 } 2003 2004 for (i = 0; i < adr_link->num_adr; i++) { 2005 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; 2006 struct asoc_sdw_codec_info *codec_info; 2007 const char *codec_name; 2008 bool check_sdca = false; 2009 2010 if (!adr_dev->name_prefix) { 2011 dev_err(dev, "codec 0x%llx does not have a name prefix\n", 2012 adr_dev->adr); 2013 return -EINVAL; 2014 } 2015 2016 codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); 2017 if (!codec_info) 2018 return -EINVAL; 2019 2020 for (j = 0; j < codec_info->aux_num; j++) { 2021 struct snd_soc_component *component; 2022 2023 ret = is_sdca_aux_dev_present(dev, codec_info->auxs[j].codec_name, 2024 adr_link, i); 2025 if (ret < 0) 2026 return ret; 2027 2028 if (ret == 0) 2029 continue; 2030 2031 component = snd_soc_lookup_component_by_name(codec_info->auxs[j].codec_name); 2032 if (component) { 2033 dev_dbg(dev, "%s found component %s for aux name %s\n", 2034 __func__, component->name, 2035 codec_info->auxs[j].codec_name); 2036 soc_aux->dlc.name = component->name; 2037 } else { 2038 dev_dbg(dev, "%s the aux component %s is not registered yet\n", 2039 __func__, codec_info->auxs[j].codec_name); 2040 return -EPROBE_DEFER; 2041 } 2042 soc_aux++; 2043 } 2044 2045 ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; 2046 2047 if (codec_info->count_sidecar && codec_info->add_sidecar) { 2048 ret = codec_info->count_sidecar(card, &num_dais, num_devs); 2049 if (ret) 2050 return ret; 2051 2052 soc_end->include_sidecar = true; 2053 } 2054 2055 if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1) 2056 check_sdca = true; 2057 2058 for (j = 0; j < adr_dev->num_endpoints; j++) { 2059 const struct snd_soc_acpi_endpoint *adr_end; 2060 const struct asoc_sdw_dai_info *dai_info; 2061 struct asoc_sdw_dailink *soc_dai; 2062 int stream; 2063 2064 adr_end = &adr_dev->endpoints[j]; 2065 dai_info = &codec_info->dais[adr_end->num]; 2066 soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); 2067 2068 /* 2069 * quirk should have higher priority than the sdca properties 2070 * in the BIOS. We can't always check the DAI quirk because we 2071 * will set the mc_quirk when the BIOS doesn't provide the right 2072 * information. The endpoint will be skipped if the dai_info-> 2073 * quirk_exclude and mc_quirk are both not set if we always skip 2074 * the endpoint according to the quirk information. We need to 2075 * keep the endpoint if it is present in the BIOS. So, only 2076 * check the DAI quirk when the mc_quirk is set or SDCA endpoint 2077 * present check is not needed. 2078 */ 2079 if (dai_info->quirk & ctx->mc_quirk || !check_sdca) { 2080 /* 2081 * Check the endpoint if a matching quirk is set or SDCA 2082 * endpoint check is not necessary 2083 */ 2084 if (dai_info->quirk && 2085 !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) { 2086 (*num_devs)--; 2087 continue; 2088 } 2089 } else { 2090 /* Check SDCA codec endpoint if there is no matching quirk */ 2091 ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j); 2092 if (ret < 0) 2093 return ret; 2094 2095 /* The endpoint is not present, skip */ 2096 if (!ret) { 2097 (*num_devs)--; 2098 continue; 2099 } 2100 } 2101 2102 dev_dbg(dev, 2103 "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n", 2104 ffs(adr_link->mask) - 1, adr_dev->adr, 2105 adr_end->num, dai_info->dai_type, 2106 dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-', 2107 dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-', 2108 adr_end->aggregated ? "group" : "solo", 2109 adr_end->group_id); 2110 2111 if (adr_end->num >= codec_info->dai_num) { 2112 dev_err(dev, 2113 "%d is too many endpoints for codec: 0x%x\n", 2114 adr_end->num, codec_info->part_id); 2115 return -EINVAL; 2116 } 2117 2118 for_each_pcm_streams(stream) { 2119 if (dai_info->direction[stream] && 2120 dai_info->dailink[stream] < 0) { 2121 dev_err(dev, 2122 "Invalid dailink id %d for codec: 0x%x\n", 2123 dai_info->dailink[stream], 2124 codec_info->part_id); 2125 return -EINVAL; 2126 } 2127 2128 if (dai_info->direction[stream]) { 2129 num_dais += !soc_dai->num_devs[stream]; 2130 soc_dai->num_devs[stream]++; 2131 soc_dai->link_mask[stream] |= adr_link->mask; 2132 } 2133 } 2134 2135 num_link_dailinks += !!list_empty(&soc_dai->endpoints); 2136 list_add_tail(&soc_end->list, &soc_dai->endpoints); 2137 2138 codec_name = asoc_sdw_get_codec_name(dev, dai_info, 2139 adr_link, i); 2140 if (IS_ERR(codec_name)) 2141 return PTR_ERR(codec_name); 2142 if (!codec_name) 2143 return -ENOMEM; 2144 2145 dev_dbg(dev, "Adding prefix %s for %s\n", 2146 adr_dev->name_prefix, codec_name); 2147 2148 soc_end->name_prefix = adr_dev->name_prefix; 2149 2150 soc_end->link_mask = adr_link->mask; 2151 soc_end->codec_name = codec_name; 2152 soc_end->codec_info = codec_info; 2153 soc_end->dai_info = dai_info; 2154 soc_end++; 2155 } 2156 } 2157 2158 ctx->append_dai_type |= (num_link_dailinks > 1); 2159 } 2160 2161 return num_dais; 2162 } 2163 EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, "SND_SOC_SDW_UTILS"); 2164 2165 MODULE_LICENSE("GPL"); 2166 MODULE_DESCRIPTION("SoundWire ASoC helpers"); 2167