1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2022 Intel Corporation. All rights reserved. 4 5 /* 6 * sof_ssp_amp.c - ASoc Machine driver for Intel platforms 7 * with RT1308/CS35L41 codec. 8 */ 9 10 #include <linux/acpi.h> 11 #include <linux/delay.h> 12 #include <linux/dmi.h> 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 #include <sound/core.h> 16 #include <sound/jack.h> 17 #include <sound/pcm.h> 18 #include <sound/pcm_params.h> 19 #include <sound/sof.h> 20 #include "../../codecs/hdac_hdmi.h" 21 #include "hda_dsp_common.h" 22 #include "sof_realtek_common.h" 23 #include "sof_cirrus_common.h" 24 #include "sof_ssp_common.h" 25 26 #define NAME_SIZE 32 27 28 /* SSP port ID for speaker amplifier */ 29 #define SOF_AMPLIFIER_SSP(quirk) ((quirk) & GENMASK(3, 0)) 30 #define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0)) 31 32 /* HDMI capture*/ 33 #define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(4) 34 #define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 5 35 #define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(6, 5)) 36 #define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \ 37 (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) 38 39 #define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7 40 #define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7)) 41 #define SOF_HDMI_CAPTURE_1_SSP(quirk) \ 42 (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK) 43 44 #define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10 45 #define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10)) 46 #define SOF_HDMI_CAPTURE_2_SSP(quirk) \ 47 (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK) 48 49 /* HDMI playback */ 50 #define SOF_HDMI_PLAYBACK_PRESENT BIT(13) 51 #define SOF_NO_OF_HDMI_PLAYBACK_SHIFT 14 52 #define SOF_NO_OF_HDMI_PLAYBACK_MASK (GENMASK(16, 14)) 53 #define SOF_NO_OF_HDMI_PLAYBACK(quirk) \ 54 (((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK) 55 56 /* BT audio offload */ 57 #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(17) 58 #define SOF_BT_OFFLOAD_SSP_SHIFT 18 59 #define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(20, 18)) 60 #define SOF_BT_OFFLOAD_SSP(quirk) \ 61 (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) 62 63 /* Default: SSP2 */ 64 static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2); 65 66 struct sof_hdmi_pcm { 67 struct list_head head; 68 struct snd_soc_jack sof_hdmi; 69 struct snd_soc_dai *codec_dai; 70 int device; 71 }; 72 73 struct sof_card_private { 74 struct list_head hdmi_pcm_list; 75 bool common_hdmi_codec_drv; 76 bool idisp_codec; 77 enum sof_ssp_codec amp_type; 78 }; 79 80 static const struct dmi_system_id chromebook_platforms[] = { 81 { 82 .ident = "Google Chromebooks", 83 .matches = { 84 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 85 } 86 }, 87 {}, 88 }; 89 90 static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = { 91 SND_SOC_DAPM_MIC("SoC DMIC", NULL), 92 }; 93 94 static const struct snd_soc_dapm_route sof_ssp_amp_dapm_routes[] = { 95 /* digital mics */ 96 {"DMic", NULL, "SoC DMIC"}, 97 }; 98 99 static int sof_card_late_probe(struct snd_soc_card *card) 100 { 101 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); 102 struct snd_soc_component *component = NULL; 103 char jack_name[NAME_SIZE]; 104 struct sof_hdmi_pcm *pcm; 105 int err; 106 107 if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT)) 108 return 0; 109 110 /* HDMI is not supported by SOF on Baytrail/CherryTrail */ 111 if (!ctx->idisp_codec) 112 return 0; 113 114 if (list_empty(&ctx->hdmi_pcm_list)) 115 return -EINVAL; 116 117 if (ctx->common_hdmi_codec_drv) { 118 pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, 119 head); 120 component = pcm->codec_dai->component; 121 return hda_dsp_hdmi_build_controls(card, component); 122 } 123 124 list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { 125 component = pcm->codec_dai->component; 126 snprintf(jack_name, sizeof(jack_name), 127 "HDMI/DP, pcm=%d Jack", pcm->device); 128 err = snd_soc_card_jack_new(card, jack_name, 129 SND_JACK_AVOUT, &pcm->sof_hdmi); 130 131 if (err) 132 return err; 133 134 err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, 135 &pcm->sof_hdmi); 136 if (err < 0) 137 return err; 138 } 139 140 return hdac_hdmi_jack_port_init(component, &card->dapm); 141 } 142 143 static struct snd_soc_card sof_ssp_amp_card = { 144 .name = "ssp_amp", 145 .owner = THIS_MODULE, 146 .dapm_widgets = sof_ssp_amp_dapm_widgets, 147 .num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets), 148 .dapm_routes = sof_ssp_amp_dapm_routes, 149 .num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes), 150 .fully_routed = true, 151 .late_probe = sof_card_late_probe, 152 }; 153 154 static struct snd_soc_dai_link_component platform_component[] = { 155 { 156 /* name might be overridden during probe */ 157 .name = "0000:00:1f.3" 158 } 159 }; 160 161 static struct snd_soc_dai_link_component dmic_component[] = { 162 { 163 .name = "dmic-codec", 164 .dai_name = "dmic-hifi", 165 } 166 }; 167 168 static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) 169 { 170 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 171 struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); 172 struct sof_hdmi_pcm *pcm; 173 174 pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); 175 if (!pcm) 176 return -ENOMEM; 177 178 /* dai_link id is 1:1 mapped to the PCM device */ 179 pcm->device = rtd->dai_link->id; 180 pcm->codec_dai = dai; 181 182 list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); 183 184 return 0; 185 } 186 187 #define IDISP_CODEC_MASK 0x4 188 189 /* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */ 190 #define HDMI_IN_BE_ID 0 191 #define SPK_BE_ID 2 192 #define DMIC01_BE_ID 3 193 #define INTEL_HDMI_BE_ID 5 194 195 static struct snd_soc_dai_link * 196 sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, 197 int ssp_codec, int dmic_be_num, int hdmi_num, 198 bool idisp_codec) 199 { 200 struct snd_soc_dai_link_component *idisp_components; 201 struct snd_soc_dai_link_component *cpus; 202 struct snd_soc_dai_link *links; 203 int i, id = 0; 204 bool fixed_be = false; 205 206 links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, 207 sizeof(struct snd_soc_dai_link), GFP_KERNEL); 208 cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links, 209 sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); 210 if (!links || !cpus) 211 return NULL; 212 213 /* HDMI-In SSP */ 214 if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) { 215 int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> 216 SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; 217 218 /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ 219 fixed_be = true; 220 221 for (i = 1; i <= num_of_hdmi_ssp; i++) { 222 int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> 223 SOF_HDMI_CAPTURE_1_SSP_SHIFT : 224 (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >> 225 SOF_HDMI_CAPTURE_2_SSP_SHIFT); 226 227 links[id].cpus = &cpus[id]; 228 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 229 "SSP%d Pin", port); 230 if (!links[id].cpus->dai_name) 231 return NULL; 232 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); 233 if (!links[id].name) 234 return NULL; 235 links[id].id = fixed_be ? (HDMI_IN_BE_ID + i - 1) : id; 236 links[id].codecs = &snd_soc_dummy_dlc; 237 links[id].num_codecs = 1; 238 links[id].platforms = platform_component; 239 links[id].num_platforms = ARRAY_SIZE(platform_component); 240 links[id].dpcm_capture = 1; 241 links[id].no_pcm = 1; 242 links[id].num_cpus = 1; 243 id++; 244 } 245 } 246 247 /* codec SSP */ 248 if (amp_type != CODEC_NONE) { 249 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); 250 if (!links[id].name) 251 return NULL; 252 253 links[id].id = fixed_be ? SPK_BE_ID : id; 254 255 switch (amp_type) { 256 case CODEC_CS35L41: 257 cs35l41_set_dai_link(&links[id]); 258 break; 259 case CODEC_RT1308: 260 sof_rt1308_dai_link(&links[id]); 261 break; 262 default: 263 dev_err(dev, "invalid amp type %d\n", amp_type); 264 return NULL; 265 } 266 267 links[id].platforms = platform_component; 268 links[id].num_platforms = ARRAY_SIZE(platform_component); 269 links[id].dpcm_playback = 1; 270 /* feedback from amplifier or firmware-generated echo reference */ 271 links[id].dpcm_capture = 1; 272 links[id].no_pcm = 1; 273 links[id].cpus = &cpus[id]; 274 links[id].num_cpus = 1; 275 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec); 276 if (!links[id].cpus->dai_name) 277 return NULL; 278 279 id++; 280 } 281 282 /* dmic */ 283 if (dmic_be_num > 0) { 284 /* at least we have dmic01 */ 285 links[id].name = "dmic01"; 286 links[id].cpus = &cpus[id]; 287 links[id].cpus->dai_name = "DMIC01 Pin"; 288 if (dmic_be_num > 1) { 289 /* set up 2 BE links at most */ 290 links[id + 1].name = "dmic16k"; 291 links[id + 1].cpus = &cpus[id + 1]; 292 links[id + 1].cpus->dai_name = "DMIC16k Pin"; 293 dmic_be_num = 2; 294 } 295 } 296 297 for (i = 0; i < dmic_be_num; i++) { 298 links[id].id = fixed_be ? (DMIC01_BE_ID + i) : id; 299 links[id].num_cpus = 1; 300 links[id].codecs = dmic_component; 301 links[id].num_codecs = ARRAY_SIZE(dmic_component); 302 links[id].platforms = platform_component; 303 links[id].num_platforms = ARRAY_SIZE(platform_component); 304 links[id].ignore_suspend = 1; 305 links[id].dpcm_capture = 1; 306 links[id].no_pcm = 1; 307 id++; 308 } 309 310 /* HDMI playback */ 311 if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { 312 /* HDMI */ 313 if (hdmi_num > 0) { 314 idisp_components = devm_kcalloc(dev, 315 hdmi_num, 316 sizeof(struct snd_soc_dai_link_component), 317 GFP_KERNEL); 318 if (!idisp_components) 319 goto devm_err; 320 } 321 for (i = 1; i <= hdmi_num; i++) { 322 links[id].name = devm_kasprintf(dev, GFP_KERNEL, 323 "iDisp%d", i); 324 if (!links[id].name) 325 goto devm_err; 326 327 links[id].id = fixed_be ? (INTEL_HDMI_BE_ID + i - 1) : id; 328 links[id].cpus = &cpus[id]; 329 links[id].num_cpus = 1; 330 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 331 "iDisp%d Pin", i); 332 if (!links[id].cpus->dai_name) 333 goto devm_err; 334 335 if (idisp_codec) { 336 idisp_components[i - 1].name = "ehdaudio0D2"; 337 idisp_components[i - 1].dai_name = devm_kasprintf(dev, 338 GFP_KERNEL, 339 "intel-hdmi-hifi%d", 340 i); 341 if (!idisp_components[i - 1].dai_name) 342 goto devm_err; 343 } else { 344 idisp_components[i - 1] = snd_soc_dummy_dlc; 345 } 346 347 links[id].codecs = &idisp_components[i - 1]; 348 links[id].num_codecs = 1; 349 links[id].platforms = platform_component; 350 links[id].num_platforms = ARRAY_SIZE(platform_component); 351 links[id].init = sof_hdmi_init; 352 links[id].dpcm_playback = 1; 353 links[id].no_pcm = 1; 354 id++; 355 } 356 } 357 358 /* BT audio offload */ 359 if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { 360 int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> 361 SOF_BT_OFFLOAD_SSP_SHIFT; 362 363 links[id].id = id; 364 links[id].cpus = &cpus[id]; 365 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 366 "SSP%d Pin", port); 367 if (!links[id].cpus->dai_name) 368 goto devm_err; 369 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); 370 if (!links[id].name) 371 goto devm_err; 372 links[id].codecs = &snd_soc_dummy_dlc; 373 links[id].num_codecs = 1; 374 links[id].platforms = platform_component; 375 links[id].num_platforms = ARRAY_SIZE(platform_component); 376 links[id].dpcm_playback = 1; 377 links[id].dpcm_capture = 1; 378 links[id].no_pcm = 1; 379 links[id].num_cpus = 1; 380 id++; 381 } 382 383 return links; 384 devm_err: 385 return NULL; 386 } 387 388 static int sof_ssp_amp_probe(struct platform_device *pdev) 389 { 390 struct snd_soc_dai_link *dai_links; 391 struct snd_soc_acpi_mach *mach; 392 struct sof_card_private *ctx; 393 int dmic_be_num = 0, hdmi_num = 0; 394 int ret, ssp_codec; 395 396 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 397 if (!ctx) 398 return -ENOMEM; 399 400 if (pdev->id_entry && pdev->id_entry->driver_data) 401 sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data; 402 403 mach = pdev->dev.platform_data; 404 405 ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); 406 407 if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0) 408 dmic_be_num = 2; 409 410 ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; 411 412 /* set number of dai links */ 413 sof_ssp_amp_card.num_links = dmic_be_num; 414 415 if (ctx->amp_type != CODEC_NONE) 416 sof_ssp_amp_card.num_links++; 417 418 if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) 419 sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> 420 SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; 421 422 if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { 423 hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >> 424 SOF_NO_OF_HDMI_PLAYBACK_SHIFT; 425 /* default number of HDMI DAI's */ 426 if (!hdmi_num) 427 hdmi_num = 3; 428 429 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) 430 ctx->idisp_codec = true; 431 432 sof_ssp_amp_card.num_links += hdmi_num; 433 } 434 435 if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) 436 sof_ssp_amp_card.num_links++; 437 438 dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, 439 ssp_codec, dmic_be_num, hdmi_num, 440 ctx->idisp_codec); 441 if (!dai_links) 442 return -ENOMEM; 443 444 sof_ssp_amp_card.dai_link = dai_links; 445 446 /* update codec_conf */ 447 switch (ctx->amp_type) { 448 case CODEC_CS35L41: 449 cs35l41_set_codec_conf(&sof_ssp_amp_card); 450 break; 451 case CODEC_NONE: 452 case CODEC_RT1308: 453 /* no codec conf required */ 454 break; 455 default: 456 dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); 457 return -EINVAL; 458 } 459 460 INIT_LIST_HEAD(&ctx->hdmi_pcm_list); 461 462 sof_ssp_amp_card.dev = &pdev->dev; 463 464 /* set platform name for each dailink */ 465 ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card, 466 mach->mach_params.platform); 467 if (ret) 468 return ret; 469 470 ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; 471 472 snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx); 473 474 return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card); 475 } 476 477 static const struct platform_device_id board_ids[] = { 478 { 479 .name = "sof_ssp_amp", 480 }, 481 { 482 .name = "tgl_rt1308_hdmi_ssp", 483 .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) | 484 SOF_NO_OF_HDMI_CAPTURE_SSP(2) | 485 SOF_HDMI_CAPTURE_1_SSP(1) | 486 SOF_HDMI_CAPTURE_2_SSP(5) | 487 SOF_SSP_HDMI_CAPTURE_PRESENT), 488 }, 489 { 490 .name = "adl_cs35l41", 491 .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) | 492 SOF_NO_OF_HDMI_PLAYBACK(4) | 493 SOF_HDMI_PLAYBACK_PRESENT | 494 SOF_BT_OFFLOAD_SSP(2) | 495 SOF_SSP_BT_OFFLOAD_PRESENT), 496 }, 497 { 498 .name = "adl_lt6911_hdmi_ssp", 499 .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | 500 SOF_HDMI_CAPTURE_1_SSP(0) | 501 SOF_HDMI_CAPTURE_2_SSP(2) | 502 SOF_SSP_HDMI_CAPTURE_PRESENT | 503 SOF_NO_OF_HDMI_PLAYBACK(3) | 504 SOF_HDMI_PLAYBACK_PRESENT), 505 }, 506 { 507 .name = "rpl_lt6911_hdmi_ssp", 508 .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | 509 SOF_HDMI_CAPTURE_1_SSP(0) | 510 SOF_HDMI_CAPTURE_2_SSP(2) | 511 SOF_SSP_HDMI_CAPTURE_PRESENT | 512 SOF_NO_OF_HDMI_PLAYBACK(3) | 513 SOF_HDMI_PLAYBACK_PRESENT), 514 }, 515 { } 516 }; 517 MODULE_DEVICE_TABLE(platform, board_ids); 518 519 static struct platform_driver sof_ssp_amp_driver = { 520 .probe = sof_ssp_amp_probe, 521 .driver = { 522 .name = "sof_ssp_amp", 523 .pm = &snd_soc_pm_ops, 524 }, 525 .id_table = board_ids, 526 }; 527 module_platform_driver(sof_ssp_amp_driver); 528 529 MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver"); 530 MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>"); 531 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 532 MODULE_LICENSE("GPL"); 533 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); 534 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); 535 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON); 536 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); 537