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 
sof_card_late_probe(struct snd_soc_card * card)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;
1082fe14ff6SBrent Lu 
1092fe14ff6SBrent Lu 	if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT))
1102fe14ff6SBrent Lu 		return 0;
1112fe14ff6SBrent Lu 
1122fe14ff6SBrent Lu 	/* HDMI is not supported by SOF on Baytrail/CherryTrail */
1132fe14ff6SBrent Lu 	if (!ctx->idisp_codec)
1142fe14ff6SBrent Lu 		return 0;
1152fe14ff6SBrent Lu 
1162fe14ff6SBrent Lu 	if (list_empty(&ctx->hdmi_pcm_list))
1172fe14ff6SBrent Lu 		return -EINVAL;
1182fe14ff6SBrent Lu 
1192fe14ff6SBrent Lu 	if (ctx->common_hdmi_codec_drv) {
1202fe14ff6SBrent Lu 		pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
1212fe14ff6SBrent Lu 				       head);
1222fe14ff6SBrent Lu 		component = pcm->codec_dai->component;
1232fe14ff6SBrent Lu 		return hda_dsp_hdmi_build_controls(card, component);
1242fe14ff6SBrent Lu 	}
1252fe14ff6SBrent Lu 
1262fe14ff6SBrent Lu 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
1272fe14ff6SBrent Lu 		component = pcm->codec_dai->component;
1282fe14ff6SBrent Lu 		snprintf(jack_name, sizeof(jack_name),
1292fe14ff6SBrent Lu 			 "HDMI/DP, pcm=%d Jack", pcm->device);
1302fe14ff6SBrent Lu 		err = snd_soc_card_jack_new(card, jack_name,
13119aed2d6SAkihiko Odaki 					    SND_JACK_AVOUT, &pcm->sof_hdmi);
1322fe14ff6SBrent Lu 
1332fe14ff6SBrent Lu 		if (err)
1342fe14ff6SBrent Lu 			return err;
1352fe14ff6SBrent Lu 
1362fe14ff6SBrent Lu 		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
1372fe14ff6SBrent Lu 					  &pcm->sof_hdmi);
1382fe14ff6SBrent Lu 		if (err < 0)
1392fe14ff6SBrent Lu 			return err;
1402fe14ff6SBrent Lu 	}
1412fe14ff6SBrent Lu 
1422fe14ff6SBrent Lu 	return hdac_hdmi_jack_port_init(component, &card->dapm);
1432fe14ff6SBrent Lu }
1442fe14ff6SBrent Lu 
1452fe14ff6SBrent Lu static struct snd_soc_card sof_ssp_amp_card = {
1462fe14ff6SBrent Lu 	.name         = "ssp_amp",
1472fe14ff6SBrent Lu 	.owner        = THIS_MODULE,
1482fe14ff6SBrent Lu 	.dapm_widgets = sof_ssp_amp_dapm_widgets,
1492fe14ff6SBrent Lu 	.num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets),
1502fe14ff6SBrent Lu 	.dapm_routes = sof_ssp_amp_dapm_routes,
1512fe14ff6SBrent Lu 	.num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes),
1522fe14ff6SBrent Lu 	.fully_routed = true,
1532fe14ff6SBrent Lu 	.late_probe = sof_card_late_probe,
1542fe14ff6SBrent Lu };
1552fe14ff6SBrent Lu 
1562fe14ff6SBrent Lu static struct snd_soc_dai_link_component platform_component[] = {
1572fe14ff6SBrent Lu 	{
1582fe14ff6SBrent Lu 		/* name might be overridden during probe */
1592fe14ff6SBrent Lu 		.name = "0000:00:1f.3"
1602fe14ff6SBrent Lu 	}
1612fe14ff6SBrent Lu };
1622fe14ff6SBrent Lu 
1632fe14ff6SBrent Lu static struct snd_soc_dai_link_component dmic_component[] = {
1642fe14ff6SBrent Lu 	{
1652fe14ff6SBrent Lu 		.name = "dmic-codec",
1662fe14ff6SBrent Lu 		.dai_name = "dmic-hifi",
1672fe14ff6SBrent Lu 	}
1682fe14ff6SBrent Lu };
1692fe14ff6SBrent Lu 
sof_hdmi_init(struct snd_soc_pcm_runtime * rtd)1702fe14ff6SBrent Lu static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
1712fe14ff6SBrent Lu {
1722fe14ff6SBrent Lu 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
1732fe14ff6SBrent Lu 	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
1742fe14ff6SBrent Lu 	struct sof_hdmi_pcm *pcm;
1752fe14ff6SBrent Lu 
1762fe14ff6SBrent Lu 	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
1772fe14ff6SBrent Lu 	if (!pcm)
1782fe14ff6SBrent Lu 		return -ENOMEM;
1792fe14ff6SBrent Lu 
1802fe14ff6SBrent Lu 	/* dai_link id is 1:1 mapped to the PCM device */
1812fe14ff6SBrent Lu 	pcm->device = rtd->dai_link->id;
1822fe14ff6SBrent Lu 	pcm->codec_dai = dai;
1832fe14ff6SBrent Lu 
1842fe14ff6SBrent Lu 	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
1852fe14ff6SBrent Lu 
1862fe14ff6SBrent Lu 	return 0;
1872fe14ff6SBrent Lu }
1882fe14ff6SBrent Lu 
1892fe14ff6SBrent Lu #define IDISP_CODEC_MASK	0x4
1902fe14ff6SBrent Lu 
sof_card_dai_links_create(struct device * dev,int ssp_codec,int dmic_be_num,int hdmi_num,bool idisp_codec)1912fe14ff6SBrent Lu static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
1922fe14ff6SBrent Lu 							  int ssp_codec,
1932fe14ff6SBrent Lu 							  int dmic_be_num,
1942fe14ff6SBrent Lu 							  int hdmi_num,
1952fe14ff6SBrent Lu 							  bool idisp_codec)
1962fe14ff6SBrent Lu {
1972fe14ff6SBrent Lu 	struct snd_soc_dai_link_component *idisp_components;
1982fe14ff6SBrent Lu 	struct snd_soc_dai_link_component *cpus;
1992fe14ff6SBrent Lu 	struct snd_soc_dai_link *links;
2002fe14ff6SBrent Lu 	int i, id = 0;
2012fe14ff6SBrent Lu 
20209dea5acSye xingchen 	links = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
20309dea5acSye xingchen 					sizeof(struct snd_soc_dai_link), GFP_KERNEL);
20409dea5acSye xingchen 	cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
20509dea5acSye xingchen 					sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
2062fe14ff6SBrent Lu 	if (!links || !cpus)
2072fe14ff6SBrent Lu 		return NULL;
2082fe14ff6SBrent Lu 
2092fe14ff6SBrent Lu 	/* HDMI-In SSP */
2102fe14ff6SBrent Lu 	if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
2112fe14ff6SBrent Lu 		int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
2122fe14ff6SBrent Lu 				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
2132fe14ff6SBrent Lu 
2142fe14ff6SBrent Lu 		for (i = 1; i <= num_of_hdmi_ssp; i++) {
2152fe14ff6SBrent Lu 			int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
2162fe14ff6SBrent Lu 						SOF_HDMI_CAPTURE_1_SSP_SHIFT :
2172fe14ff6SBrent Lu 						(sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
2182fe14ff6SBrent Lu 						SOF_HDMI_CAPTURE_2_SSP_SHIFT);
2192fe14ff6SBrent Lu 
2202fe14ff6SBrent Lu 			links[id].cpus = &cpus[id];
2212fe14ff6SBrent Lu 			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
2222fe14ff6SBrent Lu 								  "SSP%d Pin", port);
2232fe14ff6SBrent Lu 			if (!links[id].cpus->dai_name)
2242fe14ff6SBrent Lu 				return NULL;
2252fe14ff6SBrent Lu 			links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
2262fe14ff6SBrent Lu 			if (!links[id].name)
2272fe14ff6SBrent Lu 				return NULL;
2282fe14ff6SBrent Lu 			links[id].id = id;
2291785af9fSKuninori Morimoto 			links[id].codecs = &asoc_dummy_dlc;
2301785af9fSKuninori Morimoto 			links[id].num_codecs = 1;
2312fe14ff6SBrent Lu 			links[id].platforms = platform_component;
2322fe14ff6SBrent Lu 			links[id].num_platforms = ARRAY_SIZE(platform_component);
2332fe14ff6SBrent Lu 			links[id].dpcm_capture = 1;
2342fe14ff6SBrent Lu 			links[id].no_pcm = 1;
2352fe14ff6SBrent Lu 			links[id].num_cpus = 1;
2362fe14ff6SBrent Lu 			id++;
2372fe14ff6SBrent Lu 		}
2382fe14ff6SBrent Lu 	}
2392fe14ff6SBrent Lu 
2402fe14ff6SBrent Lu 	/* codec SSP */
2412fe14ff6SBrent Lu 	links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
2422fe14ff6SBrent Lu 	if (!links[id].name)
2432fe14ff6SBrent Lu 		return NULL;
2442fe14ff6SBrent Lu 
2452fe14ff6SBrent Lu 	links[id].id = id;
2462fe14ff6SBrent Lu 	if (sof_ssp_amp_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) {
2472fe14ff6SBrent Lu 		sof_rt1308_dai_link(&links[id]);
2482fe14ff6SBrent Lu 	} else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
2492fe14ff6SBrent Lu 		cs35l41_set_dai_link(&links[id]);
2502fe14ff6SBrent Lu 	}
2512fe14ff6SBrent Lu 	links[id].platforms = platform_component;
2522fe14ff6SBrent Lu 	links[id].num_platforms = ARRAY_SIZE(platform_component);
2532fe14ff6SBrent Lu 	links[id].dpcm_playback = 1;
254b3c00316SPierre-Louis Bossart 	/* feedback from amplifier or firmware-generated echo reference */
255b3c00316SPierre-Louis Bossart 	links[id].dpcm_capture = 1;
2562fe14ff6SBrent Lu 	links[id].no_pcm = 1;
2572fe14ff6SBrent Lu 	links[id].cpus = &cpus[id];
2582fe14ff6SBrent Lu 	links[id].num_cpus = 1;
2592fe14ff6SBrent Lu 	links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec);
2602fe14ff6SBrent Lu 	if (!links[id].cpus->dai_name)
2612fe14ff6SBrent Lu 		return NULL;
2622fe14ff6SBrent Lu 
2632fe14ff6SBrent Lu 	id++;
2642fe14ff6SBrent Lu 
2652fe14ff6SBrent Lu 	/* dmic */
2662fe14ff6SBrent Lu 	if (dmic_be_num > 0) {
2672fe14ff6SBrent Lu 		/* at least we have dmic01 */
2682fe14ff6SBrent Lu 		links[id].name = "dmic01";
2692fe14ff6SBrent Lu 		links[id].cpus = &cpus[id];
2702fe14ff6SBrent Lu 		links[id].cpus->dai_name = "DMIC01 Pin";
2712fe14ff6SBrent Lu 		if (dmic_be_num > 1) {
2722fe14ff6SBrent Lu 			/* set up 2 BE links at most */
2732fe14ff6SBrent Lu 			links[id + 1].name = "dmic16k";
2742fe14ff6SBrent Lu 			links[id + 1].cpus = &cpus[id + 1];
2752fe14ff6SBrent Lu 			links[id + 1].cpus->dai_name = "DMIC16k Pin";
2762fe14ff6SBrent Lu 			dmic_be_num = 2;
2772fe14ff6SBrent Lu 		}
2782fe14ff6SBrent Lu 	}
2792fe14ff6SBrent Lu 
2802fe14ff6SBrent Lu 	for (i = 0; i < dmic_be_num; i++) {
2812fe14ff6SBrent Lu 		links[id].id = id;
2822fe14ff6SBrent Lu 		links[id].num_cpus = 1;
2832fe14ff6SBrent Lu 		links[id].codecs = dmic_component;
2842fe14ff6SBrent Lu 		links[id].num_codecs = ARRAY_SIZE(dmic_component);
2852fe14ff6SBrent Lu 		links[id].platforms = platform_component;
2862fe14ff6SBrent Lu 		links[id].num_platforms = ARRAY_SIZE(platform_component);
2872fe14ff6SBrent Lu 		links[id].ignore_suspend = 1;
2882fe14ff6SBrent Lu 		links[id].dpcm_capture = 1;
2892fe14ff6SBrent Lu 		links[id].no_pcm = 1;
2902fe14ff6SBrent Lu 		id++;
2912fe14ff6SBrent Lu 	}
2922fe14ff6SBrent Lu 
2932fe14ff6SBrent Lu 	/* HDMI playback */
2942fe14ff6SBrent Lu 	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
2952fe14ff6SBrent Lu 		/* HDMI */
2962fe14ff6SBrent Lu 		if (hdmi_num > 0) {
29709dea5acSye xingchen 			idisp_components = devm_kcalloc(dev,
29809dea5acSye xingchen 					   hdmi_num,
29909dea5acSye xingchen 					   sizeof(struct snd_soc_dai_link_component),
30009dea5acSye xingchen 					   GFP_KERNEL);
3012fe14ff6SBrent Lu 			if (!idisp_components)
3022fe14ff6SBrent Lu 				goto devm_err;
3032fe14ff6SBrent Lu 		}
3042fe14ff6SBrent Lu 		for (i = 1; i <= hdmi_num; i++) {
3052fe14ff6SBrent Lu 			links[id].name = devm_kasprintf(dev, GFP_KERNEL,
3062fe14ff6SBrent Lu 							"iDisp%d", i);
3072fe14ff6SBrent Lu 			if (!links[id].name)
3082fe14ff6SBrent Lu 				goto devm_err;
3092fe14ff6SBrent Lu 
3102fe14ff6SBrent Lu 			links[id].id = id;
3112fe14ff6SBrent Lu 			links[id].cpus = &cpus[id];
3122fe14ff6SBrent Lu 			links[id].num_cpus = 1;
3132fe14ff6SBrent Lu 			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
3142fe14ff6SBrent Lu 								  "iDisp%d Pin", i);
3152fe14ff6SBrent Lu 			if (!links[id].cpus->dai_name)
3162fe14ff6SBrent Lu 				goto devm_err;
3172fe14ff6SBrent Lu 
3182fe14ff6SBrent Lu 			if (idisp_codec) {
3192fe14ff6SBrent Lu 				idisp_components[i - 1].name = "ehdaudio0D2";
3202fe14ff6SBrent Lu 				idisp_components[i - 1].dai_name = devm_kasprintf(dev,
3212fe14ff6SBrent Lu 										  GFP_KERNEL,
3222fe14ff6SBrent Lu 										  "intel-hdmi-hifi%d",
3232fe14ff6SBrent Lu 										  i);
3242fe14ff6SBrent Lu 				if (!idisp_components[i - 1].dai_name)
3252fe14ff6SBrent Lu 					goto devm_err;
3262fe14ff6SBrent Lu 			} else {
3271785af9fSKuninori Morimoto 				idisp_components[i - 1] = asoc_dummy_dlc;
3282fe14ff6SBrent Lu 			}
3292fe14ff6SBrent Lu 
3302fe14ff6SBrent Lu 			links[id].codecs = &idisp_components[i - 1];
3312fe14ff6SBrent Lu 			links[id].num_codecs = 1;
3322fe14ff6SBrent Lu 			links[id].platforms = platform_component;
3332fe14ff6SBrent Lu 			links[id].num_platforms = ARRAY_SIZE(platform_component);
3342fe14ff6SBrent Lu 			links[id].init = sof_hdmi_init;
3352fe14ff6SBrent Lu 			links[id].dpcm_playback = 1;
3362fe14ff6SBrent Lu 			links[id].no_pcm = 1;
3372fe14ff6SBrent Lu 			id++;
3382fe14ff6SBrent Lu 		}
3392fe14ff6SBrent Lu 	}
3402fe14ff6SBrent Lu 
3412fe14ff6SBrent Lu 	/* BT audio offload */
3422fe14ff6SBrent Lu 	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
3432fe14ff6SBrent Lu 		int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
3442fe14ff6SBrent Lu 				SOF_BT_OFFLOAD_SSP_SHIFT;
3452fe14ff6SBrent Lu 
3462fe14ff6SBrent Lu 		links[id].id = id;
3472fe14ff6SBrent Lu 		links[id].cpus = &cpus[id];
3482fe14ff6SBrent Lu 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
3492fe14ff6SBrent Lu 							  "SSP%d Pin", port);
3502fe14ff6SBrent Lu 		if (!links[id].cpus->dai_name)
3512fe14ff6SBrent Lu 			goto devm_err;
3522fe14ff6SBrent Lu 		links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
3532fe14ff6SBrent Lu 		if (!links[id].name)
3542fe14ff6SBrent Lu 			goto devm_err;
3551785af9fSKuninori Morimoto 		links[id].codecs = &asoc_dummy_dlc;
3561785af9fSKuninori Morimoto 		links[id].num_codecs = 1;
3572fe14ff6SBrent Lu 		links[id].platforms = platform_component;
3582fe14ff6SBrent Lu 		links[id].num_platforms = ARRAY_SIZE(platform_component);
3592fe14ff6SBrent Lu 		links[id].dpcm_playback = 1;
3602fe14ff6SBrent Lu 		links[id].dpcm_capture = 1;
3612fe14ff6SBrent Lu 		links[id].no_pcm = 1;
3622fe14ff6SBrent Lu 		links[id].num_cpus = 1;
3632fe14ff6SBrent Lu 		id++;
3642fe14ff6SBrent Lu 	}
3652fe14ff6SBrent Lu 
3662fe14ff6SBrent Lu 	return links;
3672fe14ff6SBrent Lu devm_err:
3682fe14ff6SBrent Lu 	return NULL;
3692fe14ff6SBrent Lu }
3702fe14ff6SBrent Lu 
sof_ssp_amp_probe(struct platform_device * pdev)3712fe14ff6SBrent Lu static int sof_ssp_amp_probe(struct platform_device *pdev)
3722fe14ff6SBrent Lu {
3732fe14ff6SBrent Lu 	struct snd_soc_dai_link *dai_links;
3742fe14ff6SBrent Lu 	struct snd_soc_acpi_mach *mach;
3752fe14ff6SBrent Lu 	struct sof_card_private *ctx;
376d1c80876SBrent Lu 	int dmic_be_num = 0, hdmi_num = 0;
3772fe14ff6SBrent Lu 	int ret, ssp_codec;
3782fe14ff6SBrent Lu 
3792fe14ff6SBrent Lu 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
3802fe14ff6SBrent Lu 	if (!ctx)
3812fe14ff6SBrent Lu 		return -ENOMEM;
3822fe14ff6SBrent Lu 
3832fe14ff6SBrent Lu 	if (pdev->id_entry && pdev->id_entry->driver_data)
3842fe14ff6SBrent Lu 		sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
3852fe14ff6SBrent Lu 
3862fe14ff6SBrent Lu 	mach = pdev->dev.platform_data;
3872fe14ff6SBrent Lu 
388d1c80876SBrent Lu 	if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0)
389d1c80876SBrent Lu 		dmic_be_num = 2;
3902fe14ff6SBrent Lu 
3912fe14ff6SBrent Lu 	ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
3922fe14ff6SBrent Lu 
3932fe14ff6SBrent Lu 	/* set number of dai links */
3942fe14ff6SBrent Lu 	sof_ssp_amp_card.num_links = 1 + dmic_be_num;
3952fe14ff6SBrent Lu 
3962fe14ff6SBrent Lu 	if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
3972fe14ff6SBrent Lu 		sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
3982fe14ff6SBrent Lu 				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
3992fe14ff6SBrent Lu 
4002fe14ff6SBrent Lu 	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
4012fe14ff6SBrent Lu 		hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
4022fe14ff6SBrent Lu 				SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
4032fe14ff6SBrent Lu 		/* default number of HDMI DAI's */
4042fe14ff6SBrent Lu 		if (!hdmi_num)
4052fe14ff6SBrent Lu 			hdmi_num = 3;
4062fe14ff6SBrent Lu 
4072fe14ff6SBrent Lu 		if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
4082fe14ff6SBrent Lu 			ctx->idisp_codec = true;
4092fe14ff6SBrent Lu 
4102fe14ff6SBrent Lu 		sof_ssp_amp_card.num_links += hdmi_num;
4112fe14ff6SBrent Lu 	}
4122fe14ff6SBrent Lu 
4132fe14ff6SBrent Lu 	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
4142fe14ff6SBrent Lu 		sof_ssp_amp_card.num_links++;
4152fe14ff6SBrent Lu 
4162fe14ff6SBrent Lu 	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num, hdmi_num, ctx->idisp_codec);
4172fe14ff6SBrent Lu 	if (!dai_links)
4182fe14ff6SBrent Lu 		return -ENOMEM;
4192fe14ff6SBrent Lu 
4202fe14ff6SBrent Lu 	sof_ssp_amp_card.dai_link = dai_links;
4212fe14ff6SBrent Lu 
4222fe14ff6SBrent Lu 	/* update codec_conf */
4232fe14ff6SBrent Lu 	if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
4242fe14ff6SBrent Lu 		cs35l41_set_codec_conf(&sof_ssp_amp_card);
4252fe14ff6SBrent Lu 	}
4262fe14ff6SBrent Lu 
4272fe14ff6SBrent Lu 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
4282fe14ff6SBrent Lu 
4292fe14ff6SBrent Lu 	sof_ssp_amp_card.dev = &pdev->dev;
4302fe14ff6SBrent Lu 
4312fe14ff6SBrent Lu 	/* set platform name for each dailink */
4322fe14ff6SBrent Lu 	ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
4332fe14ff6SBrent Lu 						    mach->mach_params.platform);
4342fe14ff6SBrent Lu 	if (ret)
4352fe14ff6SBrent Lu 		return ret;
4362fe14ff6SBrent Lu 
4372fe14ff6SBrent Lu 	ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
4382fe14ff6SBrent Lu 
4392fe14ff6SBrent Lu 	snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
4402fe14ff6SBrent Lu 
4412fe14ff6SBrent Lu 	return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
4422fe14ff6SBrent Lu }
4432fe14ff6SBrent Lu 
4442fe14ff6SBrent Lu static const struct platform_device_id board_ids[] = {
4452fe14ff6SBrent Lu 	{
4462fe14ff6SBrent Lu 		.name = "sof_ssp_amp",
4472fe14ff6SBrent Lu 	},
4482fe14ff6SBrent Lu 	{
4492fe14ff6SBrent Lu 		.name = "tgl_rt1308_hdmi_ssp",
4502fe14ff6SBrent Lu 		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
4512fe14ff6SBrent Lu 					SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
4522fe14ff6SBrent Lu 					SOF_HDMI_CAPTURE_1_SSP(1) |
4532fe14ff6SBrent Lu 					SOF_HDMI_CAPTURE_2_SSP(5) |
4542fe14ff6SBrent Lu 					SOF_SSP_HDMI_CAPTURE_PRESENT |
4552fe14ff6SBrent Lu 					SOF_RT1308_SPEAKER_AMP_PRESENT),
4562fe14ff6SBrent Lu 	},
4572fe14ff6SBrent Lu 	{
4582fe14ff6SBrent Lu 		.name = "adl_cs35l41",
4592fe14ff6SBrent Lu 		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
4602fe14ff6SBrent Lu 					SOF_NO_OF_HDMI_PLAYBACK(4) |
4612fe14ff6SBrent Lu 					SOF_HDMI_PLAYBACK_PRESENT |
4622fe14ff6SBrent Lu 					SOF_BT_OFFLOAD_SSP(2) |
4632fe14ff6SBrent Lu 					SOF_SSP_BT_OFFLOAD_PRESENT |
4642fe14ff6SBrent Lu 					SOF_CS35L41_SPEAKER_AMP_PRESENT),
4652fe14ff6SBrent Lu 	},
4665376d37bSBalamurugan C 	{
4675376d37bSBalamurugan C 		.name = "adl_lt6911_hdmi_ssp",
4685376d37bSBalamurugan C 		.driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
4695376d37bSBalamurugan C 					SOF_HDMI_CAPTURE_1_SSP(0) |
4705376d37bSBalamurugan C 					SOF_HDMI_CAPTURE_2_SSP(2) |
4715376d37bSBalamurugan C 					SOF_SSP_HDMI_CAPTURE_PRESENT |
4725376d37bSBalamurugan C 					SOF_NO_OF_HDMI_PLAYBACK(3) |
4735376d37bSBalamurugan C 					SOF_HDMI_PLAYBACK_PRESENT),
4745376d37bSBalamurugan C 	},
475*f7555da7SBalamurugan C 	{
476*f7555da7SBalamurugan C 		.name = "rpl_lt6911_hdmi_ssp",
477*f7555da7SBalamurugan C 		.driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
478*f7555da7SBalamurugan C 					SOF_HDMI_CAPTURE_1_SSP(0) |
479*f7555da7SBalamurugan C 					SOF_HDMI_CAPTURE_2_SSP(2) |
480*f7555da7SBalamurugan C 					SOF_SSP_HDMI_CAPTURE_PRESENT |
481*f7555da7SBalamurugan C 					SOF_NO_OF_HDMI_PLAYBACK(3) |
482*f7555da7SBalamurugan C 					SOF_HDMI_PLAYBACK_PRESENT),
483*f7555da7SBalamurugan C 	},
4842fe14ff6SBrent Lu 	{ }
4852fe14ff6SBrent Lu };
4862fe14ff6SBrent Lu MODULE_DEVICE_TABLE(platform, board_ids);
4872fe14ff6SBrent Lu 
4882fe14ff6SBrent Lu static struct platform_driver sof_ssp_amp_driver = {
4892fe14ff6SBrent Lu 	.probe          = sof_ssp_amp_probe,
4902fe14ff6SBrent Lu 	.driver = {
4912fe14ff6SBrent Lu 		.name   = "sof_ssp_amp",
4922fe14ff6SBrent Lu 		.pm = &snd_soc_pm_ops,
4932fe14ff6SBrent Lu 	},
4942fe14ff6SBrent Lu 	.id_table = board_ids,
4952fe14ff6SBrent Lu };
4962fe14ff6SBrent Lu module_platform_driver(sof_ssp_amp_driver);
4972fe14ff6SBrent Lu 
4982fe14ff6SBrent Lu MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
4991529d344SBalamurugan C MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>");
5002fe14ff6SBrent Lu MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
5012fe14ff6SBrent Lu MODULE_LICENSE("GPL");
5022fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
5032fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
5042fe14ff6SBrent Lu MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);
505