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