12fe14ff6SBrent Lu // SPDX-License-Identifier: GPL-2.0-only 22fe14ff6SBrent Lu // 32fe14ff6SBrent Lu // Copyright(c) 2022 Intel Corporation. All rights reserved. 42fe14ff6SBrent Lu 52fe14ff6SBrent Lu /* 62fe14ff6SBrent Lu * sof_ssp_amp.c - ASoc Machine driver for Intel platforms 72fe14ff6SBrent Lu * with RT1308/CS35L41 codec. 82fe14ff6SBrent Lu */ 92fe14ff6SBrent Lu 102fe14ff6SBrent Lu #include <linux/acpi.h> 112fe14ff6SBrent Lu #include <linux/delay.h> 12d1c80876SBrent Lu #include <linux/dmi.h> 132fe14ff6SBrent Lu #include <linux/module.h> 142fe14ff6SBrent Lu #include <linux/platform_device.h> 152fe14ff6SBrent Lu #include <sound/core.h> 162fe14ff6SBrent Lu #include <sound/jack.h> 172fe14ff6SBrent Lu #include <sound/pcm.h> 182fe14ff6SBrent Lu #include <sound/pcm_params.h> 192fe14ff6SBrent Lu #include <sound/sof.h> 202fe14ff6SBrent Lu #include "../../codecs/hdac_hdmi.h" 212fe14ff6SBrent Lu #include "hda_dsp_common.h" 222fe14ff6SBrent Lu #include "sof_realtek_common.h" 232fe14ff6SBrent Lu #include "sof_cirrus_common.h" 242fe14ff6SBrent Lu 252fe14ff6SBrent Lu #define NAME_SIZE 32 262fe14ff6SBrent Lu 272fe14ff6SBrent Lu /* SSP port ID for speaker amplifier */ 282fe14ff6SBrent Lu #define SOF_AMPLIFIER_SSP(quirk) ((quirk) & GENMASK(3, 0)) 292fe14ff6SBrent Lu #define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0)) 302fe14ff6SBrent Lu 312fe14ff6SBrent Lu /* HDMI capture*/ 322fe14ff6SBrent Lu #define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(4) 332fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 5 342fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(6, 5)) 352fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \ 362fe14ff6SBrent Lu (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) 372fe14ff6SBrent Lu 382fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7 392fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7)) 402fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_1_SSP(quirk) \ 412fe14ff6SBrent Lu (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK) 422fe14ff6SBrent Lu 432fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10 442fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10)) 452fe14ff6SBrent Lu #define SOF_HDMI_CAPTURE_2_SSP(quirk) \ 462fe14ff6SBrent Lu (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK) 472fe14ff6SBrent Lu 482fe14ff6SBrent Lu /* HDMI playback */ 492fe14ff6SBrent Lu #define SOF_HDMI_PLAYBACK_PRESENT BIT(13) 502fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_PLAYBACK_SHIFT 14 512fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_PLAYBACK_MASK (GENMASK(16, 14)) 522fe14ff6SBrent Lu #define SOF_NO_OF_HDMI_PLAYBACK(quirk) \ 532fe14ff6SBrent Lu (((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK) 542fe14ff6SBrent Lu 552fe14ff6SBrent Lu /* BT audio offload */ 562fe14ff6SBrent Lu #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(17) 572fe14ff6SBrent Lu #define SOF_BT_OFFLOAD_SSP_SHIFT 18 582fe14ff6SBrent Lu #define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(20, 18)) 592fe14ff6SBrent Lu #define SOF_BT_OFFLOAD_SSP(quirk) \ 602fe14ff6SBrent Lu (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) 612fe14ff6SBrent Lu 622fe14ff6SBrent Lu /* Speaker amplifiers */ 632fe14ff6SBrent Lu #define SOF_RT1308_SPEAKER_AMP_PRESENT BIT(21) 642fe14ff6SBrent Lu #define SOF_CS35L41_SPEAKER_AMP_PRESENT BIT(22) 652fe14ff6SBrent Lu 662fe14ff6SBrent Lu /* Default: SSP2 */ 672fe14ff6SBrent Lu static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2); 682fe14ff6SBrent Lu 692fe14ff6SBrent Lu struct sof_hdmi_pcm { 702fe14ff6SBrent Lu struct list_head head; 712fe14ff6SBrent Lu struct snd_soc_jack sof_hdmi; 722fe14ff6SBrent Lu struct snd_soc_dai *codec_dai; 732fe14ff6SBrent Lu int device; 742fe14ff6SBrent Lu }; 752fe14ff6SBrent Lu 762fe14ff6SBrent Lu struct sof_card_private { 772fe14ff6SBrent Lu struct list_head hdmi_pcm_list; 782fe14ff6SBrent Lu bool common_hdmi_codec_drv; 792fe14ff6SBrent Lu bool idisp_codec; 802fe14ff6SBrent Lu }; 812fe14ff6SBrent Lu 82d1c80876SBrent Lu static const struct dmi_system_id chromebook_platforms[] = { 83d1c80876SBrent Lu { 84d1c80876SBrent Lu .ident = "Google Chromebooks", 85d1c80876SBrent Lu .matches = { 86d1c80876SBrent Lu DMI_MATCH(DMI_SYS_VENDOR, "Google"), 87d1c80876SBrent Lu } 88d1c80876SBrent Lu }, 89d1c80876SBrent Lu {}, 90d1c80876SBrent Lu }; 91d1c80876SBrent Lu 922fe14ff6SBrent Lu static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = { 932fe14ff6SBrent Lu SND_SOC_DAPM_MIC("SoC DMIC", NULL), 942fe14ff6SBrent Lu }; 952fe14ff6SBrent Lu 962fe14ff6SBrent Lu static const struct snd_soc_dapm_route sof_ssp_amp_dapm_routes[] = { 972fe14ff6SBrent Lu /* digital mics */ 982fe14ff6SBrent Lu {"DMic", NULL, "SoC DMIC"}, 992fe14ff6SBrent Lu }; 1002fe14ff6SBrent Lu 1012fe14ff6SBrent Lu static int sof_card_late_probe(struct snd_soc_card *card) 1022fe14ff6SBrent Lu { 1032fe14ff6SBrent Lu struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); 1042fe14ff6SBrent Lu struct snd_soc_component *component = NULL; 1052fe14ff6SBrent Lu char jack_name[NAME_SIZE]; 1062fe14ff6SBrent Lu struct sof_hdmi_pcm *pcm; 1072fe14ff6SBrent Lu int err; 108aa4c06e0SPierre-Louis Bossart int i; 1092fe14ff6SBrent Lu 1102fe14ff6SBrent Lu if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT)) 1112fe14ff6SBrent Lu return 0; 1122fe14ff6SBrent Lu 1132fe14ff6SBrent Lu /* HDMI is not supported by SOF on Baytrail/CherryTrail */ 1142fe14ff6SBrent Lu if (!ctx->idisp_codec) 1152fe14ff6SBrent Lu return 0; 1162fe14ff6SBrent Lu 1172fe14ff6SBrent Lu if (list_empty(&ctx->hdmi_pcm_list)) 1182fe14ff6SBrent Lu return -EINVAL; 1192fe14ff6SBrent Lu 1202fe14ff6SBrent Lu if (ctx->common_hdmi_codec_drv) { 1212fe14ff6SBrent Lu pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, 1222fe14ff6SBrent Lu head); 1232fe14ff6SBrent Lu component = pcm->codec_dai->component; 1242fe14ff6SBrent Lu return hda_dsp_hdmi_build_controls(card, component); 1252fe14ff6SBrent Lu } 1262fe14ff6SBrent Lu 127aa4c06e0SPierre-Louis Bossart i = 0; 1282fe14ff6SBrent Lu list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { 1292fe14ff6SBrent Lu component = pcm->codec_dai->component; 1302fe14ff6SBrent Lu snprintf(jack_name, sizeof(jack_name), 1312fe14ff6SBrent Lu "HDMI/DP, pcm=%d Jack", pcm->device); 1322fe14ff6SBrent Lu err = snd_soc_card_jack_new(card, jack_name, 13319aed2d6SAkihiko Odaki SND_JACK_AVOUT, &pcm->sof_hdmi); 1342fe14ff6SBrent Lu 1352fe14ff6SBrent Lu if (err) 1362fe14ff6SBrent Lu return err; 1372fe14ff6SBrent Lu 1382fe14ff6SBrent Lu err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, 1392fe14ff6SBrent Lu &pcm->sof_hdmi); 1402fe14ff6SBrent Lu if (err < 0) 1412fe14ff6SBrent Lu return err; 1422fe14ff6SBrent Lu 1432fe14ff6SBrent Lu i++; 1442fe14ff6SBrent Lu } 1452fe14ff6SBrent Lu 1462fe14ff6SBrent Lu return hdac_hdmi_jack_port_init(component, &card->dapm); 1472fe14ff6SBrent Lu } 1482fe14ff6SBrent Lu 1492fe14ff6SBrent Lu static struct snd_soc_card sof_ssp_amp_card = { 1502fe14ff6SBrent Lu .name = "ssp_amp", 1512fe14ff6SBrent Lu .owner = THIS_MODULE, 1522fe14ff6SBrent Lu .dapm_widgets = sof_ssp_amp_dapm_widgets, 1532fe14ff6SBrent Lu .num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets), 1542fe14ff6SBrent Lu .dapm_routes = sof_ssp_amp_dapm_routes, 1552fe14ff6SBrent Lu .num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes), 1562fe14ff6SBrent Lu .fully_routed = true, 1572fe14ff6SBrent Lu .late_probe = sof_card_late_probe, 1582fe14ff6SBrent Lu }; 1592fe14ff6SBrent Lu 1602fe14ff6SBrent Lu static struct snd_soc_dai_link_component platform_component[] = { 1612fe14ff6SBrent Lu { 1622fe14ff6SBrent Lu /* name might be overridden during probe */ 1632fe14ff6SBrent Lu .name = "0000:00:1f.3" 1642fe14ff6SBrent Lu } 1652fe14ff6SBrent Lu }; 1662fe14ff6SBrent Lu 1672fe14ff6SBrent Lu static struct snd_soc_dai_link_component dmic_component[] = { 1682fe14ff6SBrent Lu { 1692fe14ff6SBrent Lu .name = "dmic-codec", 1702fe14ff6SBrent Lu .dai_name = "dmic-hifi", 1712fe14ff6SBrent Lu } 1722fe14ff6SBrent Lu }; 1732fe14ff6SBrent Lu 1742fe14ff6SBrent Lu static struct snd_soc_dai_link_component dummy_component[] = { 1752fe14ff6SBrent Lu { 1762fe14ff6SBrent Lu .name = "snd-soc-dummy", 1772fe14ff6SBrent Lu .dai_name = "snd-soc-dummy-dai", 1782fe14ff6SBrent Lu } 1792fe14ff6SBrent Lu }; 1802fe14ff6SBrent Lu 1812fe14ff6SBrent Lu static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) 1822fe14ff6SBrent Lu { 1832fe14ff6SBrent Lu struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 1842fe14ff6SBrent Lu struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); 1852fe14ff6SBrent Lu struct sof_hdmi_pcm *pcm; 1862fe14ff6SBrent Lu 1872fe14ff6SBrent Lu pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); 1882fe14ff6SBrent Lu if (!pcm) 1892fe14ff6SBrent Lu return -ENOMEM; 1902fe14ff6SBrent Lu 1912fe14ff6SBrent Lu /* dai_link id is 1:1 mapped to the PCM device */ 1922fe14ff6SBrent Lu pcm->device = rtd->dai_link->id; 1932fe14ff6SBrent Lu pcm->codec_dai = dai; 1942fe14ff6SBrent Lu 1952fe14ff6SBrent Lu list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); 1962fe14ff6SBrent Lu 1972fe14ff6SBrent Lu return 0; 1982fe14ff6SBrent Lu } 1992fe14ff6SBrent Lu 2002fe14ff6SBrent Lu #define IDISP_CODEC_MASK 0x4 2012fe14ff6SBrent Lu 2022fe14ff6SBrent Lu static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, 2032fe14ff6SBrent Lu int ssp_codec, 2042fe14ff6SBrent Lu int dmic_be_num, 2052fe14ff6SBrent Lu int hdmi_num, 2062fe14ff6SBrent Lu bool idisp_codec) 2072fe14ff6SBrent Lu { 2082fe14ff6SBrent Lu struct snd_soc_dai_link_component *idisp_components; 2092fe14ff6SBrent Lu struct snd_soc_dai_link_component *cpus; 2102fe14ff6SBrent Lu struct snd_soc_dai_link *links; 2112fe14ff6SBrent Lu int i, id = 0; 2122fe14ff6SBrent Lu 21309dea5acSye xingchen links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, 21409dea5acSye xingchen sizeof(struct snd_soc_dai_link), GFP_KERNEL); 21509dea5acSye xingchen cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links, 21609dea5acSye xingchen sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); 2172fe14ff6SBrent Lu if (!links || !cpus) 2182fe14ff6SBrent Lu return NULL; 2192fe14ff6SBrent Lu 2202fe14ff6SBrent Lu /* HDMI-In SSP */ 2212fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) { 2222fe14ff6SBrent Lu int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> 2232fe14ff6SBrent Lu SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; 2242fe14ff6SBrent Lu 2252fe14ff6SBrent Lu for (i = 1; i <= num_of_hdmi_ssp; i++) { 2262fe14ff6SBrent Lu int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> 2272fe14ff6SBrent Lu SOF_HDMI_CAPTURE_1_SSP_SHIFT : 2282fe14ff6SBrent Lu (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >> 2292fe14ff6SBrent Lu SOF_HDMI_CAPTURE_2_SSP_SHIFT); 2302fe14ff6SBrent Lu 2312fe14ff6SBrent Lu links[id].cpus = &cpus[id]; 2322fe14ff6SBrent Lu links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 2332fe14ff6SBrent Lu "SSP%d Pin", port); 2342fe14ff6SBrent Lu if (!links[id].cpus->dai_name) 2352fe14ff6SBrent Lu return NULL; 2362fe14ff6SBrent Lu links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); 2372fe14ff6SBrent Lu if (!links[id].name) 2382fe14ff6SBrent Lu return NULL; 2392fe14ff6SBrent Lu links[id].id = id; 2402fe14ff6SBrent Lu links[id].codecs = dummy_component; 2412fe14ff6SBrent Lu links[id].num_codecs = ARRAY_SIZE(dummy_component); 2422fe14ff6SBrent Lu links[id].platforms = platform_component; 2432fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component); 2442fe14ff6SBrent Lu links[id].dpcm_capture = 1; 2452fe14ff6SBrent Lu links[id].no_pcm = 1; 2462fe14ff6SBrent Lu links[id].num_cpus = 1; 2472fe14ff6SBrent Lu id++; 2482fe14ff6SBrent Lu } 2492fe14ff6SBrent Lu } 2502fe14ff6SBrent Lu 2512fe14ff6SBrent Lu /* codec SSP */ 2522fe14ff6SBrent Lu links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); 2532fe14ff6SBrent Lu if (!links[id].name) 2542fe14ff6SBrent Lu return NULL; 2552fe14ff6SBrent Lu 2562fe14ff6SBrent Lu links[id].id = id; 2572fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) { 2582fe14ff6SBrent Lu sof_rt1308_dai_link(&links[id]); 2592fe14ff6SBrent Lu } else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) { 2602fe14ff6SBrent Lu cs35l41_set_dai_link(&links[id]); 2612fe14ff6SBrent Lu } 2622fe14ff6SBrent Lu links[id].platforms = platform_component; 2632fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component); 2642fe14ff6SBrent Lu links[id].dpcm_playback = 1; 265*b3c00316SPierre-Louis Bossart /* feedback from amplifier or firmware-generated echo reference */ 266*b3c00316SPierre-Louis Bossart links[id].dpcm_capture = 1; 2672fe14ff6SBrent Lu links[id].no_pcm = 1; 2682fe14ff6SBrent Lu links[id].cpus = &cpus[id]; 2692fe14ff6SBrent Lu links[id].num_cpus = 1; 2702fe14ff6SBrent Lu links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec); 2712fe14ff6SBrent Lu if (!links[id].cpus->dai_name) 2722fe14ff6SBrent Lu return NULL; 2732fe14ff6SBrent Lu 2742fe14ff6SBrent Lu id++; 2752fe14ff6SBrent Lu 2762fe14ff6SBrent Lu /* dmic */ 2772fe14ff6SBrent Lu if (dmic_be_num > 0) { 2782fe14ff6SBrent Lu /* at least we have dmic01 */ 2792fe14ff6SBrent Lu links[id].name = "dmic01"; 2802fe14ff6SBrent Lu links[id].cpus = &cpus[id]; 2812fe14ff6SBrent Lu links[id].cpus->dai_name = "DMIC01 Pin"; 2822fe14ff6SBrent Lu if (dmic_be_num > 1) { 2832fe14ff6SBrent Lu /* set up 2 BE links at most */ 2842fe14ff6SBrent Lu links[id + 1].name = "dmic16k"; 2852fe14ff6SBrent Lu links[id + 1].cpus = &cpus[id + 1]; 2862fe14ff6SBrent Lu links[id + 1].cpus->dai_name = "DMIC16k Pin"; 2872fe14ff6SBrent Lu dmic_be_num = 2; 2882fe14ff6SBrent Lu } 2892fe14ff6SBrent Lu } 2902fe14ff6SBrent Lu 2912fe14ff6SBrent Lu for (i = 0; i < dmic_be_num; i++) { 2922fe14ff6SBrent Lu links[id].id = id; 2932fe14ff6SBrent Lu links[id].num_cpus = 1; 2942fe14ff6SBrent Lu links[id].codecs = dmic_component; 2952fe14ff6SBrent Lu links[id].num_codecs = ARRAY_SIZE(dmic_component); 2962fe14ff6SBrent Lu links[id].platforms = platform_component; 2972fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component); 2982fe14ff6SBrent Lu links[id].ignore_suspend = 1; 2992fe14ff6SBrent Lu links[id].dpcm_capture = 1; 3002fe14ff6SBrent Lu links[id].no_pcm = 1; 3012fe14ff6SBrent Lu id++; 3022fe14ff6SBrent Lu } 3032fe14ff6SBrent Lu 3042fe14ff6SBrent Lu /* HDMI playback */ 3052fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { 3062fe14ff6SBrent Lu /* HDMI */ 3072fe14ff6SBrent Lu if (hdmi_num > 0) { 30809dea5acSye xingchen idisp_components = devm_kcalloc(dev, 30909dea5acSye xingchen hdmi_num, 31009dea5acSye xingchen sizeof(struct snd_soc_dai_link_component), 31109dea5acSye xingchen GFP_KERNEL); 3122fe14ff6SBrent Lu if (!idisp_components) 3132fe14ff6SBrent Lu goto devm_err; 3142fe14ff6SBrent Lu } 3152fe14ff6SBrent Lu for (i = 1; i <= hdmi_num; i++) { 3162fe14ff6SBrent Lu links[id].name = devm_kasprintf(dev, GFP_KERNEL, 3172fe14ff6SBrent Lu "iDisp%d", i); 3182fe14ff6SBrent Lu if (!links[id].name) 3192fe14ff6SBrent Lu goto devm_err; 3202fe14ff6SBrent Lu 3212fe14ff6SBrent Lu links[id].id = id; 3222fe14ff6SBrent Lu links[id].cpus = &cpus[id]; 3232fe14ff6SBrent Lu links[id].num_cpus = 1; 3242fe14ff6SBrent Lu links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 3252fe14ff6SBrent Lu "iDisp%d Pin", i); 3262fe14ff6SBrent Lu if (!links[id].cpus->dai_name) 3272fe14ff6SBrent Lu goto devm_err; 3282fe14ff6SBrent Lu 3292fe14ff6SBrent Lu if (idisp_codec) { 3302fe14ff6SBrent Lu idisp_components[i - 1].name = "ehdaudio0D2"; 3312fe14ff6SBrent Lu idisp_components[i - 1].dai_name = devm_kasprintf(dev, 3322fe14ff6SBrent Lu GFP_KERNEL, 3332fe14ff6SBrent Lu "intel-hdmi-hifi%d", 3342fe14ff6SBrent Lu i); 3352fe14ff6SBrent Lu if (!idisp_components[i - 1].dai_name) 3362fe14ff6SBrent Lu goto devm_err; 3372fe14ff6SBrent Lu } else { 3382fe14ff6SBrent Lu idisp_components[i - 1].name = "snd-soc-dummy"; 3392fe14ff6SBrent Lu idisp_components[i - 1].dai_name = "snd-soc-dummy-dai"; 3402fe14ff6SBrent Lu } 3412fe14ff6SBrent Lu 3422fe14ff6SBrent Lu links[id].codecs = &idisp_components[i - 1]; 3432fe14ff6SBrent Lu links[id].num_codecs = 1; 3442fe14ff6SBrent Lu links[id].platforms = platform_component; 3452fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component); 3462fe14ff6SBrent Lu links[id].init = sof_hdmi_init; 3472fe14ff6SBrent Lu links[id].dpcm_playback = 1; 3482fe14ff6SBrent Lu links[id].no_pcm = 1; 3492fe14ff6SBrent Lu id++; 3502fe14ff6SBrent Lu } 3512fe14ff6SBrent Lu } 3522fe14ff6SBrent Lu 3532fe14ff6SBrent Lu /* BT audio offload */ 3542fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { 3552fe14ff6SBrent Lu int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> 3562fe14ff6SBrent Lu SOF_BT_OFFLOAD_SSP_SHIFT; 3572fe14ff6SBrent Lu 3582fe14ff6SBrent Lu links[id].id = id; 3592fe14ff6SBrent Lu links[id].cpus = &cpus[id]; 3602fe14ff6SBrent Lu links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 3612fe14ff6SBrent Lu "SSP%d Pin", port); 3622fe14ff6SBrent Lu if (!links[id].cpus->dai_name) 3632fe14ff6SBrent Lu goto devm_err; 3642fe14ff6SBrent Lu links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); 3652fe14ff6SBrent Lu if (!links[id].name) 3662fe14ff6SBrent Lu goto devm_err; 3672fe14ff6SBrent Lu links[id].codecs = dummy_component; 3682fe14ff6SBrent Lu links[id].num_codecs = ARRAY_SIZE(dummy_component); 3692fe14ff6SBrent Lu links[id].platforms = platform_component; 3702fe14ff6SBrent Lu links[id].num_platforms = ARRAY_SIZE(platform_component); 3712fe14ff6SBrent Lu links[id].dpcm_playback = 1; 3722fe14ff6SBrent Lu links[id].dpcm_capture = 1; 3732fe14ff6SBrent Lu links[id].no_pcm = 1; 3742fe14ff6SBrent Lu links[id].num_cpus = 1; 3752fe14ff6SBrent Lu id++; 3762fe14ff6SBrent Lu } 3772fe14ff6SBrent Lu 3782fe14ff6SBrent Lu return links; 3792fe14ff6SBrent Lu devm_err: 3802fe14ff6SBrent Lu return NULL; 3812fe14ff6SBrent Lu } 3822fe14ff6SBrent Lu 3832fe14ff6SBrent Lu static int sof_ssp_amp_probe(struct platform_device *pdev) 3842fe14ff6SBrent Lu { 3852fe14ff6SBrent Lu struct snd_soc_dai_link *dai_links; 3862fe14ff6SBrent Lu struct snd_soc_acpi_mach *mach; 3872fe14ff6SBrent Lu struct sof_card_private *ctx; 388d1c80876SBrent Lu int dmic_be_num = 0, hdmi_num = 0; 3892fe14ff6SBrent Lu int ret, ssp_codec; 3902fe14ff6SBrent Lu 3912fe14ff6SBrent Lu ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 3922fe14ff6SBrent Lu if (!ctx) 3932fe14ff6SBrent Lu return -ENOMEM; 3942fe14ff6SBrent Lu 3952fe14ff6SBrent Lu if (pdev->id_entry && pdev->id_entry->driver_data) 3962fe14ff6SBrent Lu sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data; 3972fe14ff6SBrent Lu 3982fe14ff6SBrent Lu mach = pdev->dev.platform_data; 3992fe14ff6SBrent Lu 400d1c80876SBrent Lu if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0) 401d1c80876SBrent Lu dmic_be_num = 2; 4022fe14ff6SBrent Lu 4032fe14ff6SBrent Lu ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; 4042fe14ff6SBrent Lu 4052fe14ff6SBrent Lu /* set number of dai links */ 4062fe14ff6SBrent Lu sof_ssp_amp_card.num_links = 1 + dmic_be_num; 4072fe14ff6SBrent Lu 4082fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) 4092fe14ff6SBrent Lu sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> 4102fe14ff6SBrent Lu SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; 4112fe14ff6SBrent Lu 4122fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { 4132fe14ff6SBrent Lu hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >> 4142fe14ff6SBrent Lu SOF_NO_OF_HDMI_PLAYBACK_SHIFT; 4152fe14ff6SBrent Lu /* default number of HDMI DAI's */ 4162fe14ff6SBrent Lu if (!hdmi_num) 4172fe14ff6SBrent Lu hdmi_num = 3; 4182fe14ff6SBrent Lu 4192fe14ff6SBrent Lu if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) 4202fe14ff6SBrent Lu ctx->idisp_codec = true; 4212fe14ff6SBrent Lu 4222fe14ff6SBrent Lu sof_ssp_amp_card.num_links += hdmi_num; 4232fe14ff6SBrent Lu } 4242fe14ff6SBrent Lu 4252fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) 4262fe14ff6SBrent Lu sof_ssp_amp_card.num_links++; 4272fe14ff6SBrent Lu 4282fe14ff6SBrent Lu dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num, hdmi_num, ctx->idisp_codec); 4292fe14ff6SBrent Lu if (!dai_links) 4302fe14ff6SBrent Lu return -ENOMEM; 4312fe14ff6SBrent Lu 4322fe14ff6SBrent Lu sof_ssp_amp_card.dai_link = dai_links; 4332fe14ff6SBrent Lu 4342fe14ff6SBrent Lu /* update codec_conf */ 4352fe14ff6SBrent Lu if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) { 4362fe14ff6SBrent Lu cs35l41_set_codec_conf(&sof_ssp_amp_card); 4372fe14ff6SBrent Lu } 4382fe14ff6SBrent Lu 4392fe14ff6SBrent Lu INIT_LIST_HEAD(&ctx->hdmi_pcm_list); 4402fe14ff6SBrent Lu 4412fe14ff6SBrent Lu sof_ssp_amp_card.dev = &pdev->dev; 4422fe14ff6SBrent Lu 4432fe14ff6SBrent Lu /* set platform name for each dailink */ 4442fe14ff6SBrent Lu ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card, 4452fe14ff6SBrent Lu mach->mach_params.platform); 4462fe14ff6SBrent Lu if (ret) 4472fe14ff6SBrent Lu return ret; 4482fe14ff6SBrent Lu 4492fe14ff6SBrent Lu ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; 4502fe14ff6SBrent Lu 4512fe14ff6SBrent Lu snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx); 4522fe14ff6SBrent Lu 4532fe14ff6SBrent Lu return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card); 4542fe14ff6SBrent Lu } 4552fe14ff6SBrent Lu 4562fe14ff6SBrent Lu static const struct platform_device_id board_ids[] = { 4572fe14ff6SBrent Lu { 4582fe14ff6SBrent Lu .name = "sof_ssp_amp", 4592fe14ff6SBrent Lu }, 4602fe14ff6SBrent Lu { 4612fe14ff6SBrent Lu .name = "tgl_rt1308_hdmi_ssp", 4622fe14ff6SBrent Lu .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) | 4632fe14ff6SBrent Lu SOF_NO_OF_HDMI_CAPTURE_SSP(2) | 4642fe14ff6SBrent Lu SOF_HDMI_CAPTURE_1_SSP(1) | 4652fe14ff6SBrent Lu SOF_HDMI_CAPTURE_2_SSP(5) | 4662fe14ff6SBrent Lu SOF_SSP_HDMI_CAPTURE_PRESENT | 4672fe14ff6SBrent Lu SOF_RT1308_SPEAKER_AMP_PRESENT), 4682fe14ff6SBrent Lu }, 4692fe14ff6SBrent Lu { 4702fe14ff6SBrent Lu .name = "adl_cs35l41", 4712fe14ff6SBrent Lu .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) | 4722fe14ff6SBrent Lu SOF_NO_OF_HDMI_PLAYBACK(4) | 4732fe14ff6SBrent Lu SOF_HDMI_PLAYBACK_PRESENT | 4742fe14ff6SBrent Lu SOF_BT_OFFLOAD_SSP(2) | 4752fe14ff6SBrent Lu SOF_SSP_BT_OFFLOAD_PRESENT | 4762fe14ff6SBrent Lu SOF_CS35L41_SPEAKER_AMP_PRESENT), 4772fe14ff6SBrent Lu }, 4782fe14ff6SBrent Lu { } 4792fe14ff6SBrent Lu }; 4802fe14ff6SBrent Lu MODULE_DEVICE_TABLE(platform, board_ids); 4812fe14ff6SBrent Lu 4822fe14ff6SBrent Lu static struct platform_driver sof_ssp_amp_driver = { 4832fe14ff6SBrent Lu .probe = sof_ssp_amp_probe, 4842fe14ff6SBrent Lu .driver = { 4852fe14ff6SBrent Lu .name = "sof_ssp_amp", 4862fe14ff6SBrent Lu .pm = &snd_soc_pm_ops, 4872fe14ff6SBrent Lu }, 4882fe14ff6SBrent Lu .id_table = board_ids, 4892fe14ff6SBrent Lu }; 4902fe14ff6SBrent Lu module_platform_driver(sof_ssp_amp_driver); 4912fe14ff6SBrent Lu 4922fe14ff6SBrent Lu MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver"); 4932fe14ff6SBrent Lu MODULE_AUTHOR("balamurugan.c <balamurugan.c@intel.com>"); 4942fe14ff6SBrent Lu MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 4952fe14ff6SBrent Lu MODULE_LICENSE("GPL"); 4962fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); 4972fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); 4982fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON); 499