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