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