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 maxim_widgets[] = { 39 SND_SOC_DAPM_SPK("Left Spk", NULL), 40 SND_SOC_DAPM_SPK("Right Spk", NULL), 41 }; 42 43 static const struct snd_kcontrol_new maxim_controls[] = { 44 SOC_DAPM_PIN_SWITCH("Left Spk"), 45 SOC_DAPM_PIN_SWITCH("Right Spk"), 46 }; 47 48 static const struct snd_soc_dapm_widget rt700_widgets[] = { 49 SND_SOC_DAPM_HP("Headphones", NULL), 50 SND_SOC_DAPM_MIC("AMIC", NULL), 51 SND_SOC_DAPM_SPK("Speaker", NULL), 52 }; 53 54 static const struct snd_kcontrol_new rt700_controls[] = { 55 SOC_DAPM_PIN_SWITCH("Headphones"), 56 SOC_DAPM_PIN_SWITCH("AMIC"), 57 SOC_DAPM_PIN_SWITCH("Speaker"), 58 }; 59 60 struct asoc_sdw_codec_info codec_info_list[] = { 61 { 62 .part_id = 0x700, 63 .dais = { 64 { 65 .direction = {true, true}, 66 .dai_name = "rt700-aif1", 67 .dai_type = SOC_SDW_DAI_TYPE_JACK, 68 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 69 .rtd_init = asoc_sdw_rt700_rtd_init, 70 .controls = rt700_controls, 71 .num_controls = ARRAY_SIZE(rt700_controls), 72 .widgets = rt700_widgets, 73 .num_widgets = ARRAY_SIZE(rt700_widgets), 74 }, 75 }, 76 .dai_num = 1, 77 }, 78 { 79 .part_id = 0x711, 80 .version_id = 3, 81 .dais = { 82 { 83 .direction = {true, true}, 84 .dai_name = "rt711-sdca-aif1", 85 .dai_type = SOC_SDW_DAI_TYPE_JACK, 86 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 87 .init = asoc_sdw_rt_sdca_jack_init, 88 .exit = asoc_sdw_rt_sdca_jack_exit, 89 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 90 .controls = generic_jack_controls, 91 .num_controls = ARRAY_SIZE(generic_jack_controls), 92 .widgets = generic_jack_widgets, 93 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 94 }, 95 }, 96 .dai_num = 1, 97 }, 98 { 99 .part_id = 0x711, 100 .version_id = 2, 101 .dais = { 102 { 103 .direction = {true, true}, 104 .dai_name = "rt711-aif1", 105 .dai_type = SOC_SDW_DAI_TYPE_JACK, 106 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 107 .init = asoc_sdw_rt711_init, 108 .exit = asoc_sdw_rt711_exit, 109 .rtd_init = asoc_sdw_rt711_rtd_init, 110 .controls = generic_jack_controls, 111 .num_controls = ARRAY_SIZE(generic_jack_controls), 112 .widgets = generic_jack_widgets, 113 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 114 }, 115 }, 116 .dai_num = 1, 117 }, 118 { 119 .part_id = 0x712, 120 .version_id = 3, 121 .dais = { 122 { 123 .direction = {true, true}, 124 .dai_name = "rt712-sdca-aif1", 125 .dai_type = SOC_SDW_DAI_TYPE_JACK, 126 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 127 .init = asoc_sdw_rt_sdca_jack_init, 128 .exit = asoc_sdw_rt_sdca_jack_exit, 129 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 130 .controls = generic_jack_controls, 131 .num_controls = ARRAY_SIZE(generic_jack_controls), 132 .widgets = generic_jack_widgets, 133 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 134 }, 135 { 136 .direction = {true, false}, 137 .dai_name = "rt712-sdca-aif2", 138 .dai_type = SOC_SDW_DAI_TYPE_AMP, 139 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 140 .init = asoc_sdw_rt_amp_init, 141 .exit = asoc_sdw_rt_amp_exit, 142 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, 143 .controls = generic_spk_controls, 144 .num_controls = ARRAY_SIZE(generic_spk_controls), 145 .widgets = generic_spk_widgets, 146 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 147 }, 148 { 149 .direction = {false, true}, 150 .dai_name = "rt712-sdca-aif3", 151 .dai_type = SOC_SDW_DAI_TYPE_MIC, 152 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 153 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 154 }, 155 }, 156 .dai_num = 3, 157 }, 158 { 159 .part_id = 0x1712, 160 .version_id = 3, 161 .dais = { 162 { 163 .direction = {false, true}, 164 .dai_name = "rt712-sdca-dmic-aif1", 165 .dai_type = SOC_SDW_DAI_TYPE_MIC, 166 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 167 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 168 }, 169 }, 170 .dai_num = 1, 171 }, 172 { 173 .part_id = 0x713, 174 .version_id = 3, 175 .dais = { 176 { 177 .direction = {true, true}, 178 .dai_name = "rt712-sdca-aif1", 179 .dai_type = SOC_SDW_DAI_TYPE_JACK, 180 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 181 .init = asoc_sdw_rt_sdca_jack_init, 182 .exit = asoc_sdw_rt_sdca_jack_exit, 183 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 184 .controls = generic_jack_controls, 185 .num_controls = ARRAY_SIZE(generic_jack_controls), 186 .widgets = generic_jack_widgets, 187 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 188 }, 189 { 190 .direction = {false, true}, 191 .dai_name = "rt712-sdca-aif3", 192 .dai_type = SOC_SDW_DAI_TYPE_MIC, 193 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 194 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 195 }, 196 }, 197 .dai_num = 2, 198 }, 199 { 200 .part_id = 0x1713, 201 .version_id = 3, 202 .dais = { 203 { 204 .direction = {false, true}, 205 .dai_name = "rt712-sdca-dmic-aif1", 206 .dai_type = SOC_SDW_DAI_TYPE_MIC, 207 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 208 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 209 }, 210 }, 211 .dai_num = 1, 212 }, 213 { 214 .part_id = 0x1308, 215 .acpi_id = "10EC1308", 216 .dais = { 217 { 218 .direction = {true, false}, 219 .dai_name = "rt1308-aif", 220 .dai_type = SOC_SDW_DAI_TYPE_AMP, 221 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 222 .init = asoc_sdw_rt_amp_init, 223 .exit = asoc_sdw_rt_amp_exit, 224 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 225 .controls = generic_spk_controls, 226 .num_controls = ARRAY_SIZE(generic_spk_controls), 227 .widgets = generic_spk_widgets, 228 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 229 }, 230 }, 231 .dai_num = 1, 232 .ops = &soc_sdw_rt1308_i2s_ops, 233 }, 234 { 235 .part_id = 0x1316, 236 .dais = { 237 { 238 .direction = {true, true}, 239 .dai_name = "rt1316-aif", 240 .dai_type = SOC_SDW_DAI_TYPE_AMP, 241 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 242 .init = asoc_sdw_rt_amp_init, 243 .exit = asoc_sdw_rt_amp_exit, 244 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 245 .controls = generic_spk_controls, 246 .num_controls = ARRAY_SIZE(generic_spk_controls), 247 .widgets = generic_spk_widgets, 248 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 249 }, 250 }, 251 .dai_num = 1, 252 }, 253 { 254 .part_id = 0x1318, 255 .dais = { 256 { 257 .direction = {true, true}, 258 .dai_name = "rt1318-aif", 259 .dai_type = SOC_SDW_DAI_TYPE_AMP, 260 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 261 .init = asoc_sdw_rt_amp_init, 262 .exit = asoc_sdw_rt_amp_exit, 263 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 264 .controls = generic_spk_controls, 265 .num_controls = ARRAY_SIZE(generic_spk_controls), 266 .widgets = generic_spk_widgets, 267 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 268 }, 269 }, 270 .dai_num = 1, 271 }, 272 { 273 .part_id = 0x1320, 274 .dais = { 275 { 276 .direction = {true, false}, 277 .dai_name = "rt1320-aif1", 278 .dai_type = SOC_SDW_DAI_TYPE_AMP, 279 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 280 .init = asoc_sdw_rt_amp_init, 281 .exit = asoc_sdw_rt_amp_exit, 282 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, 283 .controls = generic_spk_controls, 284 .num_controls = ARRAY_SIZE(generic_spk_controls), 285 .widgets = generic_spk_widgets, 286 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 287 }, 288 }, 289 .dai_num = 1, 290 }, 291 { 292 .part_id = 0x714, 293 .version_id = 3, 294 .ignore_internal_dmic = true, 295 .dais = { 296 { 297 .direction = {false, true}, 298 .dai_name = "rt715-sdca-aif2", 299 .dai_type = SOC_SDW_DAI_TYPE_MIC, 300 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 301 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 302 }, 303 }, 304 .dai_num = 1, 305 }, 306 { 307 .part_id = 0x715, 308 .version_id = 3, 309 .ignore_internal_dmic = true, 310 .dais = { 311 { 312 .direction = {false, true}, 313 .dai_name = "rt715-sdca-aif2", 314 .dai_type = SOC_SDW_DAI_TYPE_MIC, 315 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 316 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 317 }, 318 }, 319 .dai_num = 1, 320 }, 321 { 322 .part_id = 0x714, 323 .version_id = 2, 324 .ignore_internal_dmic = true, 325 .dais = { 326 { 327 .direction = {false, true}, 328 .dai_name = "rt715-aif2", 329 .dai_type = SOC_SDW_DAI_TYPE_MIC, 330 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 331 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 332 }, 333 }, 334 .dai_num = 1, 335 }, 336 { 337 .part_id = 0x715, 338 .version_id = 2, 339 .ignore_internal_dmic = true, 340 .dais = { 341 { 342 .direction = {false, true}, 343 .dai_name = "rt715-aif2", 344 .dai_type = SOC_SDW_DAI_TYPE_MIC, 345 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 346 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 347 }, 348 }, 349 .dai_num = 1, 350 }, 351 { 352 .part_id = 0x721, 353 .version_id = 3, 354 .dais = { 355 { 356 .direction = {true, true}, 357 .dai_name = "rt721-sdca-aif1", 358 .dai_type = SOC_SDW_DAI_TYPE_JACK, 359 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 360 .init = asoc_sdw_rt_sdca_jack_init, 361 .exit = asoc_sdw_rt_sdca_jack_exit, 362 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 363 .controls = generic_jack_controls, 364 .num_controls = ARRAY_SIZE(generic_jack_controls), 365 .widgets = generic_jack_widgets, 366 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 367 }, 368 { 369 .direction = {true, false}, 370 .dai_name = "rt721-sdca-aif2", 371 .dai_type = SOC_SDW_DAI_TYPE_AMP, 372 /* No feedback capability is provided by rt721-sdca codec driver*/ 373 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 374 .init = asoc_sdw_rt_amp_init, 375 .exit = asoc_sdw_rt_amp_exit, 376 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, 377 .controls = generic_spk_controls, 378 .num_controls = ARRAY_SIZE(generic_spk_controls), 379 .widgets = generic_spk_widgets, 380 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 381 }, 382 { 383 .direction = {false, true}, 384 .dai_name = "rt721-sdca-aif3", 385 .dai_type = SOC_SDW_DAI_TYPE_MIC, 386 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 387 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 388 }, 389 }, 390 .dai_num = 3, 391 }, 392 { 393 .part_id = 0x722, 394 .version_id = 3, 395 .dais = { 396 { 397 .direction = {true, true}, 398 .dai_name = "rt722-sdca-aif1", 399 .dai_type = SOC_SDW_DAI_TYPE_JACK, 400 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 401 .init = asoc_sdw_rt_sdca_jack_init, 402 .exit = asoc_sdw_rt_sdca_jack_exit, 403 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, 404 .controls = generic_jack_controls, 405 .num_controls = ARRAY_SIZE(generic_jack_controls), 406 .widgets = generic_jack_widgets, 407 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 408 }, 409 { 410 .direction = {true, false}, 411 .dai_name = "rt722-sdca-aif2", 412 .dai_type = SOC_SDW_DAI_TYPE_AMP, 413 /* No feedback capability is provided by rt722-sdca codec driver*/ 414 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 415 .init = asoc_sdw_rt_amp_init, 416 .exit = asoc_sdw_rt_amp_exit, 417 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, 418 .controls = generic_spk_controls, 419 .num_controls = ARRAY_SIZE(generic_spk_controls), 420 .widgets = generic_spk_widgets, 421 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 422 .quirk = SOC_SDW_CODEC_SPKR, 423 .quirk_exclude = true, 424 }, 425 { 426 .direction = {false, true}, 427 .dai_name = "rt722-sdca-aif3", 428 .dai_type = SOC_SDW_DAI_TYPE_MIC, 429 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 430 .rtd_init = asoc_sdw_rt_dmic_rtd_init, 431 }, 432 }, 433 .dai_num = 3, 434 }, 435 { 436 .part_id = 0x8373, 437 .dais = { 438 { 439 .direction = {true, true}, 440 .dai_name = "max98373-aif1", 441 .dai_type = SOC_SDW_DAI_TYPE_AMP, 442 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 443 .init = asoc_sdw_maxim_init, 444 .rtd_init = asoc_sdw_maxim_spk_rtd_init, 445 .controls = maxim_controls, 446 .num_controls = ARRAY_SIZE(maxim_controls), 447 .widgets = maxim_widgets, 448 .num_widgets = ARRAY_SIZE(maxim_widgets), 449 }, 450 }, 451 .dai_num = 1, 452 }, 453 { 454 .part_id = 0x8363, 455 .dais = { 456 { 457 .direction = {true, false}, 458 .dai_name = "max98363-aif1", 459 .dai_type = SOC_SDW_DAI_TYPE_AMP, 460 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 461 .init = asoc_sdw_maxim_init, 462 .rtd_init = asoc_sdw_maxim_spk_rtd_init, 463 .controls = maxim_controls, 464 .num_controls = ARRAY_SIZE(maxim_controls), 465 .widgets = maxim_widgets, 466 .num_widgets = ARRAY_SIZE(maxim_widgets), 467 }, 468 }, 469 .dai_num = 1, 470 }, 471 { 472 .part_id = 0x5682, 473 .dais = { 474 { 475 .direction = {true, true}, 476 .dai_name = "rt5682-sdw", 477 .dai_type = SOC_SDW_DAI_TYPE_JACK, 478 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 479 .rtd_init = asoc_sdw_rt5682_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 .dai_num = 1, 487 }, 488 { 489 .part_id = 0x3556, 490 .dais = { 491 { 492 .direction = {true, false}, 493 .dai_name = "cs35l56-sdw1", 494 .dai_type = SOC_SDW_DAI_TYPE_AMP, 495 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 496 .init = asoc_sdw_cs_amp_init, 497 .rtd_init = asoc_sdw_cs_spk_rtd_init, 498 .controls = generic_spk_controls, 499 .num_controls = ARRAY_SIZE(generic_spk_controls), 500 .widgets = generic_spk_widgets, 501 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 502 }, 503 { 504 .direction = {false, true}, 505 .dai_name = "cs35l56-sdw1c", 506 .dai_type = SOC_SDW_DAI_TYPE_AMP, 507 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 508 .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, 509 }, 510 }, 511 .dai_num = 2, 512 }, 513 { 514 .part_id = 0x3563, 515 .dais = { 516 { 517 .direction = {true, false}, 518 .dai_name = "cs35l56-sdw1", 519 .dai_type = SOC_SDW_DAI_TYPE_AMP, 520 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 521 .init = asoc_sdw_cs_amp_init, 522 .rtd_init = asoc_sdw_cs_spk_rtd_init, 523 .controls = generic_spk_controls, 524 .num_controls = ARRAY_SIZE(generic_spk_controls), 525 .widgets = generic_spk_widgets, 526 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 527 }, 528 { 529 .direction = {false, true}, 530 .dai_name = "cs35l56-sdw1c", 531 .dai_type = SOC_SDW_DAI_TYPE_AMP, 532 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 533 .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, 534 }, 535 }, 536 .dai_num = 2, 537 }, 538 { 539 .part_id = 0x4242, 540 .dais = { 541 { 542 .direction = {true, true}, 543 .dai_name = "cs42l42-sdw", 544 .dai_type = SOC_SDW_DAI_TYPE_JACK, 545 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 546 .rtd_init = asoc_sdw_cs42l42_rtd_init, 547 .controls = generic_jack_controls, 548 .num_controls = ARRAY_SIZE(generic_jack_controls), 549 .widgets = generic_jack_widgets, 550 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 551 }, 552 }, 553 .dai_num = 1, 554 }, 555 { 556 .part_id = 0x4243, 557 .codec_name = "cs42l43-codec", 558 .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, 559 .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, 560 .dais = { 561 { 562 .direction = {true, false}, 563 .dai_name = "cs42l43-dp5", 564 .dai_type = SOC_SDW_DAI_TYPE_JACK, 565 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 566 .rtd_init = asoc_sdw_cs42l43_hs_rtd_init, 567 .controls = generic_jack_controls, 568 .num_controls = ARRAY_SIZE(generic_jack_controls), 569 .widgets = generic_jack_widgets, 570 .num_widgets = ARRAY_SIZE(generic_jack_widgets), 571 }, 572 { 573 .direction = {false, true}, 574 .dai_name = "cs42l43-dp1", 575 .dai_type = SOC_SDW_DAI_TYPE_MIC, 576 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 577 .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, 578 .widgets = generic_dmic_widgets, 579 .num_widgets = ARRAY_SIZE(generic_dmic_widgets), 580 .quirk = SOC_SDW_CODEC_MIC, 581 .quirk_exclude = true, 582 }, 583 { 584 .direction = {false, true}, 585 .dai_name = "cs42l43-dp2", 586 .dai_type = SOC_SDW_DAI_TYPE_JACK, 587 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 588 }, 589 { 590 .direction = {true, false}, 591 .dai_name = "cs42l43-dp6", 592 .dai_type = SOC_SDW_DAI_TYPE_AMP, 593 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 594 .init = asoc_sdw_cs42l43_spk_init, 595 .rtd_init = asoc_sdw_cs42l43_spk_rtd_init, 596 .controls = generic_spk_controls, 597 .num_controls = ARRAY_SIZE(generic_spk_controls), 598 .widgets = generic_spk_widgets, 599 .num_widgets = ARRAY_SIZE(generic_spk_widgets), 600 .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS, 601 }, 602 }, 603 .dai_num = 4, 604 }, 605 { 606 .part_id = 0xaaaa, /* generic codec mockup */ 607 .version_id = 0, 608 .dais = { 609 { 610 .direction = {true, true}, 611 .dai_name = "sdw-mockup-aif1", 612 .dai_type = SOC_SDW_DAI_TYPE_JACK, 613 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 614 }, 615 { 616 .direction = {true, false}, 617 .dai_name = "sdw-mockup-aif1", 618 .dai_type = SOC_SDW_DAI_TYPE_AMP, 619 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, 620 }, 621 { 622 .direction = {false, true}, 623 .dai_name = "sdw-mockup-aif1", 624 .dai_type = SOC_SDW_DAI_TYPE_MIC, 625 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 626 }, 627 }, 628 .dai_num = 3, 629 }, 630 { 631 .part_id = 0xaa55, /* headset codec mockup */ 632 .version_id = 0, 633 .dais = { 634 { 635 .direction = {true, true}, 636 .dai_name = "sdw-mockup-aif1", 637 .dai_type = SOC_SDW_DAI_TYPE_JACK, 638 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, 639 }, 640 }, 641 .dai_num = 1, 642 }, 643 { 644 .part_id = 0x55aa, /* amplifier mockup */ 645 .version_id = 0, 646 .dais = { 647 { 648 .direction = {true, true}, 649 .dai_name = "sdw-mockup-aif1", 650 .dai_type = SOC_SDW_DAI_TYPE_AMP, 651 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, 652 }, 653 }, 654 .dai_num = 1, 655 }, 656 { 657 .part_id = 0x5555, 658 .version_id = 0, 659 .dais = { 660 { 661 .dai_name = "sdw-mockup-aif1", 662 .direction = {false, true}, 663 .dai_type = SOC_SDW_DAI_TYPE_MIC, 664 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, 665 }, 666 }, 667 .dai_num = 1, 668 }, 669 }; 670 EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS"); 671 672 int asoc_sdw_get_codec_info_list_count(void) 673 { 674 return ARRAY_SIZE(codec_info_list); 675 }; 676 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS"); 677 678 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr) 679 { 680 unsigned int part_id, sdw_version; 681 int i; 682 683 part_id = SDW_PART_ID(adr); 684 sdw_version = SDW_VERSION(adr); 685 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 686 /* 687 * A codec info is for all sdw version with the part id if 688 * version_id is not specified in the codec info. 689 */ 690 if (part_id == codec_info_list[i].part_id && 691 (!codec_info_list[i].version_id || 692 sdw_version == codec_info_list[i].version_id)) 693 return &codec_info_list[i]; 694 695 return NULL; 696 } 697 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS"); 698 699 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id) 700 { 701 int i; 702 703 if (!acpi_id[0]) 704 return NULL; 705 706 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) 707 if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) 708 return &codec_info_list[i]; 709 710 return NULL; 711 } 712 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, "SND_SOC_SDW_UTILS"); 713 714 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index) 715 { 716 int i, j; 717 718 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { 719 for (j = 0; j < codec_info_list[i].dai_num; j++) { 720 if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { 721 *dai_index = j; 722 return &codec_info_list[i]; 723 } 724 } 725 } 726 727 return NULL; 728 } 729 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS"); 730 731 int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) 732 { 733 struct snd_soc_card *card = rtd->card; 734 struct asoc_sdw_codec_info *codec_info; 735 struct snd_soc_dai *dai; 736 int dai_index; 737 int ret; 738 int i; 739 740 for_each_rtd_codec_dais(rtd, i, dai) { 741 codec_info = asoc_sdw_find_codec_info_dai(dai->name, &dai_index); 742 if (!codec_info) 743 return -EINVAL; 744 745 /* 746 * A codec dai can be connected to different dai links for capture and playback, 747 * but we only need to call the rtd_init function once. 748 * The rtd_init for each codec dai is independent. So, the order of rtd_init 749 * doesn't matter. 750 */ 751 if (codec_info->dais[dai_index].rtd_init_done) 752 continue; 753 754 /* 755 * Add card controls and dapm widgets for the first codec dai. 756 * The controls and widgets will be used for all codec dais. 757 */ 758 759 if (i > 0) 760 goto skip_add_controls_widgets; 761 762 if (codec_info->dais[dai_index].controls) { 763 ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls, 764 codec_info->dais[dai_index].num_controls); 765 if (ret) { 766 dev_err(card->dev, "%#x controls addition failed: %d\n", 767 codec_info->part_id, ret); 768 return ret; 769 } 770 } 771 if (codec_info->dais[dai_index].widgets) { 772 ret = snd_soc_dapm_new_controls(&card->dapm, 773 codec_info->dais[dai_index].widgets, 774 codec_info->dais[dai_index].num_widgets); 775 if (ret) { 776 dev_err(card->dev, "%#x widgets addition failed: %d\n", 777 codec_info->part_id, ret); 778 return ret; 779 } 780 } 781 782 skip_add_controls_widgets: 783 if (codec_info->dais[dai_index].rtd_init) { 784 ret = codec_info->dais[dai_index].rtd_init(rtd, dai); 785 if (ret) 786 return ret; 787 } 788 codec_info->dais[dai_index].rtd_init_done = true; 789 } 790 791 return 0; 792 } 793 EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, "SND_SOC_SDW_UTILS"); 794 795 /* these wrappers are only needed to avoid typecast compilation errors */ 796 int asoc_sdw_startup(struct snd_pcm_substream *substream) 797 { 798 return sdw_startup_stream(substream); 799 } 800 EXPORT_SYMBOL_NS(asoc_sdw_startup, "SND_SOC_SDW_UTILS"); 801 802 int asoc_sdw_prepare(struct snd_pcm_substream *substream) 803 { 804 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 805 struct sdw_stream_runtime *sdw_stream; 806 struct snd_soc_dai *dai; 807 808 /* Find stream from first CPU DAI */ 809 dai = snd_soc_rtd_to_cpu(rtd, 0); 810 811 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 812 if (IS_ERR(sdw_stream)) { 813 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 814 return PTR_ERR(sdw_stream); 815 } 816 817 return sdw_prepare_stream(sdw_stream); 818 } 819 EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS"); 820 821 int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd) 822 { 823 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 824 struct sdw_stream_runtime *sdw_stream; 825 struct snd_soc_dai *dai; 826 int ret; 827 828 /* Find stream from first CPU DAI */ 829 dai = snd_soc_rtd_to_cpu(rtd, 0); 830 831 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 832 if (IS_ERR(sdw_stream)) { 833 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 834 return PTR_ERR(sdw_stream); 835 } 836 837 switch (cmd) { 838 case SNDRV_PCM_TRIGGER_START: 839 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 840 case SNDRV_PCM_TRIGGER_RESUME: 841 ret = sdw_enable_stream(sdw_stream); 842 break; 843 844 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 845 case SNDRV_PCM_TRIGGER_SUSPEND: 846 case SNDRV_PCM_TRIGGER_STOP: 847 ret = sdw_disable_stream(sdw_stream); 848 break; 849 default: 850 ret = -EINVAL; 851 break; 852 } 853 854 if (ret) 855 dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); 856 857 return ret; 858 } 859 EXPORT_SYMBOL_NS(asoc_sdw_trigger, "SND_SOC_SDW_UTILS"); 860 861 int asoc_sdw_hw_params(struct snd_pcm_substream *substream, 862 struct snd_pcm_hw_params *params) 863 { 864 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 865 struct snd_soc_dai_link_ch_map *ch_maps; 866 int ch = params_channels(params); 867 unsigned int ch_mask; 868 int num_codecs; 869 int step; 870 int i; 871 872 if (!rtd->dai_link->ch_maps) 873 return 0; 874 875 /* Identical data will be sent to all codecs in playback */ 876 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 877 ch_mask = GENMASK(ch - 1, 0); 878 step = 0; 879 } else { 880 num_codecs = rtd->dai_link->num_codecs; 881 882 if (ch < num_codecs || ch % num_codecs != 0) { 883 dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", 884 ch, num_codecs); 885 return -EINVAL; 886 } 887 888 ch_mask = GENMASK(ch / num_codecs - 1, 0); 889 step = hweight_long(ch_mask); 890 } 891 892 /* 893 * The captured data will be combined from each cpu DAI if the dai 894 * link has more than one codec DAIs. Set codec channel mask and 895 * ASoC will set the corresponding channel numbers for each cpu dai. 896 */ 897 for_each_link_ch_maps(rtd->dai_link, i, ch_maps) 898 ch_maps->ch_mask = ch_mask << (i * step); 899 900 return 0; 901 } 902 EXPORT_SYMBOL_NS(asoc_sdw_hw_params, "SND_SOC_SDW_UTILS"); 903 904 int asoc_sdw_hw_free(struct snd_pcm_substream *substream) 905 { 906 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 907 struct sdw_stream_runtime *sdw_stream; 908 struct snd_soc_dai *dai; 909 910 /* Find stream from first CPU DAI */ 911 dai = snd_soc_rtd_to_cpu(rtd, 0); 912 913 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); 914 if (IS_ERR(sdw_stream)) { 915 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); 916 return PTR_ERR(sdw_stream); 917 } 918 919 return sdw_deprepare_stream(sdw_stream); 920 } 921 EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS"); 922 923 void asoc_sdw_shutdown(struct snd_pcm_substream *substream) 924 { 925 sdw_shutdown_stream(substream); 926 } 927 EXPORT_SYMBOL_NS(asoc_sdw_shutdown, "SND_SOC_SDW_UTILS"); 928 929 static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, 930 unsigned int sdw_version, 931 unsigned int mfg_id, 932 unsigned int part_id, 933 unsigned int class_id, 934 int index_in_link) 935 { 936 int i; 937 938 for (i = 0; i < adr_link->num_adr; i++) { 939 unsigned int sdw1_version, mfg1_id, part1_id, class1_id; 940 u64 adr; 941 942 /* skip itself */ 943 if (i == index_in_link) 944 continue; 945 946 adr = adr_link->adr_d[i].adr; 947 948 sdw1_version = SDW_VERSION(adr); 949 mfg1_id = SDW_MFG_ID(adr); 950 part1_id = SDW_PART_ID(adr); 951 class1_id = SDW_CLASS_ID(adr); 952 953 if (sdw_version == sdw1_version && 954 mfg_id == mfg1_id && 955 part_id == part1_id && 956 class_id == class1_id) 957 return false; 958 } 959 960 return true; 961 } 962 963 static const char *_asoc_sdw_get_codec_name(struct device *dev, 964 const struct asoc_sdw_codec_info *codec_info, 965 const struct snd_soc_acpi_link_adr *adr_link, 966 int adr_index) 967 { 968 u64 adr = adr_link->adr_d[adr_index].adr; 969 unsigned int sdw_version = SDW_VERSION(adr); 970 unsigned int link_id = SDW_DISCO_LINK_ID(adr); 971 unsigned int unique_id = SDW_UNIQUE_ID(adr); 972 unsigned int mfg_id = SDW_MFG_ID(adr); 973 unsigned int part_id = SDW_PART_ID(adr); 974 unsigned int class_id = SDW_CLASS_ID(adr); 975 976 if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id, 977 class_id, adr_index)) 978 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", 979 link_id, mfg_id, part_id, class_id); 980 981 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", 982 link_id, mfg_id, part_id, class_id, unique_id); 983 } 984 985 const char *asoc_sdw_get_codec_name(struct device *dev, 986 const struct asoc_sdw_codec_info *codec_info, 987 const struct snd_soc_acpi_link_adr *adr_link, 988 int adr_index) 989 { 990 if (codec_info->codec_name) 991 return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL); 992 993 return _asoc_sdw_get_codec_name(dev, codec_info, adr_link, adr_index); 994 } 995 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS"); 996 997 /* helper to get the link that the codec DAI is used */ 998 struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card, 999 const char *dai_name) 1000 { 1001 struct snd_soc_dai_link *dai_link; 1002 int i; 1003 int j; 1004 1005 for_each_card_prelinks(card, i, dai_link) { 1006 for (j = 0; j < dai_link->num_codecs; j++) { 1007 /* Check each codec in a link */ 1008 if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) 1009 return dai_link; 1010 } 1011 } 1012 return NULL; 1013 } 1014 EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, "SND_SOC_SDW_UTILS"); 1015 1016 void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card) 1017 { 1018 struct snd_soc_dai_link *dai_link; 1019 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1020 int ret; 1021 int i, j; 1022 1023 for (i = 0; i < ctx->codec_info_list_count; i++) { 1024 for (j = 0; j < codec_info_list[i].dai_num; j++) { 1025 codec_info_list[i].dais[j].rtd_init_done = false; 1026 /* Check each dai in codec_info_lis to see if it is used in the link */ 1027 if (!codec_info_list[i].dais[j].exit) 1028 continue; 1029 /* 1030 * We don't need to call .exit function if there is no matched 1031 * dai link found. 1032 */ 1033 dai_link = asoc_sdw_mc_find_codec_dai_used(card, 1034 codec_info_list[i].dais[j].dai_name); 1035 if (dai_link) { 1036 /* Do the .exit function if the codec dai is used in the link */ 1037 ret = codec_info_list[i].dais[j].exit(card, dai_link); 1038 if (ret) 1039 dev_warn(card->dev, 1040 "codec exit failed %d\n", 1041 ret); 1042 break; 1043 } 1044 } 1045 } 1046 } 1047 EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, "SND_SOC_SDW_UTILS"); 1048 1049 int asoc_sdw_card_late_probe(struct snd_soc_card *card) 1050 { 1051 int ret = 0; 1052 int i; 1053 1054 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { 1055 if (codec_info_list[i].codec_card_late_probe) { 1056 ret = codec_info_list[i].codec_card_late_probe(card); 1057 if (ret < 0) 1058 return ret; 1059 } 1060 } 1061 return ret; 1062 } 1063 EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, "SND_SOC_SDW_UTILS"); 1064 1065 void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, 1066 int *be_id, char *name, int playback, int capture, 1067 struct snd_soc_dai_link_component *cpus, int cpus_num, 1068 struct snd_soc_dai_link_component *platform_component, 1069 int num_platforms, struct snd_soc_dai_link_component *codecs, 1070 int codecs_num, int no_pcm, 1071 int (*init)(struct snd_soc_pcm_runtime *rtd), 1072 const struct snd_soc_ops *ops) 1073 { 1074 dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); 1075 dai_links->id = (*be_id)++; 1076 dai_links->name = name; 1077 dai_links->stream_name = name; 1078 dai_links->platforms = platform_component; 1079 dai_links->num_platforms = num_platforms; 1080 dai_links->no_pcm = no_pcm; 1081 dai_links->cpus = cpus; 1082 dai_links->num_cpus = cpus_num; 1083 dai_links->codecs = codecs; 1084 dai_links->num_codecs = codecs_num; 1085 dai_links->playback_only = playback && !capture; 1086 dai_links->capture_only = !playback && capture; 1087 dai_links->init = init; 1088 dai_links->ops = ops; 1089 } 1090 EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, "SND_SOC_SDW_UTILS"); 1091 1092 int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, 1093 int *be_id, char *name, int playback, int capture, 1094 const char *cpu_dai_name, const char *platform_comp_name, 1095 const char *codec_name, const char *codec_dai_name, 1096 int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd), 1097 const struct snd_soc_ops *ops) 1098 { 1099 struct snd_soc_dai_link_component *dlc; 1100 1101 /* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */ 1102 dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL); 1103 if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name) 1104 return -ENOMEM; 1105 1106 dlc[0].dai_name = cpu_dai_name; 1107 dlc[1].name = platform_comp_name; 1108 1109 dlc[2].name = codec_name; 1110 dlc[2].dai_name = codec_dai_name; 1111 1112 asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture, 1113 &dlc[0], 1, &dlc[1], 1, &dlc[2], 1, 1114 no_pcm, init, ops); 1115 1116 return 0; 1117 } 1118 EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS"); 1119 1120 int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) 1121 { 1122 struct device *dev = card->dev; 1123 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); 1124 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1125 const struct snd_soc_acpi_link_adr *adr_link; 1126 int i; 1127 1128 for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { 1129 *num_devs += adr_link->num_adr; 1130 1131 for (i = 0; i < adr_link->num_adr; i++) 1132 *num_ends += adr_link->adr_d[i].num_endpoints; 1133 } 1134 1135 dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); 1136 1137 return 0; 1138 } 1139 EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, "SND_SOC_SDW_UTILS"); 1140 1141 struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, 1142 const struct snd_soc_acpi_endpoint *new) 1143 { 1144 while (dailinks->initialised) { 1145 if (new->aggregated && dailinks->group_id == new->group_id) 1146 return dailinks; 1147 1148 dailinks++; 1149 } 1150 1151 INIT_LIST_HEAD(&dailinks->endpoints); 1152 dailinks->group_id = new->group_id; 1153 dailinks->initialised = true; 1154 1155 return dailinks; 1156 } 1157 EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS"); 1158 1159 static int asoc_sdw_get_dai_type(u32 type) 1160 { 1161 switch (type) { 1162 case SDCA_FUNCTION_TYPE_SMART_AMP: 1163 case SDCA_FUNCTION_TYPE_SIMPLE_AMP: 1164 return SOC_SDW_DAI_TYPE_AMP; 1165 case SDCA_FUNCTION_TYPE_SMART_MIC: 1166 case SDCA_FUNCTION_TYPE_SIMPLE_MIC: 1167 case SDCA_FUNCTION_TYPE_SPEAKER_MIC: 1168 return SOC_SDW_DAI_TYPE_MIC; 1169 case SDCA_FUNCTION_TYPE_UAJ: 1170 case SDCA_FUNCTION_TYPE_RJ: 1171 case SDCA_FUNCTION_TYPE_SIMPLE_JACK: 1172 return SOC_SDW_DAI_TYPE_JACK; 1173 default: 1174 return -EINVAL; 1175 } 1176 } 1177 1178 /* 1179 * Check if the SDCA endpoint is present by the SDW peripheral 1180 * 1181 * @dev: Device pointer 1182 * @codec_info: Codec info pointer 1183 * @adr_link: ACPI link address 1184 * @adr_index: Index of the ACPI link address 1185 * @end_index: Index of the endpoint 1186 * 1187 * Return: 1 if the endpoint is present, 1188 * 0 if the endpoint is not present, 1189 * negative error code. 1190 */ 1191 1192 static int is_sdca_endpoint_present(struct device *dev, 1193 struct asoc_sdw_codec_info *codec_info, 1194 const struct snd_soc_acpi_link_adr *adr_link, 1195 int adr_index, int end_index) 1196 { 1197 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index]; 1198 const struct snd_soc_acpi_endpoint *adr_end; 1199 const struct asoc_sdw_dai_info *dai_info; 1200 struct snd_soc_dai_link_component *dlc; 1201 struct snd_soc_dai *codec_dai; 1202 struct sdw_slave *slave; 1203 struct device *sdw_dev; 1204 const char *sdw_codec_name; 1205 int i; 1206 1207 dlc = kzalloc(sizeof(*dlc), GFP_KERNEL); 1208 if (!dlc) 1209 return -ENOMEM; 1210 1211 adr_end = &adr_dev->endpoints[end_index]; 1212 dai_info = &codec_info->dais[adr_end->num]; 1213 1214 dlc->dai_name = dai_info->dai_name; 1215 codec_dai = snd_soc_find_dai_with_mutex(dlc); 1216 if (!codec_dai) { 1217 dev_warn(dev, "codec dai %s not registered yet\n", dlc->dai_name); 1218 kfree(dlc); 1219 return -EPROBE_DEFER; 1220 } 1221 kfree(dlc); 1222 1223 sdw_codec_name = _asoc_sdw_get_codec_name(dev, codec_info, 1224 adr_link, adr_index); 1225 if (!sdw_codec_name) 1226 return -ENOMEM; 1227 1228 sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); 1229 if (!sdw_dev) { 1230 dev_err(dev, "codec %s not found\n", sdw_codec_name); 1231 return -EINVAL; 1232 } 1233 1234 slave = dev_to_sdw_dev(sdw_dev); 1235 if (!slave) 1236 return -EINVAL; 1237 1238 /* Make sure BIOS provides SDCA properties */ 1239 if (!slave->sdca_data.interface_revision) { 1240 dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n"); 1241 return 1; 1242 } 1243 1244 for (i = 0; i < slave->sdca_data.num_functions; i++) { 1245 int dai_type = asoc_sdw_get_dai_type(slave->sdca_data.function[i].type); 1246 1247 if (dai_type == dai_info->dai_type) { 1248 dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n", 1249 dai_type, slave->sdca_data.function[i].name); 1250 return 1; 1251 } 1252 } 1253 1254 dev_dbg(&slave->dev, 1255 "SDCA device function for DAI type %d not supported, skip endpoint\n", 1256 dai_info->dai_type); 1257 1258 return 0; 1259 } 1260 1261 int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, 1262 struct asoc_sdw_dailink *soc_dais, 1263 struct asoc_sdw_endpoint *soc_ends, 1264 int *num_devs) 1265 { 1266 struct device *dev = card->dev; 1267 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 1268 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); 1269 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; 1270 const struct snd_soc_acpi_link_adr *adr_link; 1271 struct asoc_sdw_endpoint *soc_end = soc_ends; 1272 int num_dais = 0; 1273 int i, j; 1274 int ret; 1275 1276 for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { 1277 int num_link_dailinks = 0; 1278 1279 if (!is_power_of_2(adr_link->mask)) { 1280 dev_err(dev, "link with multiple mask bits: 0x%x\n", 1281 adr_link->mask); 1282 return -EINVAL; 1283 } 1284 1285 for (i = 0; i < adr_link->num_adr; i++) { 1286 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; 1287 struct asoc_sdw_codec_info *codec_info; 1288 const char *codec_name; 1289 bool check_sdca = false; 1290 1291 if (!adr_dev->name_prefix) { 1292 dev_err(dev, "codec 0x%llx does not have a name prefix\n", 1293 adr_dev->adr); 1294 return -EINVAL; 1295 } 1296 1297 codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); 1298 if (!codec_info) 1299 return -EINVAL; 1300 1301 ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; 1302 1303 codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i); 1304 if (!codec_name) 1305 return -ENOMEM; 1306 1307 dev_dbg(dev, "Adding prefix %s for %s\n", 1308 adr_dev->name_prefix, codec_name); 1309 1310 soc_end->name_prefix = adr_dev->name_prefix; 1311 1312 if (codec_info->count_sidecar && codec_info->add_sidecar) { 1313 ret = codec_info->count_sidecar(card, &num_dais, num_devs); 1314 if (ret) 1315 return ret; 1316 1317 soc_end->include_sidecar = true; 1318 } 1319 1320 if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1) 1321 check_sdca = true; 1322 1323 for (j = 0; j < adr_dev->num_endpoints; j++) { 1324 const struct snd_soc_acpi_endpoint *adr_end; 1325 const struct asoc_sdw_dai_info *dai_info; 1326 struct asoc_sdw_dailink *soc_dai; 1327 int stream; 1328 1329 adr_end = &adr_dev->endpoints[j]; 1330 dai_info = &codec_info->dais[adr_end->num]; 1331 soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); 1332 1333 /* 1334 * quirk should have higher priority than the sdca properties 1335 * in the BIOS. We can't always check the DAI quirk because we 1336 * will set the mc_quirk when the BIOS doesn't provide the right 1337 * information. The endpoint will be skipped if the dai_info-> 1338 * quirk_exclude and mc_quirk are both not set if we always skip 1339 * the endpoint according to the quirk information. We need to 1340 * keep the endpoint if it is present in the BIOS. So, only 1341 * check the DAI quirk when the mc_quirk is set or SDCA endpoint 1342 * present check is not needed. 1343 */ 1344 if (dai_info->quirk & ctx->mc_quirk || !check_sdca) { 1345 /* 1346 * Check the endpoint if a matching quirk is set or SDCA 1347 * endpoint check is not necessary 1348 */ 1349 if (dai_info->quirk && 1350 !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) 1351 continue; 1352 } else { 1353 /* Check SDCA codec endpoint if there is no matching quirk */ 1354 ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j); 1355 if (ret < 0) 1356 return ret; 1357 1358 /* The endpoint is not present, skip */ 1359 if (!ret) 1360 continue; 1361 } 1362 1363 dev_dbg(dev, 1364 "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n", 1365 ffs(adr_link->mask) - 1, adr_dev->adr, 1366 adr_end->num, dai_info->dai_type, 1367 dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-', 1368 dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-', 1369 adr_end->aggregated ? "group" : "solo", 1370 adr_end->group_id); 1371 1372 if (adr_end->num >= codec_info->dai_num) { 1373 dev_err(dev, 1374 "%d is too many endpoints for codec: 0x%x\n", 1375 adr_end->num, codec_info->part_id); 1376 return -EINVAL; 1377 } 1378 1379 for_each_pcm_streams(stream) { 1380 if (dai_info->direction[stream] && 1381 dai_info->dailink[stream] < 0) { 1382 dev_err(dev, 1383 "Invalid dailink id %d for codec: 0x%x\n", 1384 dai_info->dailink[stream], 1385 codec_info->part_id); 1386 return -EINVAL; 1387 } 1388 1389 if (dai_info->direction[stream]) { 1390 num_dais += !soc_dai->num_devs[stream]; 1391 soc_dai->num_devs[stream]++; 1392 soc_dai->link_mask[stream] |= adr_link->mask; 1393 } 1394 } 1395 1396 num_link_dailinks += !!list_empty(&soc_dai->endpoints); 1397 list_add_tail(&soc_end->list, &soc_dai->endpoints); 1398 1399 soc_end->link_mask = adr_link->mask; 1400 soc_end->codec_name = codec_name; 1401 soc_end->codec_info = codec_info; 1402 soc_end->dai_info = dai_info; 1403 soc_end++; 1404 } 1405 } 1406 1407 ctx->append_dai_type |= (num_link_dailinks > 1); 1408 } 1409 1410 return num_dais; 1411 } 1412 EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, "SND_SOC_SDW_UTILS"); 1413 1414 MODULE_LICENSE("GPL"); 1415 MODULE_DESCRIPTION("SoundWire ASoC helpers"); 1416