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