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 }, 815 }, 816 .dai_num = 2, 817 }, 818 { 819 .vendor_id = 0x01fa, 820 .part_id = 0x3557, 821 .name_prefix = "AMP", 822 .is_amp = true, 823 .dais = { 824 { 825 .direction = {true, false}, 826 .dai_name = "cs35l56-sdw1", 827 .component_name = "cs35l56", 828 .dai_type = SOC_SDW_DAI_TYPE_AMP, 829 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 830 .init = asoc_sdw_cs_amp_init, 831 .rtd_init = asoc_sdw_cs_spk_rtd_init, 832 .controls = generic_spk_controls, 833 .num_controls = ARRAY_SIZE(generic_spk_controls), 834 .widgets = generic_spk_widgets, 835 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 836 }, 837 { 838 .direction = {false, true}, 839 .dai_name = "cs35l56-sdw1c", 840 .dai_type = SOC_SDW_DAI_TYPE_AMP, 841 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 842 }, 843 }, 844 .dai_num = 2, 845 }, 846 { 847 .vendor_id = 0x01fa, 848 .part_id = 0x3562, 849 .name_prefix = "AMP", 850 .is_amp = true, 851 .dais = { 852 { 853 .direction = {true, false}, 854 .dai_name = "cs35l56-sdw1", 855 .component_name = "cs35l56", 856 .dai_type = SOC_SDW_DAI_TYPE_AMP, 857 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 858 .init = asoc_sdw_cs_amp_init, 859 .rtd_init = asoc_sdw_cs_spk_rtd_init, 860 .controls = generic_spk_controls, 861 .num_controls = ARRAY_SIZE(generic_spk_controls), 862 .widgets = generic_spk_widgets, 863 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 864 }, 865 { 866 .direction = {false, true}, 867 .dai_name = "cs35l56-sdw1c", 868 .dai_type = SOC_SDW_DAI_TYPE_AMP, 869 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 870 }, 871 }, 872 .dai_num = 2, 873 }, 874 { 875 .vendor_id = 0x01fa, 876 .part_id = 0x3563, 877 .name_prefix = "AMP", 878 .is_amp = true, 879 .dais = { 880 { 881 .direction = {true, false}, 882 .dai_name = "cs35l56-sdw1", 883 .component_name = "cs35l56", 884 .dai_type = SOC_SDW_DAI_TYPE_AMP, 885 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 886 .init = asoc_sdw_cs_amp_init, 887 .rtd_init = asoc_sdw_cs_spk_rtd_init, 888 .controls = generic_spk_controls, 889 .num_controls = ARRAY_SIZE(generic_spk_controls), 890 .widgets = generic_spk_widgets, 891 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 892 }, 893 { 894 .direction = {false, true}, 895 .dai_name = "cs35l56-sdw1c", 896 .dai_type = SOC_SDW_DAI_TYPE_AMP, 897 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 898 }, 899 }, 900 .dai_num = 2, 901 }, 902 { 903 .vendor_id = 0x01fa, 904 .part_id = 0x4242, 905 .name_prefix = "cs42l42", 906 .dais = { 907 { 908 .direction = {true, true}, 909 .dai_name = "cs42l42-sdw", 910 .dai_type = SOC_SDW_DAI_TYPE_JACK, 911 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 912 .rtd_init = asoc_sdw_cs42l42_rtd_init, 913 .controls = generic_jack_controls, 914 .num_controls = ARRAY_SIZE(generic_jack_controls), 915 .widgets = generic_jack_widgets, 916 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 917 }, 918 }, 919 .dai_num = 1, 920 }, 921 { 922 .vendor_id = 0x01fa, 923 .part_id = 0x4243, 924 .name_prefix = "cs42l43", 925 .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, 926 .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, 927 .dais = { 928 { 929 .direction = {true, false}, 930 .codec_name = "cs42l43-codec", 931 .dai_name = "cs42l43-dp5", 932 .dai_type = SOC_SDW_DAI_TYPE_JACK, 933 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 934 .rtd_init = asoc_sdw_cs42l43_hs_rtd_init, 935 .controls = generic_jack_controls, 936 .num_controls = ARRAY_SIZE(generic_jack_controls), 937 .widgets = generic_jack_widgets, 938 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 939 }, 940 { 941 .direction = {false, true}, 942 .codec_name = "cs42l43-codec", 943 .dai_name = "cs42l43-dp1", 944 .dai_type = SOC_SDW_DAI_TYPE_MIC, 945 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 946 .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, 947 .widgets = generic_dmic_widgets, 948 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 949 .quirk = SOC_SDW_CODEC_MIC, 950 .quirk_exclude = true, 951 }, 952 { 953 .direction = {false, true}, 954 .codec_name = "cs42l43-codec", 955 .dai_name = "cs42l43-dp2", 956 .dai_type = SOC_SDW_DAI_TYPE_JACK, 957 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 958 }, 959 { 960 .direction = {true, false}, 961 .codec_name = "cs42l43-codec", 962 .component_name = "cs42l43-spk", 963 .dai_name = "cs42l43-dp6", 964 .dai_type = SOC_SDW_DAI_TYPE_AMP, 965 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 966 .init = asoc_sdw_cs42l43_spk_init, 967 .rtd_init = asoc_sdw_cs42l43_spk_rtd_init, 968 .controls = generic_spk_controls, 969 .num_controls = ARRAY_SIZE(generic_spk_controls), 970 .widgets = generic_spk_widgets, 971 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 972 .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS, 973 }, 974 }, 975 .dai_num = 4, 976 }, 977 { 978 .vendor_id = 0x01fa, 979 .part_id = 0x2A3B, 980 .name_prefix = "cs42l43", 981 .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, 982 .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, 983 .dais = { 984 { 985 .direction = {true, false}, 986 .codec_name = "cs42l43-codec", 987 .dai_name = "cs42l43-dp5", 988 .dai_type = SOC_SDW_DAI_TYPE_JACK, 989 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 990 .rtd_init = asoc_sdw_cs42l43_hs_rtd_init, 991 .controls = generic_jack_controls, 992 .num_controls = ARRAY_SIZE(generic_jack_controls), 993 .widgets = generic_jack_widgets, 994 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 995 }, 996 { 997 .direction = {false, true}, 998 .codec_name = "cs42l43-codec", 999 .dai_name = "cs42l43-dp1", 1000 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1001 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1002 .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, 1003 .widgets = generic_dmic_widgets, 1004 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 1005 .quirk = SOC_SDW_CODEC_MIC, 1006 .quirk_exclude = true, 1007 }, 1008 { 1009 .direction = {false, true}, 1010 .codec_name = "cs42l43-codec", 1011 .dai_name = "cs42l43-dp2", 1012 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1013 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1014 }, 1015 { 1016 .direction = {true, false}, 1017 .codec_name = "cs42l43-codec", 1018 .component_name = "cs42l43-spk", 1019 .dai_name = "cs42l43-dp6", 1020 .dai_type = SOC_SDW_DAI_TYPE_AMP, 1021 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1022 .init = asoc_sdw_cs42l43_spk_init, 1023 .rtd_init = asoc_sdw_cs42l43_spk_rtd_init, 1024 .controls = generic_spk_controls, 1025 .num_controls = ARRAY_SIZE(generic_spk_controls), 1026 .widgets = generic_spk_widgets, 1027 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 1028 .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS, 1029 }, 1030 }, 1031 .dai_num = 4, 1032 }, 1033 { 1034 .vendor_id = 0x01fa, 1035 .part_id = 0x4245, 1036 .name_prefix = "cs42l45", 1037 .dais = { 1038 { 1039 .direction = {true, false}, 1040 .codec_name = "snd_soc_sdca.UAJ", 1041 .dai_name = "IT 41", 1042 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1043 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1044 .rtd_init = asoc_sdw_cs42l45_hs_rtd_init, 1045 }, 1046 { 1047 .direction = {false, true}, 1048 .codec_name = "snd_soc_sdca.SmartMic", 1049 .dai_name = "OT 113", 1050 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1051 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1052 .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init, 1053 }, 1054 { 1055 .direction = {false, true}, 1056 .codec_name = "snd_soc_sdca.UAJ", 1057 .dai_name = "OT 36", 1058 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1059 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1060 }, 1061 }, 1062 .dai_num = 3, 1063 .auxs = { 1064 { 1065 .codec_name = "snd_soc_sdca.HID", 1066 }, 1067 }, 1068 .aux_num = 1, 1069 }, 1070 { 1071 .vendor_id = 0x01fa, 1072 .part_id = 0x4249, 1073 .name_prefix = "cs42l45", /* Use same user-space as cs42l45 */ 1074 .dais = { 1075 { 1076 .direction = {true, false}, 1077 .codec_name = "snd_soc_sdca.UAJ", 1078 .dai_name = "IT 41", 1079 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1080 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1081 .rtd_init = asoc_sdw_cs42l45_hs_rtd_init, 1082 }, 1083 { 1084 .direction = {false, true}, 1085 .codec_name = "snd_soc_sdca.SmartMic", 1086 .dai_name = "OT 113", 1087 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1088 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1089 .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init, 1090 }, 1091 { 1092 .direction = {false, true}, 1093 .codec_name = "snd_soc_sdca.UAJ", 1094 .dai_name = "OT 36", 1095 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1096 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1097 }, 1098 }, 1099 .dai_num = 3, 1100 .auxs = { 1101 { 1102 .codec_name = "snd_soc_sdca.HID", 1103 }, 1104 }, 1105 .aux_num = 1, 1106 }, 1107 { 1108 .vendor_id = 0x01fa, 1109 .part_id = 0x4747, 1110 .name_prefix = "cs47l47", 1111 .dais = { 1112 { 1113 .direction = {true, false}, 1114 .codec_name = "snd_soc_sdca.UAJ", 1115 .dai_name = "IT 41", 1116 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1117 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1118 .rtd_init = asoc_sdw_cs47l47_hs_rtd_init, 1119 }, 1120 { 1121 .direction = {false, true}, 1122 .codec_name = "snd_soc_sdca.SmartMic", 1123 .dai_name = "OT 113", 1124 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1125 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1126 .rtd_init = asoc_sdw_cs47l47_dmic_rtd_init, 1127 }, 1128 { 1129 .direction = {false, true}, 1130 .codec_name = "snd_soc_sdca.UAJ", 1131 .dai_name = "OT 36", 1132 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1133 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1134 }, 1135 }, 1136 .dai_num = 3, 1137 .auxs = { 1138 { 1139 .codec_name = "snd_soc_sdca.HID", 1140 }, 1141 }, 1142 .aux_num = 1, 1143 }, 1144 { 1145 .vendor_id = 0x04b3, 1146 .part_id = 0x9356, 1147 .name_prefix = "es9356", 1148 .version_id = 3, 1149 .dais = { 1150 { 1151 .direction = {true, false}, 1152 .dai_name = "es9356-sdp-aif1", 1153 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1154 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1155 .init = asoc_sdw_es9356_init, 1156 .exit = asoc_sdw_es9356_exit, 1157 .rtd_init = asoc_sdw_es9356_rtd_init, 1158 .controls = generic_jack_controls, 1159 .num_controls = ARRAY_SIZE(generic_jack_controls), 1160 .widgets = generic_jack_widgets, 1161 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 1162 }, 1163 { 1164 .direction = {false, true}, 1165 .dai_name = "es9356-sdp-aif4", 1166 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1167 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1168 .rtd_init = asoc_sdw_es9356_dmic_rtd_init, 1169 .widgets = generic_dmic_widgets, 1170 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 1171 }, 1172 { 1173 .direction = {false, true}, 1174 .dai_name = "es9356-sdp-aif2", 1175 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1176 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1177 }, 1178 { 1179 .direction = {true, false}, 1180 .dai_name = "es9356-sdp-aif3", 1181 .component_name = "es9356", 1182 .dai_type = SOC_SDW_DAI_TYPE_AMP, 1183 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1184 .init = asoc_sdw_es9356_amp_init, 1185 .rtd_init = asoc_sdw_es9356_spk_rtd_init, 1186 .controls = generic_spk_controls, 1187 .num_controls = ARRAY_SIZE(generic_spk_controls), 1188 .widgets = generic_spk_widgets, 1189 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 1190 }, 1191 }, 1192 .dai_num = 4, 1193 }, 1194 { 1195 .vendor_id = 0x0105, 1196 .part_id = 0xaaaa, /* generic codec mockup */ 1197 .name_prefix = "sdw_mockup_mmulti-function", 1198 .version_id = 0, 1199 .dais = { 1200 { 1201 .direction = {true, true}, 1202 .dai_name = "sdw-mockup-aif1", 1203 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1204 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1205 }, 1206 { 1207 .direction = {true, false}, 1208 .dai_name = "sdw-mockup-aif1", 1209 .dai_type = SOC_SDW_DAI_TYPE_AMP, 1210 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 1211 }, 1212 { 1213 .direction = {false, true}, 1214 .dai_name = "sdw-mockup-aif1", 1215 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1216 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1217 }, 1218 }, 1219 .dai_num = 3, 1220 }, 1221 { 1222 .vendor_id = 0x0105, 1223 .part_id = 0xaa55, /* headset codec mockup */ 1224 .name_prefix = "sdw_mockup_headset0", 1225 .version_id = 0, 1226 .dais = { 1227 { 1228 .direction = {true, true}, 1229 .dai_name = "sdw-mockup-aif1", 1230 .dai_type = SOC_SDW_DAI_TYPE_JACK, 1231 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 1232 }, 1233 }, 1234 .dai_num = 1, 1235 }, 1236 { 1237 .vendor_id = 0x0105, 1238 .part_id = 0x55aa, /* amplifier mockup */ 1239 .name_prefix = "sdw_mockup_amp1", 1240 .is_amp = true, 1241 .version_id = 0, 1242 .dais = { 1243 { 1244 .direction = {true, true}, 1245 .dai_name = "sdw-mockup-aif1", 1246 .dai_type = SOC_SDW_DAI_TYPE_AMP, 1247 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 1248 }, 1249 }, 1250 .dai_num = 1, 1251 }, 1252 { 1253 .vendor_id = 0x0105, 1254 .part_id = 0x5555, 1255 .name_prefix = "sdw_mockup_mic0", 1256 .version_id = 0, 1257 .dais = { 1258 { 1259 .dai_name = "sdw-mockup-aif1", 1260 .direction = {false, true}, 1261 .dai_type = SOC_SDW_DAI_TYPE_MIC, 1262 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 1263 }, 1264 }, 1265 .dai_num = 1, 1266 }, 1267 }; 1268 EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS"); 1269 1270 int asoc_sdw_get_codec_info_list_count(void) 1271 { 1272 return ARRAY_SIZE(codec_info_list); 1273 }; 1274 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS"); 1275 1276 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr) 1277 { 1278 unsigned int vendor_id, part_id, sdw_version; 1279 int i; 1280 1281 vendor_id = SDW_MFG_ID(adr); 1282 part_id = SDW_PART_ID(adr); 1283 sdw_version = SDW_VERSION(adr); 1284 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1285 /* 1286 * A codec info is for all sdw version with the part id if 1287 * version_id is not specified in the codec info. 1288 */ 1289 if (part_id == codec_info_list[i].part_id && 1290 vendor_id == codec_info_list[i].vendor_id && 1291 (!codec_info_list[i].version_id || 1292 sdw_version == codec_info_list[i].version_id)) 1293 return &codec_info_list[i]; 1294 1295 return NULL; 1296 } 1297 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS"); 1298 1299 static struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_sdw_id(const struct sdw_slave_id *id) 1300 { 1301 int i; 1302 1303 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1304 if (id->part_id == codec_info_list[i].part_id && 1305 id->mfg_id == codec_info_list[i].vendor_id && 1306 (!codec_info_list[i].version_id || 1307 id->sdw_version == codec_info_list[i].version_id)) 1308 return &codec_info_list[i]; 1309 1310 return NULL; 1311 } 1312 1313 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id) 1314 { 1315 int i; 1316 1317 if (!acpi_id[0]) 1318 return NULL; 1319 1320 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 1321 if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) 1322 return &codec_info_list[i]; 1323 1324 return NULL; 1325 } 1326 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, "SND_SOC_SDW_UTILS"); 1327 1328 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index) 1329 { 1330 int i, j; 1331 1332 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { 1333 for (j = 0; j < codec_info_list[i].dai_num; j++) { 1334 if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { 1335 *dai_index = j; 1336 return &codec_info_list[i]; 1337 } 1338 } 1339 } 1340 1341 return NULL; 1342 } 1343 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS"); 1344 1345 static int asoc_sdw_find_codec_info_dai_index(const struct asoc_sdw_codec_info *codec_info, 1346 const char *dai_name) 1347 { 1348 int i; 1349 1350 for (i = 0; i < codec_info->dai_num; i++) { 1351 if (!strcmp(codec_info->dais[i].dai_name, dai_name)) 1352 return i; 1353 } 1354 1355 return -ENOENT; 1356 } 1357 1358 int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) 1359 { 1360 struct snd_soc_card *card = rtd->card; 1361 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1362 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); 1363 struct asoc_sdw_codec_info *codec_info; 1364 struct snd_soc_dai *dai; 1365 struct sdw_slave *sdw_peripheral; 1366 const char *spk_components = NULL; 1367 int dai_index; 1368 int ret; 1369 int i; 1370 1371 for_each_rtd_codec_dais(rtd, i, dai) { 1372 if (is_sdw_slave(dai->component->dev)) 1373 sdw_peripheral = dev_to_sdw_dev(dai->component->dev); 1374 else if (dai->component->dev->parent && is_sdw_slave(dai->component->dev->parent)) 1375 sdw_peripheral = dev_to_sdw_dev(dai->component->dev->parent); 1376 else 1377 continue; 1378 1379 codec_info = asoc_sdw_find_codec_info_sdw_id(&sdw_peripheral->id); 1380 if (!codec_info) 1381 return -EINVAL; 1382 1383 dai_index = asoc_sdw_find_codec_info_dai_index(codec_info, dai->name); 1384 WARN_ON(dai_index < 0); 1385 1386 /* 1387 * A codec dai can be connected to different dai links for capture and playback, 1388 * but we only need to call the rtd_init function once. 1389 * The rtd_init for each codec dai is independent. So, the order of rtd_init 1390 * doesn't matter. 1391 */ 1392 if (codec_info->dais[dai_index].rtd_init_done) 1393 continue; 1394 1395 dev_dbg(card->dev, "%#x/%s initializing for %s/%s\n", 1396 codec_info->part_id, codec_info->dais[dai_index].dai_name, 1397 dai->component->name, dai->name); 1398 1399 /* 1400 * Add card controls and dapm widgets for the first codec dai. 1401 * The controls and widgets will be used for all codec dais. 1402 */ 1403 1404 if (i > 0) 1405 goto skip_add_controls_widgets; 1406 1407 if (codec_info->dais[dai_index].controls) { 1408 ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls, 1409 codec_info->dais[dai_index].num_controls); 1410 if (ret) { 1411 dev_err(card->dev, "%#x-%#x controls addition failed: %d\n", 1412 codec_info->vendor_id, codec_info->part_id, ret); 1413 return ret; 1414 } 1415 } 1416 if (codec_info->dais[dai_index].widgets) { 1417 ret = snd_soc_dapm_new_controls(dapm, 1418 codec_info->dais[dai_index].widgets, 1419 codec_info->dais[dai_index].num_widgets); 1420 if (ret) { 1421 dev_err(card->dev, "%#x-%#x widgets addition failed: %d\n", 1422 codec_info->vendor_id, codec_info->part_id, ret); 1423 return ret; 1424 } 1425 } 1426 1427 skip_add_controls_widgets: 1428 if (codec_info->dais[dai_index].rtd_init) { 1429 ret = codec_info->dais[dai_index].rtd_init(rtd, dai); 1430 if (ret) 1431 return ret; 1432 } 1433 1434 /* Generate the spk component string for card->components string */ 1435 if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP && 1436 codec_info->dais[dai_index].component_name) { 1437 const char *component; 1438 1439 /* 1440 * For the special case of cs42l43 with sidecar amps, use only 1441 * "cs35l56-bridge" as the component name in card->components 1442 */ 1443 if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS && 1444 !strcmp(codec_info->dais[dai_index].component_name, "cs42l43-spk")) 1445 component = "cs35l56-bridge"; 1446 else 1447 component = codec_info->dais[dai_index].component_name; 1448 1449 if (!spk_components) 1450 spk_components = 1451 devm_kasprintf(card->dev, GFP_KERNEL, "%s", component); 1452 else 1453 /* Append component name to spk_components */ 1454 spk_components = 1455 devm_kasprintf(card->dev, GFP_KERNEL, 1456 "%s+%s", spk_components, component); 1457 1458 if (!spk_components) 1459 return -ENOMEM; 1460 } 1461 1462 codec_info->dais[dai_index].rtd_init_done = true; 1463 } 1464 1465 if (spk_components) { 1466 /* Update card components for speaker components */ 1467 card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s", 1468 card->components, spk_components); 1469 if (!card->components) 1470 return -ENOMEM; 1471 } 1472 1473 return 0; 1474 } 1475 EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, "SND_SOC_SDW_UTILS"); 1476 1477 /* these wrappers are only needed to avoid typecast compilation errors */ 1478 int asoc_sdw_startup(struct snd_pcm_substream *substream) 1479 { 1480 return sdw_startup_stream(substream); 1481 } 1482 EXPORT_SYMBOL_NS(asoc_sdw_startup, "SND_SOC_SDW_UTILS"); 1483 1484 int asoc_sdw_prepare(struct snd_pcm_substream *substream) 1485 { 1486 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 1487 struct sdw_stream_runtime *sdw_stream; 1488 struct snd_soc_dai *dai; 1489 1490 /* Find stream from first CPU DAI */ 1491 dai = snd_soc_rtd_to_cpu(rtd, 0); 1492 1493 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 1494 if (IS_ERR(sdw_stream)) { 1495 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 1496 return PTR_ERR(sdw_stream); 1497 } 1498 1499 return sdw_prepare_stream(sdw_stream); 1500 } 1501 EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS"); 1502 1503 int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd) 1504 { 1505 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 1506 struct sdw_stream_runtime *sdw_stream; 1507 struct snd_soc_dai *dai; 1508 int ret; 1509 1510 /* Find stream from first CPU DAI */ 1511 dai = snd_soc_rtd_to_cpu(rtd, 0); 1512 1513 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 1514 if (IS_ERR(sdw_stream)) { 1515 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 1516 return PTR_ERR(sdw_stream); 1517 } 1518 1519 switch (cmd) { 1520 case SNDRV_PCM_TRIGGER_RESUME: 1521 /* 1522 * The peripherals lose their port configuration when the 1523 * controller is power-gated during system suspend, and an 1524 * application that restarts the stream with 1525 * SNDRV_PCM_IOCTL_RESUME - which platforms advertising 1526 * SNDRV_PCM_INFO_RESUME allow - never goes through 1527 * .prepare() again. Prepare the stream here so that the 1528 * ports are reprogrammed before they are enabled; 1529 * sdw_prepare_stream() reapplies the parameters without 1530 * recomputing them when the stream is disabled. 1531 */ 1532 ret = sdw_prepare_stream(sdw_stream); 1533 if (ret) 1534 break; 1535 fallthrough; 1536 case SNDRV_PCM_TRIGGER_START: 1537 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1538 ret = sdw_enable_stream(sdw_stream); 1539 break; 1540 1541 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1542 case SNDRV_PCM_TRIGGER_SUSPEND: 1543 case SNDRV_PCM_TRIGGER_STOP: 1544 ret = sdw_disable_stream(sdw_stream); 1545 break; 1546 default: 1547 ret = -EINVAL; 1548 break; 1549 } 1550 1551 if (ret) 1552 dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); 1553 1554 return ret; 1555 } 1556 EXPORT_SYMBOL_NS(asoc_sdw_trigger, "SND_SOC_SDW_UTILS"); 1557 1558 int asoc_sdw_hw_params(struct snd_pcm_substream *substream, 1559 struct snd_pcm_hw_params *params) 1560 { 1561 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 1562 struct snd_soc_dai_link_ch_map *ch_maps; 1563 int ch = params_channels(params); 1564 unsigned int cpu_ch_mask, codec_ch_mask; 1565 int num_codecs; 1566 int step; 1567 int i; 1568 1569 if (!rtd->dai_link->ch_maps) 1570 return 0; 1571 1572 /* Identical data will be sent to all codecs in playback */ 1573 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1574 cpu_ch_mask = GENMASK(ch - 1, 0); 1575 step = 0; 1576 codec_ch_mask = 0; 1577 } else { 1578 num_codecs = rtd->dai_link->num_codecs; 1579 1580 if (ch < num_codecs || ch % num_codecs != 0) { 1581 dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", 1582 ch, num_codecs); 1583 return -EINVAL; 1584 } 1585 1586 cpu_ch_mask = GENMASK(ch / num_codecs - 1, 0); 1587 step = hweight_long(cpu_ch_mask); 1588 codec_ch_mask = cpu_ch_mask; 1589 } 1590 1591 /* 1592 * The captured data will be combined from each cpu DAI if the dai 1593 * link has more than one codec DAIs. Set codec channel mask and 1594 * ASoC will set the corresponding channel numbers for each cpu dai. 1595 * 1596 * sdw_stream_add_slave() assigns different payload offsets to each 1597 * codec in a capture stream, so that the same channels on each 1598 * codec map to different channels on the CPU. 1599 */ 1600 for_each_link_ch_maps(rtd->dai_link, i, ch_maps) { 1601 ch_maps->cpu_ch_mask = cpu_ch_mask << (i * step); 1602 ch_maps->codec_ch_mask = codec_ch_mask; 1603 } 1604 1605 return 0; 1606 } 1607 EXPORT_SYMBOL_NS(asoc_sdw_hw_params, "SND_SOC_SDW_UTILS"); 1608 1609 int asoc_sdw_hw_free(struct snd_pcm_substream *substream) 1610 { 1611 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 1612 struct sdw_stream_runtime *sdw_stream; 1613 struct snd_soc_dai *dai; 1614 1615 /* Find stream from first CPU DAI */ 1616 dai = snd_soc_rtd_to_cpu(rtd, 0); 1617 1618 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 1619 if (IS_ERR(sdw_stream)) { 1620 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 1621 return PTR_ERR(sdw_stream); 1622 } 1623 1624 return sdw_deprepare_stream(sdw_stream); 1625 } 1626 EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS"); 1627 1628 void asoc_sdw_shutdown(struct snd_pcm_substream *substream) 1629 { 1630 sdw_shutdown_stream(substream); 1631 } 1632 EXPORT_SYMBOL_NS(asoc_sdw_shutdown, "SND_SOC_SDW_UTILS"); 1633 1634 static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, 1635 unsigned int sdw_version, 1636 unsigned int mfg_id, 1637 unsigned int part_id, 1638 unsigned int class_id, 1639 int index_in_link) 1640 { 1641 int i; 1642 1643 for (i = 0; i < adr_link->num_adr; i++) { 1644 unsigned int sdw1_version, mfg1_id, part1_id, class1_id; 1645 u64 adr; 1646 1647 /* skip itself */ 1648 if (i == index_in_link) 1649 continue; 1650 1651 adr = adr_link->adr_d[i].adr; 1652 1653 sdw1_version = SDW_VERSION(adr); 1654 mfg1_id = SDW_MFG_ID(adr); 1655 part1_id = SDW_PART_ID(adr); 1656 class1_id = SDW_CLASS_ID(adr); 1657 1658 if (sdw_version == sdw1_version && 1659 mfg_id == mfg1_id && 1660 part_id == part1_id && 1661 class_id == class1_id) 1662 return false; 1663 } 1664 1665 return true; 1666 } 1667 1668 static const char *_asoc_sdw_get_codec_name(struct device *dev, 1669 const struct snd_soc_acpi_link_adr *adr_link, 1670 int adr_index) 1671 { 1672 u64 adr = adr_link->adr_d[adr_index].adr; 1673 unsigned int sdw_version = SDW_VERSION(adr); 1674 unsigned int link_id = SDW_DISCO_LINK_ID(adr); 1675 unsigned int unique_id = SDW_UNIQUE_ID(adr); 1676 unsigned int mfg_id = SDW_MFG_ID(adr); 1677 unsigned int part_id = SDW_PART_ID(adr); 1678 unsigned int class_id = SDW_CLASS_ID(adr); 1679 1680 if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id, 1681 class_id, adr_index)) 1682 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", 1683 link_id, mfg_id, part_id, class_id); 1684 1685 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", 1686 link_id, mfg_id, part_id, class_id, unique_id); 1687 } 1688 1689 const char *asoc_sdw_get_codec_name(struct device *dev, 1690 const struct asoc_sdw_dai_info *dai_info, 1691 const struct snd_soc_acpi_link_adr *adr_link, 1692 int adr_index) 1693 { 1694 if (dai_info->codec_name) { 1695 struct snd_soc_component *component; 1696 1697 component = snd_soc_lookup_component_by_name(dai_info->codec_name); 1698 if (component) { 1699 dev_dbg(dev, "%s found component %s for codec_name %s\n", 1700 __func__, component->name, dai_info->codec_name); 1701 return devm_kstrdup(dev, component->name, GFP_KERNEL); 1702 } else { 1703 dev_dbg(dev, "%s component %s is not registered yet\n", 1704 __func__, dai_info->codec_name); 1705 return ERR_PTR(-EPROBE_DEFER); 1706 } 1707 } 1708 1709 return _asoc_sdw_get_codec_name(dev, adr_link, adr_index); 1710 } 1711 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS"); 1712 1713 /* helper to get the link that the codec DAI is used */ 1714 struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card, 1715 const char *dai_name) 1716 { 1717 struct snd_soc_dai_link *dai_link; 1718 int i; 1719 int j; 1720 1721 for_each_card_prelinks(card, i, dai_link) { 1722 for (j = 0; j < dai_link->num_codecs; j++) { 1723 /* Check each codec in a link */ 1724 if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) 1725 return dai_link; 1726 } 1727 } 1728 return NULL; 1729 } 1730 EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, "SND_SOC_SDW_UTILS"); 1731 1732 void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card) 1733 { 1734 struct snd_soc_dai_link *dai_link; 1735 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1736 int ret; 1737 int i, j; 1738 1739 for (i = 0; i < ctx->codec_info_list_count; i++) { 1740 for (j = 0; j < codec_info_list[i].dai_num; j++) { 1741 codec_info_list[i].dais[j].rtd_init_done = false; 1742 /* Check each dai in codec_info_lis to see if it is used in the link */ 1743 if (!codec_info_list[i].dais[j].exit) 1744 continue; 1745 /* 1746 * We don't need to call .exit function if there is no matched 1747 * dai link found. 1748 */ 1749 dai_link = asoc_sdw_mc_find_codec_dai_used(card, 1750 codec_info_list[i].dais[j].dai_name); 1751 if (dai_link) { 1752 /* Do the .exit function if the codec dai is used in the link */ 1753 ret = codec_info_list[i].dais[j].exit(card, dai_link); 1754 if (ret) 1755 dev_warn(card->dev, 1756 "codec exit failed %d\n", 1757 ret); 1758 break; 1759 } 1760 } 1761 } 1762 } 1763 EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, "SND_SOC_SDW_UTILS"); 1764 1765 int asoc_sdw_card_late_probe(struct snd_soc_card *card) 1766 { 1767 int ret = 0; 1768 int i; 1769 1770 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { 1771 if (codec_info_list[i].codec_card_late_probe) { 1772 ret = codec_info_list[i].codec_card_late_probe(card); 1773 if (ret < 0) 1774 return ret; 1775 } 1776 } 1777 return ret; 1778 } 1779 EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, "SND_SOC_SDW_UTILS"); 1780 1781 void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, 1782 int *be_id, char *name, int playback, int capture, 1783 struct snd_soc_dai_link_component *cpus, int cpus_num, 1784 struct snd_soc_dai_link_component *platform_component, 1785 int num_platforms, struct snd_soc_dai_link_component *codecs, 1786 int codecs_num, int no_pcm, 1787 int (*init)(struct snd_soc_pcm_runtime *rtd), 1788 const struct snd_soc_ops *ops) 1789 { 1790 dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); 1791 dai_links->id = (*be_id)++; 1792 dai_links->name = name; 1793 dai_links->stream_name = name; 1794 dai_links->platforms = platform_component; 1795 dai_links->num_platforms = num_platforms; 1796 dai_links->no_pcm = no_pcm; 1797 dai_links->cpus = cpus; 1798 dai_links->num_cpus = cpus_num; 1799 dai_links->codecs = codecs; 1800 dai_links->num_codecs = codecs_num; 1801 dai_links->playback_only = playback && !capture; 1802 dai_links->capture_only = !playback && capture; 1803 dai_links->init = init; 1804 dai_links->ops = ops; 1805 } 1806 EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, "SND_SOC_SDW_UTILS"); 1807 1808 int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, 1809 int *be_id, char *name, int playback, int capture, 1810 const char *cpu_dai_name, const char *platform_comp_name, 1811 const char *codec_name, const char *codec_dai_name, 1812 int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd), 1813 const struct snd_soc_ops *ops) 1814 { 1815 struct snd_soc_dai_link_component *dlc; 1816 1817 /* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */ 1818 dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL); 1819 if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name) 1820 return -ENOMEM; 1821 1822 dlc[0].dai_name = cpu_dai_name; 1823 dlc[1].name = platform_comp_name; 1824 1825 dlc[2].name = codec_name; 1826 dlc[2].dai_name = codec_dai_name; 1827 1828 asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture, 1829 &dlc[0], 1, &dlc[1], 1, &dlc[2], 1, 1830 no_pcm, init, ops); 1831 1832 return 0; 1833 } 1834 EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS"); 1835 1836 /** 1837 * is_sdca_aux_dev_present - Check if an SDCA aux device is present on the SDW peripheral 1838 * @dev: Device pointer 1839 * @aux_codec_name: Aux codec name from the codec info (e.g. "snd_soc_sdca.HID.2") 1840 * @adr_link: ACPI link address 1841 * @adr_index: Index of the ACPI link address 1842 * 1843 * Return: 1 if the aux is present, 0 if the aux is not present, or negative error code. 1844 */ 1845 static int is_sdca_aux_dev_present(struct device *dev, 1846 const char *aux_codec_name, 1847 const struct snd_soc_acpi_link_adr *adr_link, 1848 int adr_index) 1849 { 1850 struct sdw_slave *slave; 1851 const char *sdw_codec_name; 1852 int i; 1853 1854 if (!aux_codec_name) 1855 return 0; 1856 1857 sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index); 1858 if (!sdw_codec_name) 1859 return -ENOMEM; 1860 1861 struct device *sdw_dev __free(put_device) = 1862 bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); 1863 if (!sdw_dev) { 1864 dev_err(dev, "codec %s not found\n", sdw_codec_name); 1865 return -EINVAL; 1866 } 1867 1868 slave = dev_to_sdw_dev(sdw_dev); 1869 1870 if (!slave->sdca_data.interface_revision) { 1871 dev_warn(dev, "No SDCA properties, assuming aux '%s' present\n", aux_codec_name); 1872 return 1; 1873 } 1874 1875 for (i = 0; i < slave->sdca_data.num_functions; i++) { 1876 const char *fname = slave->sdca_data.function[i].name; 1877 1878 if (fname && strstr(aux_codec_name, fname)) 1879 return 1; 1880 } 1881 1882 dev_dbg(dev, "SDCA function for aux '%s' NOT FOUND on slave, skipping\n", aux_codec_name); 1883 1884 return 0; 1885 } 1886 1887 int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, 1888 int *num_devs, int *num_ends, int *num_aux) 1889 { 1890 struct device *dev = card->dev; 1891 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); 1892 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1893 const struct snd_soc_acpi_link_adr *adr_link; 1894 int i, j, ret; 1895 1896 for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { 1897 *num_devs += adr_link->num_adr; 1898 1899 for (i = 0; i < adr_link->num_adr; i++) { 1900 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; 1901 struct asoc_sdw_codec_info *codec_info; 1902 1903 *num_ends += adr_dev->num_endpoints; 1904 1905 codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); 1906 if (!codec_info) 1907 return -EINVAL; 1908 1909 for (j = 0; j < codec_info->aux_num; j++) { 1910 ret = is_sdca_aux_dev_present(dev, codec_info->auxs[j].codec_name, 1911 adr_link, i); 1912 if (ret < 0) 1913 return ret; 1914 if (ret) 1915 (*num_aux)++; 1916 } 1917 } 1918 } 1919 1920 dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); 1921 1922 return 0; 1923 } 1924 EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, "SND_SOC_SDW_UTILS"); 1925 1926 struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, 1927 const struct snd_soc_acpi_endpoint *new) 1928 { 1929 while (dailinks->initialised) { 1930 if (new->aggregated && dailinks->group_id == new->group_id) 1931 return dailinks; 1932 1933 dailinks++; 1934 } 1935 1936 INIT_LIST_HEAD(&dailinks->endpoints); 1937 dailinks->group_id = new->group_id; 1938 dailinks->initialised = true; 1939 1940 return dailinks; 1941 } 1942 EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS"); 1943 1944 int asoc_sdw_get_dai_type(u32 type) 1945 { 1946 switch (type) { 1947 case SDCA_FUNCTION_TYPE_SMART_AMP: 1948 case SDCA_FUNCTION_TYPE_SIMPLE_AMP: 1949 case SDCA_FUNCTION_TYPE_COMPANION_AMP: 1950 return SOC_SDW_DAI_TYPE_AMP; 1951 case SDCA_FUNCTION_TYPE_SMART_MIC: 1952 case SDCA_FUNCTION_TYPE_SIMPLE_MIC: 1953 case SDCA_FUNCTION_TYPE_SPEAKER_MIC: 1954 return SOC_SDW_DAI_TYPE_MIC; 1955 case SDCA_FUNCTION_TYPE_UAJ: 1956 case SDCA_FUNCTION_TYPE_RJ: 1957 case SDCA_FUNCTION_TYPE_SIMPLE_JACK: 1958 return SOC_SDW_DAI_TYPE_JACK; 1959 default: 1960 return -EINVAL; 1961 } 1962 } 1963 EXPORT_SYMBOL_NS(asoc_sdw_get_dai_type, "SND_SOC_SDW_UTILS"); 1964 1965 /** 1966 * is_sdca_endpoint_present - Check if an SDCA endpoint is present on the SDW peripheral 1967 * @dev: Device pointer 1968 * @codec_info: Codec info pointer 1969 * @adr_link: ACPI link address 1970 * @adr_index: Index of the ACPI link address 1971 * @end_index: Index of the endpoint 1972 * 1973 * Return: 1 if the endpoint is present, 0 if the endpoint is not present, or negative error code. 1974 */ 1975 static int is_sdca_endpoint_present(struct device *dev, 1976 struct asoc_sdw_codec_info *codec_info, 1977 const struct snd_soc_acpi_link_adr *adr_link, 1978 int adr_index, int end_index) 1979 { 1980 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index]; 1981 const struct snd_soc_acpi_endpoint *adr_end; 1982 const struct asoc_sdw_dai_info *dai_info; 1983 struct sdw_slave *slave; 1984 const char *sdw_codec_name; 1985 int i; 1986 1987 adr_end = &adr_dev->endpoints[end_index]; 1988 dai_info = &codec_info->dais[adr_end->num]; 1989 1990 sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index); 1991 if (!sdw_codec_name) 1992 return -ENOMEM; 1993 1994 struct device *sdw_dev __free(put_device) = 1995 bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); 1996 if (!sdw_dev) { 1997 dev_err(dev, "codec %s not found\n", sdw_codec_name); 1998 return -EINVAL; 1999 } 2000 2001 slave = dev_to_sdw_dev(sdw_dev); 2002 2003 /* Make sure BIOS provides SDCA properties */ 2004 if (!slave->sdca_data.interface_revision) { 2005 dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n"); 2006 return 1; 2007 } 2008 2009 for (i = 0; i < slave->sdca_data.num_functions; i++) { 2010 int dai_type = asoc_sdw_get_dai_type(slave->sdca_data.function[i].type); 2011 2012 if (dai_type == dai_info->dai_type) { 2013 dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n", 2014 dai_type, slave->sdca_data.function[i].name); 2015 return 1; 2016 } 2017 } 2018 2019 dev_dbg(&slave->dev, 2020 "SDCA device function for DAI type %d not supported, skip endpoint\n", 2021 dai_info->dai_type); 2022 2023 return 0; 2024 } 2025 2026 int asoc_sdw_parse_sdw_endpoints(struct device *dev, 2027 struct asoc_sdw_mc_private *ctx, 2028 struct snd_soc_aux_dev *soc_aux, 2029 struct asoc_sdw_dailink *soc_dais, 2030 struct asoc_sdw_endpoint *soc_ends, 2031 int *num_devs) 2032 { 2033 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); 2034 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 2035 const struct snd_soc_acpi_link_adr *adr_link; 2036 struct asoc_sdw_endpoint *soc_end = soc_ends; 2037 int num_dais = 0; 2038 int i, j; 2039 int ret; 2040 2041 for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { 2042 int num_link_dailinks = 0; 2043 2044 if (!is_power_of_2(adr_link->mask)) { 2045 dev_err(dev, "link with multiple mask bits: 0x%x\n", 2046 adr_link->mask); 2047 return -EINVAL; 2048 } 2049 2050 for (i = 0; i < adr_link->num_adr; i++) { 2051 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; 2052 struct asoc_sdw_codec_info *codec_info; 2053 const char *codec_name; 2054 bool check_sdca = false; 2055 2056 if (!adr_dev->name_prefix) { 2057 dev_err(dev, "codec 0x%llx does not have a name prefix\n", 2058 adr_dev->adr); 2059 return -EINVAL; 2060 } 2061 2062 codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); 2063 if (!codec_info) 2064 return -EINVAL; 2065 2066 for (j = 0; j < codec_info->aux_num; j++) { 2067 struct snd_soc_component *component; 2068 2069 ret = is_sdca_aux_dev_present(dev, codec_info->auxs[j].codec_name, 2070 adr_link, i); 2071 if (ret < 0) 2072 return ret; 2073 2074 if (ret == 0) 2075 continue; 2076 2077 component = snd_soc_lookup_component_by_name(codec_info->auxs[j].codec_name); 2078 if (component) { 2079 dev_dbg(dev, "%s found component %s for aux name %s\n", 2080 __func__, component->name, 2081 codec_info->auxs[j].codec_name); 2082 soc_aux->dlc.name = component->name; 2083 } else { 2084 dev_dbg(dev, "%s the aux component %s is not registered yet\n", 2085 __func__, codec_info->auxs[j].codec_name); 2086 return -EPROBE_DEFER; 2087 } 2088 soc_aux++; 2089 } 2090 2091 ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; 2092 2093 if (codec_info->count_sidecar && codec_info->add_sidecar) { 2094 ret = codec_info->count_sidecar(ctx, &num_dais, num_devs); 2095 if (ret) 2096 return ret; 2097 2098 soc_end->include_sidecar = true; 2099 } 2100 2101 if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1) 2102 check_sdca = true; 2103 2104 for (j = 0; j < adr_dev->num_endpoints; j++) { 2105 const struct snd_soc_acpi_endpoint *adr_end; 2106 const struct asoc_sdw_dai_info *dai_info; 2107 struct asoc_sdw_dailink *soc_dai; 2108 int stream; 2109 2110 adr_end = &adr_dev->endpoints[j]; 2111 dai_info = &codec_info->dais[adr_end->num]; 2112 soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); 2113 2114 /* 2115 * quirk should have higher priority than the sdca properties 2116 * in the BIOS. We can't always check the DAI quirk because we 2117 * will set the mc_quirk when the BIOS doesn't provide the right 2118 * information. The endpoint will be skipped if the dai_info-> 2119 * quirk_exclude and mc_quirk are both not set if we always skip 2120 * the endpoint according to the quirk information. We need to 2121 * keep the endpoint if it is present in the BIOS. So, only 2122 * check the DAI quirk when the mc_quirk is set or SDCA endpoint 2123 * present check is not needed. 2124 */ 2125 if (dai_info->quirk & ctx->mc_quirk || !check_sdca) { 2126 /* 2127 * Check the endpoint if a matching quirk is set or SDCA 2128 * endpoint check is not necessary 2129 */ 2130 if (dai_info->quirk && 2131 !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) { 2132 (*num_devs)--; 2133 continue; 2134 } 2135 } else { 2136 /* Check SDCA codec endpoint if there is no matching quirk */ 2137 ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j); 2138 if (ret < 0) 2139 return ret; 2140 2141 /* The endpoint is not present, skip */ 2142 if (!ret) { 2143 (*num_devs)--; 2144 continue; 2145 } 2146 } 2147 2148 dev_dbg(dev, 2149 "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n", 2150 ffs(adr_link->mask) - 1, adr_dev->adr, 2151 adr_end->num, dai_info->dai_type, 2152 dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-', 2153 dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-', 2154 adr_end->aggregated ? "group" : "solo", 2155 adr_end->group_id); 2156 2157 if (adr_end->num >= codec_info->dai_num) { 2158 dev_err(dev, 2159 "%d is too many endpoints for codec: 0x%x\n", 2160 adr_end->num, codec_info->part_id); 2161 return -EINVAL; 2162 } 2163 2164 for_each_pcm_streams(stream) { 2165 if (dai_info->direction[stream] && 2166 dai_info->dailink[stream] < 0) { 2167 dev_err(dev, 2168 "Invalid dailink id %d for codec: 0x%x\n", 2169 dai_info->dailink[stream], 2170 codec_info->part_id); 2171 return -EINVAL; 2172 } 2173 2174 if (dai_info->direction[stream]) { 2175 num_dais += !soc_dai->num_devs[stream]; 2176 soc_dai->num_devs[stream]++; 2177 soc_dai->link_mask[stream] |= adr_link->mask; 2178 } 2179 } 2180 2181 num_link_dailinks += !!list_empty(&soc_dai->endpoints); 2182 list_add_tail(&soc_end->list, &soc_dai->endpoints); 2183 2184 codec_name = asoc_sdw_get_codec_name(dev, dai_info, 2185 adr_link, i); 2186 if (IS_ERR(codec_name)) 2187 return PTR_ERR(codec_name); 2188 if (!codec_name) 2189 return -ENOMEM; 2190 2191 dev_dbg(dev, "Adding prefix %s for %s\n", 2192 adr_dev->name_prefix, codec_name); 2193 2194 soc_end->name_prefix = adr_dev->name_prefix; 2195 2196 soc_end->link_mask = adr_link->mask; 2197 soc_end->codec_name = codec_name; 2198 soc_end->codec_info = codec_info; 2199 soc_end->dai_info = dai_info; 2200 soc_end++; 2201 } 2202 } 2203 2204 ctx->append_dai_type |= (num_link_dailinks > 1); 2205 } 2206 2207 return num_dais; 2208 } 2209 EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, "SND_SOC_SDW_UTILS"); 2210 2211 MODULE_LICENSE("GPL"); 2212 MODULE_DESCRIPTION("SoundWire ASoC helpers"); 2213