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