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