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