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 "sof_board_helpers.h" 21 #include "sof_realtek_common.h" 22 #include "sof_cirrus_common.h" 23 #include "sof_ssp_common.h" 24 25 /* SSP port ID for speaker amplifier */ 26 #define SOF_AMPLIFIER_SSP(quirk) ((quirk) & GENMASK(3, 0)) 27 #define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0)) 28 29 /* HDMI capture*/ 30 #define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(4) 31 #define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 5 32 #define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(6, 5)) 33 #define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \ 34 (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) 35 36 #define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7 37 #define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7)) 38 #define SOF_HDMI_CAPTURE_1_SSP(quirk) \ 39 (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK) 40 41 #define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10 42 #define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10)) 43 #define SOF_HDMI_CAPTURE_2_SSP(quirk) \ 44 (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK) 45 46 /* HDMI playback */ 47 #define SOF_HDMI_PLAYBACK_PRESENT BIT(13) 48 #define SOF_NO_OF_HDMI_PLAYBACK_SHIFT 14 49 #define SOF_NO_OF_HDMI_PLAYBACK_MASK (GENMASK(16, 14)) 50 #define SOF_NO_OF_HDMI_PLAYBACK(quirk) \ 51 (((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK) 52 53 /* BT audio offload */ 54 #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(17) 55 #define SOF_BT_OFFLOAD_SSP_SHIFT 18 56 #define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(20, 18)) 57 #define SOF_BT_OFFLOAD_SSP(quirk) \ 58 (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) 59 60 /* Default: SSP2 */ 61 static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2); 62 63 static const struct dmi_system_id chromebook_platforms[] = { 64 { 65 .ident = "Google Chromebooks", 66 .matches = { 67 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 68 } 69 }, 70 {}, 71 }; 72 73 static int sof_card_late_probe(struct snd_soc_card *card) 74 { 75 return sof_intel_board_card_late_probe(card); 76 } 77 78 static struct snd_soc_card sof_ssp_amp_card = { 79 .name = "ssp_amp", 80 .owner = THIS_MODULE, 81 .fully_routed = true, 82 .late_probe = sof_card_late_probe, 83 }; 84 85 static struct snd_soc_dai_link_component platform_component[] = { 86 { 87 /* name might be overridden during probe */ 88 .name = "0000:00:1f.3" 89 } 90 }; 91 92 /* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */ 93 #define HDMI_IN_BE_ID 0 94 #define SPK_BE_ID 2 95 #define DMIC01_BE_ID 3 96 #define DMIC16K_BE_ID 4 97 #define INTEL_HDMI_BE_ID 5 98 99 static struct snd_soc_dai_link * 100 sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, 101 int ssp_codec, int dmic_be_num, int hdmi_num, 102 bool idisp_codec) 103 { 104 struct snd_soc_dai_link_component *cpus; 105 struct snd_soc_dai_link *links; 106 int i; 107 int id = 0; 108 int ret; 109 bool fixed_be = false; 110 int be_id; 111 112 links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, 113 sizeof(struct snd_soc_dai_link), GFP_KERNEL); 114 cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links, 115 sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); 116 if (!links || !cpus) 117 return NULL; 118 119 /* HDMI-In SSP */ 120 if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) { 121 int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> 122 SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; 123 124 /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ 125 fixed_be = true; 126 127 for (i = 1; i <= num_of_hdmi_ssp; i++) { 128 int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> 129 SOF_HDMI_CAPTURE_1_SSP_SHIFT : 130 (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >> 131 SOF_HDMI_CAPTURE_2_SSP_SHIFT); 132 133 links[id].cpus = &cpus[id]; 134 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 135 "SSP%d Pin", port); 136 if (!links[id].cpus->dai_name) 137 return NULL; 138 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); 139 if (!links[id].name) 140 return NULL; 141 links[id].id = fixed_be ? (HDMI_IN_BE_ID + i - 1) : id; 142 links[id].codecs = &snd_soc_dummy_dlc; 143 links[id].num_codecs = 1; 144 links[id].platforms = platform_component; 145 links[id].num_platforms = ARRAY_SIZE(platform_component); 146 links[id].dpcm_capture = 1; 147 links[id].no_pcm = 1; 148 links[id].num_cpus = 1; 149 id++; 150 } 151 } 152 153 /* codec SSP */ 154 if (amp_type != CODEC_NONE) { 155 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); 156 if (!links[id].name) 157 return NULL; 158 159 links[id].id = fixed_be ? SPK_BE_ID : id; 160 161 switch (amp_type) { 162 case CODEC_CS35L41: 163 cs35l41_set_dai_link(&links[id]); 164 break; 165 case CODEC_RT1308: 166 sof_rt1308_dai_link(&links[id]); 167 break; 168 default: 169 dev_err(dev, "invalid amp type %d\n", amp_type); 170 return NULL; 171 } 172 173 links[id].platforms = platform_component; 174 links[id].num_platforms = ARRAY_SIZE(platform_component); 175 links[id].dpcm_playback = 1; 176 /* feedback from amplifier or firmware-generated echo reference */ 177 links[id].dpcm_capture = 1; 178 links[id].no_pcm = 1; 179 links[id].cpus = &cpus[id]; 180 links[id].num_cpus = 1; 181 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec); 182 if (!links[id].cpus->dai_name) 183 return NULL; 184 185 id++; 186 } 187 188 /* dmic */ 189 if (dmic_be_num > 0) { 190 /* at least we have dmic01 */ 191 be_id = fixed_be ? DMIC01_BE_ID : id; 192 ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id, 193 SOF_DMIC_01); 194 if (ret) 195 return NULL; 196 197 id++; 198 } 199 200 if (dmic_be_num > 1) { 201 /* set up 2 BE links at most */ 202 be_id = fixed_be ? DMIC16K_BE_ID : id; 203 ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id, 204 SOF_DMIC_16K); 205 if (ret) 206 return NULL; 207 208 id++; 209 } 210 211 /* HDMI playback */ 212 for (i = 1; i <= hdmi_num; i++) { 213 be_id = fixed_be ? (INTEL_HDMI_BE_ID + i - 1) : id; 214 ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], be_id, 215 i, idisp_codec); 216 if (ret) 217 return NULL; 218 219 id++; 220 } 221 222 /* BT audio offload */ 223 if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { 224 int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> 225 SOF_BT_OFFLOAD_SSP_SHIFT; 226 227 links[id].id = id; 228 links[id].cpus = &cpus[id]; 229 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 230 "SSP%d Pin", port); 231 if (!links[id].cpus->dai_name) 232 goto devm_err; 233 links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); 234 if (!links[id].name) 235 goto devm_err; 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_playback = 1; 241 links[id].dpcm_capture = 1; 242 links[id].no_pcm = 1; 243 links[id].num_cpus = 1; 244 id++; 245 } 246 247 return links; 248 devm_err: 249 return NULL; 250 } 251 252 static int sof_ssp_amp_probe(struct platform_device *pdev) 253 { 254 struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; 255 struct snd_soc_dai_link *dai_links; 256 struct sof_card_private *ctx; 257 int ret, ssp_codec; 258 259 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 260 if (!ctx) 261 return -ENOMEM; 262 263 if (pdev->id_entry && pdev->id_entry->driver_data) 264 sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data; 265 266 ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); 267 268 if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0) 269 ctx->dmic_be_num = 2; 270 else 271 ctx->dmic_be_num = 0; 272 273 ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; 274 275 /* set number of dai links */ 276 sof_ssp_amp_card.num_links = ctx->dmic_be_num; 277 278 if (ctx->amp_type != CODEC_NONE) 279 sof_ssp_amp_card.num_links++; 280 281 if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) 282 sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> 283 SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; 284 285 if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { 286 ctx->hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >> 287 SOF_NO_OF_HDMI_PLAYBACK_SHIFT; 288 /* default number of HDMI DAI's */ 289 if (!ctx->hdmi_num) 290 ctx->hdmi_num = 3; 291 292 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) 293 ctx->hdmi.idisp_codec = true; 294 295 sof_ssp_amp_card.num_links += ctx->hdmi_num; 296 } else { 297 ctx->hdmi_num = 0; 298 } 299 300 if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) 301 sof_ssp_amp_card.num_links++; 302 303 dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, 304 ssp_codec, ctx->dmic_be_num, 305 ctx->hdmi_num, 306 ctx->hdmi.idisp_codec); 307 if (!dai_links) 308 return -ENOMEM; 309 310 sof_ssp_amp_card.dai_link = dai_links; 311 312 /* update codec_conf */ 313 switch (ctx->amp_type) { 314 case CODEC_CS35L41: 315 cs35l41_set_codec_conf(&sof_ssp_amp_card); 316 break; 317 case CODEC_NONE: 318 case CODEC_RT1308: 319 /* no codec conf required */ 320 break; 321 default: 322 dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); 323 return -EINVAL; 324 } 325 326 sof_ssp_amp_card.dev = &pdev->dev; 327 328 /* set platform name for each dailink */ 329 ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card, 330 mach->mach_params.platform); 331 if (ret) 332 return ret; 333 334 snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx); 335 336 return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card); 337 } 338 339 static const struct platform_device_id board_ids[] = { 340 { 341 .name = "sof_ssp_amp", 342 }, 343 { 344 .name = "tgl_rt1308_hdmi_ssp", 345 .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) | 346 SOF_NO_OF_HDMI_CAPTURE_SSP(2) | 347 SOF_HDMI_CAPTURE_1_SSP(1) | 348 SOF_HDMI_CAPTURE_2_SSP(5) | 349 SOF_SSP_HDMI_CAPTURE_PRESENT), 350 }, 351 { 352 .name = "adl_cs35l41", 353 .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) | 354 SOF_NO_OF_HDMI_PLAYBACK(4) | 355 SOF_HDMI_PLAYBACK_PRESENT | 356 SOF_BT_OFFLOAD_SSP(2) | 357 SOF_SSP_BT_OFFLOAD_PRESENT), 358 }, 359 { 360 .name = "adl_lt6911_hdmi_ssp", 361 .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | 362 SOF_HDMI_CAPTURE_1_SSP(0) | 363 SOF_HDMI_CAPTURE_2_SSP(2) | 364 SOF_SSP_HDMI_CAPTURE_PRESENT | 365 SOF_NO_OF_HDMI_PLAYBACK(3) | 366 SOF_HDMI_PLAYBACK_PRESENT), 367 }, 368 { 369 .name = "rpl_lt6911_hdmi_ssp", 370 .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | 371 SOF_HDMI_CAPTURE_1_SSP(0) | 372 SOF_HDMI_CAPTURE_2_SSP(2) | 373 SOF_SSP_HDMI_CAPTURE_PRESENT | 374 SOF_NO_OF_HDMI_PLAYBACK(3) | 375 SOF_HDMI_PLAYBACK_PRESENT), 376 }, 377 { 378 .name = "mtl_lt6911_hdmi_ssp", 379 .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | 380 SOF_HDMI_CAPTURE_1_SSP(0) | 381 SOF_HDMI_CAPTURE_2_SSP(2) | 382 SOF_SSP_HDMI_CAPTURE_PRESENT | 383 SOF_NO_OF_HDMI_PLAYBACK(3) | 384 SOF_HDMI_PLAYBACK_PRESENT), 385 }, 386 { } 387 }; 388 MODULE_DEVICE_TABLE(platform, board_ids); 389 390 static struct platform_driver sof_ssp_amp_driver = { 391 .probe = sof_ssp_amp_probe, 392 .driver = { 393 .name = "sof_ssp_amp", 394 .pm = &snd_soc_pm_ops, 395 }, 396 .id_table = board_ids, 397 }; 398 module_platform_driver(sof_ssp_amp_driver); 399 400 MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver"); 401 MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>"); 402 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 403 MODULE_LICENSE("GPL"); 404 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); 405 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); 406 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON); 407 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); 408