diff options
Diffstat (limited to 'sound/soc/intel/boards/sof_sdw.c')
| -rw-r--r-- | sound/soc/intel/boards/sof_sdw.c | 1369 | 
1 files changed, 743 insertions, 626 deletions
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 08f330ed5c2e..e41b0d95e0ff 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -5,6 +5,7 @@   *  sof_sdw - ASOC Machine driver for Intel SoundWire platforms   */ +#include <linux/bitmap.h>  #include <linux/device.h>  #include <linux/dmi.h>  #include <linux/module.h> @@ -26,7 +27,7 @@ static void log_quirks(struct device *dev)  		dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",  			SOF_JACK_JDSRC(sof_sdw_quirk));  	if (sof_sdw_quirk & SOF_SDW_FOUR_SPK) -		dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n"); +		dev_err(dev, "quirk SOF_SDW_FOUR_SPK enabled but no longer supported\n");  	if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)  		dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");  	if (sof_sdw_quirk & SOF_SDW_PCH_DMIC) @@ -35,7 +36,11 @@ static void log_quirks(struct device *dev)  		dev_dbg(dev, "SSP port %ld\n",  			SOF_SSP_GET_PORT(sof_sdw_quirk));  	if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION) -		dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n"); +		dev_err(dev, "quirk SOF_SDW_NO_AGGREGATION enabled but no longer supported\n"); +	if (sof_sdw_quirk & SOF_CODEC_SPKR) +		dev_dbg(dev, "quirk SOF_CODEC_SPKR enabled\n"); +	if (sof_sdw_quirk & SOF_SIDECAR_AMPS) +		dev_dbg(dev, "quirk SOF_SIDECAR_AMPS enabled\n");  }  static int sof_sdw_quirk_cb(const struct dmi_system_id *id) @@ -77,8 +82,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),  		}, -		.driver_data = (void *)(RT711_JD2 | -					SOF_SDW_FOUR_SPK), +		.driver_data = (void *)(RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -86,8 +90,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),  		}, -		.driver_data = (void *)(RT711_JD2 | -					SOF_SDW_FOUR_SPK), +		.driver_data = (void *)(RT711_JD2),  	},  	/* IceLake devices */  	{ @@ -138,8 +141,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -148,8 +150,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -159,7 +160,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI |  					SOF_SDW_PCH_DMIC | -					SOF_SDW_FOUR_SPK |  					SOF_BT_OFFLOAD_SSP(2) |  					SOF_SSP_BT_OFFLOAD_PRESENT),  	}, @@ -170,8 +170,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					SOF_SDW_PCH_DMIC | -					SOF_SDW_FOUR_SPK), +					SOF_SDW_PCH_DMIC),  	},  	{  		/* @@ -255,8 +254,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -287,7 +285,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI |  					SOF_SDW_PCH_DMIC | -					SOF_SDW_FOUR_SPK |  					SOF_BT_OFFLOAD_SSP(2) |  					SOF_SSP_BT_OFFLOAD_PRESENT),  	}, @@ -298,8 +295,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -308,8 +304,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),  		},  		/* No Jack */ -		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					SOF_SDW_FOUR_SPK), +		.driver_data = (void *)(SOF_SDW_TGL_HDMI),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -318,8 +313,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -328,8 +322,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -338,8 +331,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -348,8 +340,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -358,8 +349,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -368,8 +358,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -397,8 +386,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -426,8 +414,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2), +	}, +	{ +		.callback = sof_sdw_quirk_cb, +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), +			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F") +		}, +		.driver_data = (void *)(SOF_SDW_TGL_HDMI | +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -436,8 +432,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),  		},  		/* No Jack */ -		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					SOF_SDW_FOUR_SPK), +		.driver_data = (void *)(SOF_SDW_TGL_HDMI),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -446,8 +441,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -456,8 +450,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	{  		.callback = sof_sdw_quirk_cb, @@ -466,8 +459,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")  		},  		.driver_data = (void *)(SOF_SDW_TGL_HDMI | -					RT711_JD2 | -					SOF_SDW_FOUR_SPK), +					RT711_JD2),  	},  	/* MeteorLake devices */  	{ @@ -495,6 +487,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {  					SOF_BT_OFFLOAD_SSP(1) |  					SOF_SSP_BT_OFFLOAD_PRESENT),  	}, +	{ +		.callback = sof_sdw_quirk_cb, +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "HP"), +			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"), +		}, +		.driver_data = (void *)(RT711_JD2), +	}, +  	/* LunarLake devices */  	{  		.callback = sof_sdw_quirk_cb, @@ -514,6 +515,68 @@ static struct snd_soc_dai_link_component platform_component[] = {  	}  }; +static const struct snd_soc_dapm_widget generic_dmic_widgets[] = { +	SND_SOC_DAPM_MIC("DMIC", NULL), +}; + +static const struct snd_soc_dapm_widget generic_jack_widgets[] = { +	SND_SOC_DAPM_HP("Headphone", NULL), +	SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_kcontrol_new generic_jack_controls[] = { +	SOC_DAPM_PIN_SWITCH("Headphone"), +	SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget generic_spk_widgets[] = { +	SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_kcontrol_new generic_spk_controls[] = { +	SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static const struct snd_soc_dapm_widget maxim_widgets[] = { +	SND_SOC_DAPM_SPK("Left Spk", NULL), +	SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + +static const struct snd_kcontrol_new maxim_controls[] = { +	SOC_DAPM_PIN_SWITCH("Left Spk"), +	SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget rt700_widgets[] = { +	SND_SOC_DAPM_HP("Headphones", NULL), +	SND_SOC_DAPM_MIC("AMIC", NULL), +	SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_kcontrol_new rt700_controls[] = { +	SOC_DAPM_PIN_SWITCH("Headphones"), +	SOC_DAPM_PIN_SWITCH("AMIC"), +	SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, +					  const char * const dai_name[], +					  int num_dais) +{ +	struct snd_soc_dai *dai; +	int index; +	int i; + +	for (index = 0; index < num_dais; index++) +		for_each_rtd_codec_dais(rtd, i, dai) +			if (strstr(dai->name, dai_name[index])) { +				dev_dbg(rtd->card->dev, "get dai %s\n", dai->name); +				return dai; +			} + +	return NULL; +} +  /* these wrappers are only needed to avoid typecast compilation errors */  int sdw_startup(struct snd_pcm_substream *substream)  { @@ -662,6 +725,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_type = SOF_SDW_DAI_TYPE_JACK,  				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},  				.rtd_init = rt700_rtd_init, +				.controls = rt700_controls, +				.num_controls = ARRAY_SIZE(rt700_controls), +				.widgets = rt700_widgets, +				.num_widgets = ARRAY_SIZE(rt700_widgets),  			},  		},  		.dai_num = 1, @@ -678,6 +745,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.init = sof_sdw_rt_sdca_jack_init,  				.exit = sof_sdw_rt_sdca_jack_exit,  				.rtd_init = rt_sdca_jack_rtd_init, +				.controls = generic_jack_controls, +				.num_controls = ARRAY_SIZE(generic_jack_controls), +				.widgets = generic_jack_widgets, +				.num_widgets = ARRAY_SIZE(generic_jack_widgets),  			},  		},  		.dai_num = 1, @@ -694,6 +765,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.init = sof_sdw_rt711_init,  				.exit = sof_sdw_rt711_exit,  				.rtd_init = rt711_rtd_init, +				.controls = generic_jack_controls, +				.num_controls = ARRAY_SIZE(generic_jack_controls), +				.widgets = generic_jack_widgets, +				.num_widgets = ARRAY_SIZE(generic_jack_widgets),  			},  		},  		.dai_num = 1, @@ -710,13 +785,23 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.init = sof_sdw_rt_sdca_jack_init,  				.exit = sof_sdw_rt_sdca_jack_exit,  				.rtd_init = rt_sdca_jack_rtd_init, +				.controls = generic_jack_controls, +				.num_controls = ARRAY_SIZE(generic_jack_controls), +				.widgets = generic_jack_widgets, +				.num_widgets = ARRAY_SIZE(generic_jack_widgets),  			},  			{  				.direction = {true, false},  				.dai_name = "rt712-sdca-aif2",  				.dai_type = SOF_SDW_DAI_TYPE_AMP,  				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, +				.init = sof_sdw_rt_amp_init, +				.exit = sof_sdw_rt_amp_exit,  				.rtd_init = rt712_spk_rtd_init, +				.controls = generic_spk_controls, +				.num_controls = ARRAY_SIZE(generic_spk_controls), +				.widgets = generic_spk_widgets, +				.num_widgets = ARRAY_SIZE(generic_spk_widgets),  			},  		},  		.dai_num = 2, @@ -730,7 +815,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_name = "rt712-sdca-dmic-aif1",  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, -				.rtd_init = rt712_sdca_dmic_rtd_init, +				.rtd_init = rt_dmic_rtd_init,  			},  		},  		.dai_num = 1, @@ -747,6 +832,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.init = sof_sdw_rt_sdca_jack_init,  				.exit = sof_sdw_rt_sdca_jack_exit,  				.rtd_init = rt_sdca_jack_rtd_init, +				.controls = generic_jack_controls, +				.num_controls = ARRAY_SIZE(generic_jack_controls), +				.widgets = generic_jack_widgets, +				.num_widgets = ARRAY_SIZE(generic_jack_widgets),  			},  		},  		.dai_num = 1, @@ -760,7 +849,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_name = "rt712-sdca-dmic-aif1",  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, -				.rtd_init = rt712_sdca_dmic_rtd_init, +				.rtd_init = rt_dmic_rtd_init,  			},  		},  		.dai_num = 1, @@ -777,6 +866,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.init = sof_sdw_rt_amp_init,  				.exit = sof_sdw_rt_amp_exit,  				.rtd_init = rt_amp_spk_rtd_init, +				.controls = generic_spk_controls, +				.num_controls = ARRAY_SIZE(generic_spk_controls), +				.widgets = generic_spk_widgets, +				.num_widgets = ARRAY_SIZE(generic_spk_widgets),  			},  		},  		.dai_num = 1, @@ -793,6 +886,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.init = sof_sdw_rt_amp_init,  				.exit = sof_sdw_rt_amp_exit,  				.rtd_init = rt_amp_spk_rtd_init, +				.controls = generic_spk_controls, +				.num_controls = ARRAY_SIZE(generic_spk_controls), +				.widgets = generic_spk_widgets, +				.num_widgets = ARRAY_SIZE(generic_spk_widgets),  			},  		},  		.dai_num = 1, @@ -808,6 +905,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.init = sof_sdw_rt_amp_init,  				.exit = sof_sdw_rt_amp_exit,  				.rtd_init = rt_amp_spk_rtd_init, +				.controls = generic_spk_controls, +				.num_controls = ARRAY_SIZE(generic_spk_controls), +				.widgets = generic_spk_widgets, +				.num_widgets = ARRAY_SIZE(generic_spk_widgets),  			},  		},  		.dai_num = 1, @@ -819,10 +920,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  		.dais = {  			{  				.direction = {false, true}, -				.dai_name = "rt715-aif2", +				.dai_name = "rt715-sdca-aif2",  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, -				.rtd_init = rt715_sdca_rtd_init, +				.rtd_init = rt_dmic_rtd_init,  			},  		},  		.dai_num = 1, @@ -834,10 +935,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  		.dais = {  			{  				.direction = {false, true}, -				.dai_name = "rt715-aif2", +				.dai_name = "rt715-sdca-aif2",  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, -				.rtd_init = rt715_sdca_rtd_init, +				.rtd_init = rt_dmic_rtd_init,  			},  		},  		.dai_num = 1, @@ -852,7 +953,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_name = "rt715-aif2",  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, -				.rtd_init = rt715_rtd_init, +				.rtd_init = rt_dmic_rtd_init,  			},  		},  		.dai_num = 1, @@ -867,7 +968,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_name = "rt715-aif2",  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, -				.rtd_init = rt715_rtd_init, +				.rtd_init = rt_dmic_rtd_init,  			},  		},  		.dai_num = 1, @@ -883,6 +984,11 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},  				.init = sof_sdw_rt_sdca_jack_init,  				.exit = sof_sdw_rt_sdca_jack_exit, +				.rtd_init = rt_sdca_jack_rtd_init, +				.controls = generic_jack_controls, +				.num_controls = ARRAY_SIZE(generic_jack_controls), +				.widgets = generic_jack_widgets, +				.num_widgets = ARRAY_SIZE(generic_jack_widgets),  			},  			{  				.direction = {true, false}, @@ -890,14 +996,20 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_type = SOF_SDW_DAI_TYPE_AMP,  				/* No feedback capability is provided by rt722-sdca codec driver*/  				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, -				.init = sof_sdw_rt722_spk_init, +				.init = sof_sdw_rt_amp_init, +				.exit = sof_sdw_rt_amp_exit, +				.rtd_init = rt722_spk_rtd_init, +				.controls = generic_spk_controls, +				.num_controls = ARRAY_SIZE(generic_spk_controls), +				.widgets = generic_spk_widgets, +				.num_widgets = ARRAY_SIZE(generic_spk_widgets),  			},  			{  				.direction = {false, true},  				.dai_name = "rt722-sdca-aif3",  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, -				.init = sof_sdw_rt722_sdca_dmic_init, +				.rtd_init = rt_dmic_rtd_init,  			},  		},  		.dai_num = 3, @@ -912,6 +1024,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},  				.init = sof_sdw_maxim_init,  				.rtd_init = maxim_spk_rtd_init, +				.controls = maxim_controls, +				.num_controls = ARRAY_SIZE(maxim_controls), +				.widgets = maxim_widgets, +				.num_widgets = ARRAY_SIZE(maxim_widgets),  			},  		},  		.dai_num = 1, @@ -926,6 +1042,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},  				.init = sof_sdw_maxim_init,  				.rtd_init = maxim_spk_rtd_init, +				.controls = maxim_controls, +				.num_controls = ARRAY_SIZE(maxim_controls), +				.widgets = maxim_widgets, +				.num_widgets = ARRAY_SIZE(maxim_widgets),  			},  		},  		.dai_num = 1, @@ -939,6 +1059,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_type = SOF_SDW_DAI_TYPE_JACK,  				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},  				.rtd_init = rt5682_rtd_init, +				.controls = generic_jack_controls, +				.num_controls = ARRAY_SIZE(generic_jack_controls), +				.widgets = generic_jack_widgets, +				.num_widgets = ARRAY_SIZE(generic_jack_widgets),  			},  		},  		.dai_num = 1, @@ -953,6 +1077,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},  				.init = sof_sdw_cs_amp_init,  				.rtd_init = cs_spk_rtd_init, +				.widgets = generic_spk_widgets, +				.num_widgets = ARRAY_SIZE(generic_spk_widgets),  			},  		},  		.dai_num = 1, @@ -966,6 +1092,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_type = SOF_SDW_DAI_TYPE_JACK,  				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID},  				.rtd_init = cs42l42_rtd_init, +				.controls = generic_jack_controls, +				.num_controls = ARRAY_SIZE(generic_jack_controls), +				.widgets = generic_jack_widgets, +				.num_widgets = ARRAY_SIZE(generic_jack_widgets),  			},  		},  		.dai_num = 1, @@ -973,6 +1103,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {  	{  		.part_id = 0x4243,  		.codec_name = "cs42l43-codec", +		.count_sidecar = bridge_cs35l56_count_sidecar, +		.add_sidecar = bridge_cs35l56_add_sidecar,  		.dais = {  			{  				.direction = {true, false}, @@ -980,6 +1112,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_type = SOF_SDW_DAI_TYPE_JACK,  				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID},  				.rtd_init = cs42l43_hs_rtd_init, +				.widgets = generic_jack_widgets, +				.num_widgets = ARRAY_SIZE(generic_jack_widgets),  			},  			{  				.direction = {false, true}, @@ -987,6 +1121,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID},  				.rtd_init = cs42l43_dmic_rtd_init, +				.widgets = generic_dmic_widgets, +				.num_widgets = ARRAY_SIZE(generic_dmic_widgets),  			},  			{  				.direction = {false, true}, @@ -994,8 +1130,19 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_type = SOF_SDW_DAI_TYPE_JACK,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_JACK_IN_DAI_ID},  			}, +			{ +				.direction = {true, false}, +				.dai_name = "cs42l43-dp6", +				.dai_type = SOF_SDW_DAI_TYPE_AMP, +				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, +				.init = sof_sdw_cs42l43_spk_init, +				.rtd_init = cs42l43_spk_rtd_init, +				.widgets = generic_spk_widgets, +				.num_widgets = ARRAY_SIZE(generic_spk_widgets), +				.quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS, +			},  		}, -		.dai_num = 3, +		.dai_num = 4,  	},  	{  		.part_id = 0xaaaa, /* generic codec mockup */ @@ -1006,7 +1153,6 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_name = "sdw-mockup-aif1",  				.dai_type = SOF_SDW_DAI_TYPE_JACK,  				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, -				.init = NULL,  			},  		},  		.dai_num = 1, @@ -1020,7 +1166,6 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_name = "sdw-mockup-aif1",  				.dai_type = SOF_SDW_DAI_TYPE_JACK,  				.dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, -				.init = NULL,  			},  		},  		.dai_num = 1, @@ -1034,7 +1179,6 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.dai_name = "sdw-mockup-aif1",  				.dai_type = SOF_SDW_DAI_TYPE_AMP,  				.dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, -				.init = NULL,  			},  		},  		.dai_num = 1, @@ -1048,14 +1192,13 @@ static struct sof_sdw_codec_info codec_info_list[] = {  				.direction = {false, true},  				.dai_type = SOF_SDW_DAI_TYPE_MIC,  				.dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, -				.init = NULL,  			},  		},  		.dai_num = 1,  	},  }; -static inline int find_codec_info_part(const u64 adr) +static struct sof_sdw_codec_info *find_codec_info_part(const u64 adr)  {  	unsigned int part_id, sdw_version;  	int i; @@ -1070,102 +1213,41 @@ static inline int find_codec_info_part(const u64 adr)  		if (part_id == codec_info_list[i].part_id &&  		    (!codec_info_list[i].version_id ||  		     sdw_version == codec_info_list[i].version_id)) -			return i; +			return &codec_info_list[i]; -	return -EINVAL; +	return NULL;  } -static inline int find_codec_info_acpi(const u8 *acpi_id) +static struct sof_sdw_codec_info *find_codec_info_acpi(const u8 *acpi_id)  {  	int i;  	if (!acpi_id[0]) -		return -EINVAL; +		return NULL;  	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)  		if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) -			return i; +			return &codec_info_list[i]; -	return -EINVAL; +	return NULL;  } -/* - * get BE dailink number and CPU DAI number based on sdw link adr. - * Since some sdw slaves may be aggregated, the CPU DAI number - * may be larger than the number of BE dailinks. - */ -static int get_dailink_info(struct device *dev, -			    const struct snd_soc_acpi_link_adr *adr_link, -			    int *sdw_be_num, int *codecs_num) +static struct sof_sdw_codec_info *find_codec_info_dai(const char *dai_name, +						      int *dai_index)  { -	bool group_visited[SDW_MAX_GROUPS]; -	bool no_aggregation; -	int i; -	int j; - -	no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; -	*sdw_be_num  = 0; - -	if (!adr_link) -		return -EINVAL; - -	for (i = 0; i < SDW_MAX_GROUPS; i++) -		group_visited[i] = false; - -	for (; adr_link->num_adr; adr_link++) { -		const struct snd_soc_acpi_endpoint *endpoint; -		struct sof_sdw_codec_info *codec_info; -		int codec_index; -		int stream; -		u64 adr; - -		/* make sure the link mask has a single bit set */ -		if (!is_power_of_2(adr_link->mask)) -			return -EINVAL; - -		for (i = 0; i < adr_link->num_adr; i++) { -			adr = adr_link->adr_d[i].adr; -			codec_index = find_codec_info_part(adr); -			if (codec_index < 0) -				return codec_index; - -			codec_info = &codec_info_list[codec_index]; - -			*codecs_num += codec_info->dai_num; - -			if (!adr_link->adr_d[i].name_prefix) { -				dev_err(dev, "codec 0x%llx does not have a name prefix\n", -					adr_link->adr_d[i].adr); -				return -EINVAL; -			} - -			endpoint = adr_link->adr_d[i].endpoints; -			if (endpoint->aggregated && !endpoint->group_id) { -				dev_err(dev, "invalid group id on link %x\n", -					adr_link->mask); -				return -EINVAL; -			} - -			for (j = 0; j < codec_info->dai_num; j++) { -				/* count DAI number for playback and capture */ -				for_each_pcm_streams(stream) { -					if (!codec_info->dais[j].direction[stream]) -						continue; +	int i, j; -					/* count BE for each non-aggregated slave or group */ -					if (!endpoint->aggregated || no_aggregation || -					    !group_visited[endpoint->group_id]) -						(*sdw_be_num)++; -				} +	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { +		for (j = 0; j < codec_info_list[i].dai_num; j++) { +			if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { +				*dai_index = j; +				return &codec_info_list[i];  			} - -			if (endpoint->aggregated) -				group_visited[endpoint->group_id] = true;  		}  	} -	return 0; +	return NULL;  }  static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, @@ -1250,395 +1332,558 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,  	return true;  } -static int fill_sdw_codec_dlc(struct device *dev, -			      const struct snd_soc_acpi_link_adr *adr_link, -			      struct snd_soc_dai_link_component *codec, -			      int adr_index, int dai_index) +static const char *get_codec_name(struct device *dev, +				  const struct sof_sdw_codec_info *codec_info, +				  const struct snd_soc_acpi_link_adr *adr_link, +				  int adr_index)  { -	unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id;  	u64 adr = adr_link->adr_d[adr_index].adr; -	int codec_index; - -	codec_index = find_codec_info_part(adr); -	if (codec_index < 0) -		return codec_index; - -	sdw_version = SDW_VERSION(adr); -	link_id = SDW_DISCO_LINK_ID(adr); -	unique_id = SDW_UNIQUE_ID(adr); -	mfg_id = SDW_MFG_ID(adr); -	part_id = SDW_PART_ID(adr); -	class_id = SDW_CLASS_ID(adr); - -	if (codec_info_list[codec_index].codec_name) -		codec->name = devm_kstrdup(dev, -					   codec_info_list[codec_index].codec_name, -					   GFP_KERNEL); +	unsigned int sdw_version = SDW_VERSION(adr); +	unsigned int link_id = SDW_DISCO_LINK_ID(adr); +	unsigned int unique_id = SDW_UNIQUE_ID(adr); +	unsigned int mfg_id = SDW_MFG_ID(adr); +	unsigned int part_id = SDW_PART_ID(adr); +	unsigned int class_id = SDW_CLASS_ID(adr); + +	if (codec_info->codec_name) +		return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL);  	else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id,  				  class_id, adr_index)) -		codec->name = devm_kasprintf(dev, GFP_KERNEL, -					     "sdw:0:%01x:%04x:%04x:%02x", link_id, -					     mfg_id, part_id, class_id); +		return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", +				      link_id, mfg_id, part_id, class_id);  	else -		codec->name = devm_kasprintf(dev, GFP_KERNEL, -					     "sdw:0:%01x:%04x:%04x:%02x:%01x", link_id, -					     mfg_id, part_id, class_id, unique_id); +		return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", +				      link_id, mfg_id, part_id, class_id, unique_id); -	if (!codec->name) -		return -ENOMEM; - -	codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; - -	return 0; +	return NULL;  } -static int set_codec_init_func(struct snd_soc_card *card, -			       const struct snd_soc_acpi_link_adr *adr_link, -			       struct snd_soc_dai_link *dai_links, -			       bool playback, int group_id, int adr_index, int dai_index) +static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)  { -	int i = adr_index; +	struct snd_soc_card *card = rtd->card; +	struct sof_sdw_codec_info *codec_info; +	struct snd_soc_dai *dai; +	int dai_index; +	int ret; +	int i; + +	for_each_rtd_codec_dais(rtd, i, dai) { +		codec_info = find_codec_info_dai(dai->name, &dai_index); +		if (!codec_info) +			return -EINVAL; -	do {  		/* -		 * Initialize the codec. If codec is part of an aggregated -		 * group (group_id>0), initialize all codecs belonging to -		 * same group. -		 * The first link should start with adr_link->adr_d[adr_index] -		 * because that is the device that we want to initialize and -		 * we should end immediately if it is not aggregated (group_id=0) +		 * A codec dai can be connected to different dai links for capture and playback, +		 * but we only need to call the rtd_init function once. +		 * The rtd_init for each codec dai is independent. So, the order of rtd_init +		 * doesn't matter.  		 */ -		for ( ; i < adr_link->num_adr; i++) { -			int codec_index; +		if (codec_info->dais[dai_index].rtd_init_done) +			continue; -			codec_index = find_codec_info_part(adr_link->adr_d[i].adr); -			if (codec_index < 0) -				return codec_index; +		/* +		 * Add card controls and dapm widgets for the first codec dai. +		 * The controls and widgets will be used for all codec dais. +		 */ -			/* The group_id is > 0 iff the codec is aggregated */ -			if (adr_link->adr_d[i].endpoints->group_id != group_id) -				continue; +		if (i > 0) +			goto skip_add_controls_widgets; -			if (codec_info_list[codec_index].dais[dai_index].init) -				codec_info_list[codec_index].dais[dai_index].init(card, -						adr_link, -						dai_links, -						&codec_info_list[codec_index], -						playback); -			if (!group_id) -				return 0; +		if (codec_info->dais[dai_index].controls) { +			ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls, +							codec_info->dais[dai_index].num_controls); +			if (ret) { +				dev_err(card->dev, "%#x controls addition failed: %d\n", +					codec_info->part_id, ret); +				return ret; +			} +		} +		if (codec_info->dais[dai_index].widgets) { +			ret = snd_soc_dapm_new_controls(&card->dapm, +							codec_info->dais[dai_index].widgets, +							codec_info->dais[dai_index].num_widgets); +			if (ret) { +				dev_err(card->dev, "%#x widgets addition failed: %d\n", +					codec_info->part_id, ret); +				return ret; +			}  		} -		i = 0; -		adr_link++; -	} while (adr_link->mask); +skip_add_controls_widgets: +		if (codec_info->dais[dai_index].rtd_init) { +			ret = codec_info->dais[dai_index].rtd_init(rtd, dai); +			if (ret) +				return ret; +		} +		codec_info->dais[dai_index].rtd_init_done = true; +	}  	return 0;  } -/* - * check endpoint status in slaves and gather link ID for all slaves in - * the same group to generate different CPU DAI. Now only support - * one sdw link with all slaves set with only single group id. - * - * one slave on one sdw link with aggregated = 0 - * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI - * - * two or more slaves on one sdw link with aggregated = 0 - * one sdw BE DAI  <---> one-cpu DAI <---> multi-codec DAIs - * - * multiple links with multiple slaves with aggregated = 1 - * one sdw BE DAI  <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs - */ -static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, -			  struct device *dev, int *cpu_dai_id, int *cpu_dai_num, -			  int *codec_num, unsigned int *group_id, -			  int adr_index) -{ -	bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; -	int i; +struct sof_sdw_endpoint { +	struct list_head list; -	if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) { -		cpu_dai_id[0] = ffs(adr_link->mask) - 1; -		*cpu_dai_num = 1; -		*codec_num = 1; -		*group_id = 0; -		return 0; -	} +	u32 link_mask; +	const char *codec_name; +	const char *name_prefix; +	bool include_sidecar; -	*codec_num = 0; -	*cpu_dai_num = 0; -	*group_id = adr_link->adr_d[adr_index].endpoints->group_id; +	struct sof_sdw_codec_info *codec_info; +	const struct sof_sdw_dai_info *dai_info; +}; -	/* Count endpoints with the same group_id in the adr_link */ -	for (; adr_link && adr_link->num_adr; adr_link++) { -		unsigned int link_codecs = 0; +struct sof_sdw_dailink { +	bool initialised; -		for (i = 0; i < adr_link->num_adr; i++) { -			if (adr_link->adr_d[i].endpoints->aggregated && -			    adr_link->adr_d[i].endpoints->group_id == *group_id) -				link_codecs++; -		} +	u8 group_id; +	u32 link_mask[SNDRV_PCM_STREAM_LAST + 1]; +	int num_devs[SNDRV_PCM_STREAM_LAST + 1]; +	struct list_head endpoints; +}; -		if (link_codecs) { -			*codec_num += link_codecs; +static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; -			if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) { -				dev_err(dev, "cpu_dai_id array overflowed\n"); -				return -EINVAL; -			} +static int count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) +{ +	struct device *dev = card->dev; +	struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); +	struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; +	const struct snd_soc_acpi_link_adr *adr_link; +	int i; -			cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; -		} +	for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { +		*num_devs += adr_link->num_adr; + +		for (i = 0; i < adr_link->num_adr; i++) +			*num_ends += adr_link->adr_d[i].num_endpoints;  	} +	dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); +  	return 0;  } -static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps, -			    int codec_num, int cpu_num) +static struct sof_sdw_dailink *find_dailink(struct sof_sdw_dailink *dailinks, +					    const struct snd_soc_acpi_endpoint *new)  { -	int step; -	int i; +	while (dailinks->initialised) { +		if (new->aggregated && dailinks->group_id == new->group_id) +			return dailinks; -	step = codec_num / cpu_num; -	for (i = 0; i < codec_num; i++) { -		sdw_codec_ch_maps[i].cpu	= i / step; -		sdw_codec_ch_maps[i].codec	= i; +		dailinks++;  	} -} -static inline int find_codec_info_dai(const char *dai_name, int *dai_index) -{ -	int i, j; +	INIT_LIST_HEAD(&dailinks->endpoints); +	dailinks->group_id = new->group_id; +	dailinks->initialised = true; -	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { -		for (j = 0; j < codec_info_list[i].dai_num; j++) { -			if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { -				*dai_index = j; -				return i; -			} -		} -	} - -	return -EINVAL; +	return dailinks;  } -static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) +static int parse_sdw_endpoints(struct snd_soc_card *card, +			       struct sof_sdw_dailink *sof_dais, +			       struct sof_sdw_endpoint *sof_ends, +			       int *num_devs)  { -	struct sof_sdw_codec_info *codec_info; -	struct snd_soc_dai *dai; -	int codec_index; -	int dai_index; +	struct device *dev = card->dev; +	struct mc_private *ctx = snd_soc_card_get_drvdata(card); +	struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); +	struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; +	const struct snd_soc_acpi_link_adr *adr_link; +	struct sof_sdw_endpoint *sof_end = sof_ends; +	int num_dais = 0; +	int i, j;  	int ret; -	int i; -	for_each_rtd_codec_dais(rtd, i, dai) { -		codec_index = find_codec_info_dai(dai->name, &dai_index); -		if (codec_index < 0) -			return -EINVAL; +	for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { +		int num_link_dailinks = 0; -		codec_info = &codec_info_list[codec_index]; -		/* -		 * A codec dai can be connected to different dai links for capture and playback, -		 * but we only need to call the rtd_init function once. -		 * The rtd_init for each codec dai is independent. So, the order of rtd_init -		 * doesn't matter. -		 */ -		if (codec_info->dais[dai_index].rtd_init_done) -			continue; -		if (codec_info->dais[dai_index].rtd_init) { -			ret = codec_info->dais[dai_index].rtd_init(rtd); -			if (ret) -				return ret; +		if (!is_power_of_2(adr_link->mask)) { +			dev_err(dev, "link with multiple mask bits: 0x%x\n", +				adr_link->mask); +			return -EINVAL;  		} -		codec_info->dais[dai_index].rtd_init_done = true; -	} -	return 0; -} - -static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; +		for (i = 0; i < adr_link->num_adr; i++) { +			const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; +			struct sof_sdw_codec_info *codec_info; +			const char *codec_name; -static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, -			      struct snd_soc_dai_link *dai_links, int sdw_be_num, -			      const struct snd_soc_acpi_link_adr *adr_link, -			      struct snd_soc_codec_conf *codec_conf, -			      int codec_count, int *be_id, -			      int *codec_conf_index, -			      bool *ignore_pch_dmic, -			      bool append_dai_type, -			      int adr_index, -			      int dai_index) -{ -	struct mc_private *ctx = snd_soc_card_get_drvdata(card); -	struct device *dev = card->dev; -	const struct snd_soc_acpi_link_adr *adr_link_next; -	struct snd_soc_dai_link_component *codecs; -	struct snd_soc_dai_link_component *cpus; -	struct sof_sdw_codec_info *codec_info; -	int cpu_dai_id[SDW_MAX_CPU_DAIS]; -	int cpu_dai_num; -	unsigned int group_id; -	int codec_dlc_index = 0; -	int codec_index; -	int codec_num; -	int stream; -	int i = 0; -	int j, k; -	int ret; +			if (!adr_dev->name_prefix) { +				dev_err(dev, "codec 0x%llx does not have a name prefix\n", +					adr_dev->adr); +				return -EINVAL; +			} -	ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, -			     &group_id, adr_index); -	if (ret) -		return ret; +			codec_info = find_codec_info_part(adr_dev->adr); +			if (!codec_info) +				return -EINVAL; -	codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL); -	if (!codecs) -		return -ENOMEM; +			ctx->ignore_pch_dmic |= codec_info->ignore_pch_dmic; -	/* generate codec name on different links in the same group */ -	j = adr_index; -	for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && -	     i < cpu_dai_num; adr_link_next++) { -		/* skip the link excluded by this processed group */ -		if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) -			continue; +			codec_name = get_codec_name(dev, codec_info, adr_link, i); +			if (!codec_name) +				return -ENOMEM; -		/* j reset after loop, adr_index only applies to first link */ -		for (; j < adr_link_next->num_adr && codec_dlc_index < codec_num; j++) { -			const struct snd_soc_acpi_endpoint *endpoints; +			dev_dbg(dev, "Adding prefix %s for %s\n", +				adr_dev->name_prefix, codec_name); -			endpoints = adr_link_next->adr_d[j].endpoints; +			sof_end->name_prefix = adr_dev->name_prefix; -			if (group_id && (!endpoints->aggregated || -					 endpoints->group_id != group_id)) -				continue; +			if (codec_info->count_sidecar && codec_info->add_sidecar) { +				ret = codec_info->count_sidecar(card, &num_dais, num_devs); +				if (ret) +					return ret; -			/* sanity check */ -			if (*codec_conf_index >= codec_count) { -				dev_err(dev, "codec_conf array overflowed\n"); -				return -EINVAL; +				sof_end->include_sidecar = true;  			} -			ret = fill_sdw_codec_dlc(dev, adr_link_next, -						 &codecs[codec_dlc_index], -						 j, dai_index); -			if (ret) -				return ret; +			for (j = 0; j < adr_dev->num_endpoints; j++) { +				const struct snd_soc_acpi_endpoint *adr_end; +				const struct sof_sdw_dai_info *dai_info; +				struct sof_sdw_dailink *sof_dai; +				int stream; + +				adr_end = &adr_dev->endpoints[j]; +				dai_info = &codec_info->dais[adr_end->num]; +				sof_dai = find_dailink(sof_dais, adr_end); + +				if (dai_info->quirk && !(dai_info->quirk & sof_sdw_quirk)) +					continue; + +				dev_dbg(dev, +					"Add dev: %d, 0x%llx end: %d, %s, %c/%c to %s: %d\n", +					ffs(adr_link->mask) - 1, adr_dev->adr, +					adr_end->num, type_strings[dai_info->dai_type], +					dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-', +					dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-', +					adr_end->aggregated ? "group" : "solo", +					adr_end->group_id); + +				if (adr_end->num >= codec_info->dai_num) { +					dev_err(dev, +						"%d is too many endpoints for codec: 0x%x\n", +						adr_end->num, codec_info->part_id); +					return -EINVAL; +				} -			codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index]; -			codec_conf[*codec_conf_index].name_prefix = -					adr_link_next->adr_d[j].name_prefix; +				for_each_pcm_streams(stream) { +					if (dai_info->direction[stream] && +					    dai_info->dailink[stream] < 0) { +						dev_err(dev, +							"Invalid dailink id %d for codec: 0x%x\n", +							dai_info->dailink[stream], +							codec_info->part_id); +						return -EINVAL; +					} + +					if (dai_info->direction[stream]) { +						num_dais += !sof_dai->num_devs[stream]; +						sof_dai->num_devs[stream]++; +						sof_dai->link_mask[stream] |= adr_link->mask; +					} +				} -			codec_dlc_index++; -			(*codec_conf_index)++; +				num_link_dailinks += !!list_empty(&sof_dai->endpoints); +				list_add_tail(&sof_end->list, &sof_dai->endpoints); + +				sof_end->link_mask = adr_link->mask; +				sof_end->codec_name = codec_name; +				sof_end->codec_info = codec_info; +				sof_end->dai_info = dai_info; +				sof_end++; +			}  		} -		j = 0; -		/* check next link to create codec dai in the processed group */ -		i++; +		ctx->append_dai_type |= (num_link_dailinks > 1);  	} -	/* find codec info to create BE DAI */ -	codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr); -	if (codec_index < 0) -		return codec_index; -	codec_info = &codec_info_list[codec_index]; +	return num_dais; +} -	if (codec_info->ignore_pch_dmic) -		*ignore_pch_dmic = true; +static int create_sdw_dailink(struct snd_soc_card *card, +			      struct sof_sdw_dailink *sof_dai, +			      struct snd_soc_dai_link **dai_links, +			      int *be_id, struct snd_soc_codec_conf **codec_conf) +{ +	struct device *dev = card->dev; +	struct mc_private *ctx = snd_soc_card_get_drvdata(card); +	struct sof_sdw_endpoint *sof_end; +	int stream; +	int ret; + +	list_for_each_entry(sof_end, &sof_dai->endpoints, list) { +		if (sof_end->name_prefix) { +			(*codec_conf)->dlc.name = sof_end->codec_name; +			(*codec_conf)->name_prefix = sof_end->name_prefix; +			(*codec_conf)++; +		} + +		if (sof_end->include_sidecar) { +			ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); +			if (ret) +				return ret; +		} +	}  	for_each_pcm_streams(stream) { -		struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps; -		char *name, *cpu_name; -		int playback, capture;  		static const char * const sdw_stream_name[] = {  			"SDW%d-Playback",  			"SDW%d-Capture",  			"SDW%d-Playback-%s",  			"SDW%d-Capture-%s",  		}; +		struct snd_soc_dai_link_ch_map *codec_maps; +		struct snd_soc_dai_link_component *codecs; +		struct snd_soc_dai_link_component *cpus; +		int num_cpus = hweight32(sof_dai->link_mask[stream]); +		int num_codecs = sof_dai->num_devs[stream]; +		int playback, capture; +		int cur_link = 0; +		int i = 0, j = 0; +		char *name; -		if (!codec_info->dais[dai_index].direction[stream]) +		if (!sof_dai->num_devs[stream])  			continue; -		*be_id = codec_info->dais[dai_index].dailink[stream]; +		sof_end = list_first_entry(&sof_dai->endpoints, +					   struct sof_sdw_endpoint, list); + +		*be_id = sof_end->dai_info->dailink[stream];  		if (*be_id < 0) {  			dev_err(dev, "Invalid dailink id %d\n", *be_id);  			return -EINVAL;  		} -		sdw_codec_ch_maps = devm_kcalloc(dev, codec_num, -						 sizeof(*sdw_codec_ch_maps), GFP_KERNEL); -		if (!sdw_codec_ch_maps) -			return -ENOMEM; -  		/* create stream name according to first link id */ -		if (append_dai_type) { +		if (ctx->append_dai_type)  			name = devm_kasprintf(dev, GFP_KERNEL, -					      sdw_stream_name[stream + 2], cpu_dai_id[0], -					      type_strings[codec_info->dais[dai_index].dai_type]); -		} else { +					      sdw_stream_name[stream + 2], +					      ffs(sof_end->link_mask) - 1, +					      type_strings[sof_end->dai_info->dai_type]); +		else  			name = devm_kasprintf(dev, GFP_KERNEL, -					      sdw_stream_name[stream], cpu_dai_id[0]); -		} +					      sdw_stream_name[stream], +					      ffs(sof_end->link_mask) - 1);  		if (!name)  			return -ENOMEM; -		cpus = devm_kcalloc(dev, cpu_dai_num, sizeof(*cpus), GFP_KERNEL); +		cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);  		if (!cpus)  			return -ENOMEM; -		/* -		 * generate CPU DAI name base on the sdw link ID and -		 * PIN ID with offset of 2 according to sdw dai driver. -		 */ -		for (k = 0; k < cpu_dai_num; k++) { -			cpu_name = devm_kasprintf(dev, GFP_KERNEL, -						  "SDW%d Pin%d", cpu_dai_id[k], -						  ctx->sdw_pin_index[cpu_dai_id[k]]++); -			if (!cpu_name) -				return -ENOMEM; +		codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); +		if (!codecs) +			return -ENOMEM; -			cpus[k].dai_name = cpu_name; -		} +		codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); +		if (!codec_maps) +			return -ENOMEM; -		/* -		 * We create sdw dai links at first stage, so link index should -		 * not be larger than sdw_be_num -		 */ -		if (*link_index >= sdw_be_num) { -			dev_err(dev, "invalid dai link index %d\n", *link_index); -			return -EINVAL; +		list_for_each_entry(sof_end, &sof_dai->endpoints, list) { +			if (!sof_end->dai_info->direction[stream]) +				continue; + +			if (cur_link != sof_end->link_mask) { +				int link_num = ffs(sof_end->link_mask) - 1; +				int pin_num = ctx->sdw_pin_index[link_num]++; + +				cur_link = sof_end->link_mask; + +				cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, +								  "SDW%d Pin%d", +								  link_num, pin_num); +				if (!cpus[i].dai_name) +					return -ENOMEM; +				i++; +			} + +			codec_maps[j].cpu = i - 1; +			codec_maps[j].codec = j; + +			codecs[j].name = sof_end->codec_name; +			codecs[j].dai_name = sof_end->dai_info->dai_name; +			j++;  		} +		WARN_ON(i != num_cpus || j != num_codecs); +  		playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);  		capture = (stream == SNDRV_PCM_STREAM_CAPTURE); -		init_dai_link(dev, dai_links + *link_index, be_id, name, -			      playback, capture, cpus, cpu_dai_num, codecs, codec_num, +		init_dai_link(dev, *dai_links, be_id, name, playback, capture, +			      cpus, num_cpus, codecs, num_codecs,  			      sof_sdw_rtd_init, &sdw_ops);  		/*  		 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations  		 * based on wait_for_completion(), tag them as 'nonatomic'.  		 */ -		dai_links[*link_index].nonatomic = true; - -		set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); -		dai_links[*link_index].ch_maps = sdw_codec_ch_maps; -		ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, -					  playback, group_id, adr_index, dai_index); -		if (ret < 0) { -			dev_err(dev, "failed to init codec %d\n", codec_index); +		(*dai_links)->nonatomic = true; +		(*dai_links)->ch_maps = codec_maps; + +		list_for_each_entry(sof_end, &sof_dai->endpoints, list) { +			if (sof_end->dai_info->init) +				sof_end->dai_info->init(card, *dai_links, +							sof_end->codec_info, +							playback); +		} + +		(*dai_links)++; +	} + +	return 0; +} + +static int create_sdw_dailinks(struct snd_soc_card *card, +			       struct snd_soc_dai_link **dai_links, int *be_id, +			       struct sof_sdw_dailink *sof_dais, +			       struct snd_soc_codec_conf **codec_conf) +{ +	struct mc_private *ctx = snd_soc_card_get_drvdata(card); +	int ret, i; + +	for (i = 0; i < SDW_MAX_LINKS; i++) +		ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; + +	/* generate DAI links by each sdw link */ +	while (sof_dais->initialised) { +		int current_be_id; + +		ret = create_sdw_dailink(card, sof_dais, dai_links, +					 ¤t_be_id, codec_conf); +		if (ret)  			return ret; + +		/* Update the be_id to match the highest ID used for SDW link */ +		if (*be_id < current_be_id) +			*be_id = current_be_id; + +		sof_dais++; +	} + +	return 0; +} + +static int create_ssp_dailinks(struct snd_soc_card *card, +			       struct snd_soc_dai_link **dai_links, int *be_id, +			       struct sof_sdw_codec_info *ssp_info, +			       unsigned long ssp_mask) +{ +	struct device *dev = card->dev; +	int i, j = 0; +	int ret; + +	for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) { +		char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); +		char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); +		char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", +						  ssp_info->acpi_id, j++); +		int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; +		int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; + +		ret = init_simple_dai_link(dev, *dai_links, be_id, name, +					   playback, capture, cpu_dai_name, +					   codec_name, ssp_info->dais[0].dai_name, +					   NULL, ssp_info->ops); +		if (ret) +			return ret; + +		ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0); +		if (ret < 0) +			return ret; + +		(*dai_links)++; +	} + +	return 0; +} + +static int create_dmic_dailinks(struct snd_soc_card *card, +				struct snd_soc_dai_link **dai_links, int *be_id) +{ +	struct device *dev = card->dev; +	int ret; + +	ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic01", +				   0, 1, // DMIC only supports capture +				   "DMIC01 Pin", "dmic-codec", "dmic-hifi", +				   sof_sdw_dmic_init, NULL); +	if (ret) +		return ret; + +	(*dai_links)++; + +	ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", +				   0, 1, // DMIC only supports capture +				   "DMIC16k Pin", "dmic-codec", "dmic-hifi", +				   /* don't call sof_sdw_dmic_init() twice */ +				   NULL, NULL); +	if (ret) +		return ret; + +	(*dai_links)++; + +	return 0; +} + +static int create_hdmi_dailinks(struct snd_soc_card *card, +				struct snd_soc_dai_link **dai_links, int *be_id, +				int hdmi_num) +{ +	struct device *dev = card->dev; +	struct mc_private *ctx = snd_soc_card_get_drvdata(card); +	int i, ret; + +	for (i = 0; i < hdmi_num; i++) { +		char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); +		char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); +		char *codec_name, *codec_dai_name; + +		if (ctx->hdmi.idisp_codec) { +			codec_name = "ehdaudio0D2"; +			codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, +							"intel-hdmi-hifi%d", i + 1); +		} else { +			codec_name = "snd-soc-dummy"; +			codec_dai_name = "snd-soc-dummy-dai";  		} + +		ret = init_simple_dai_link(dev, *dai_links, be_id, name, +					   1, 0, // HDMI only supports playback +					   cpu_dai_name, codec_name, codec_dai_name, +					   i == 0 ? sof_sdw_hdmi_init : NULL, NULL); +		if (ret) +			return ret; + +		(*dai_links)++;  	}  	return 0;  } +static int create_bt_dailinks(struct snd_soc_card *card, +			      struct snd_soc_dai_link **dai_links, int *be_id) +{ +	struct device *dev = card->dev; +	int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> +			SOF_BT_OFFLOAD_SSP_SHIFT; +	char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); +	char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); +	int ret; + +	ret = init_simple_dai_link(dev, *dai_links, be_id, name, +				   1, 1, cpu_dai_name, snd_soc_dummy_dlc.name, +				   snd_soc_dummy_dlc.dai_name, NULL, NULL); +	if (ret) +		return ret; + +	(*dai_links)++; + +	return 0; +} +  static int sof_card_dai_links_create(struct snd_soc_card *card)  {  	struct device *dev = card->dev; @@ -1646,38 +1891,51 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)  	int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;  	struct mc_private *ctx = snd_soc_card_get_drvdata(card);  	struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; -	const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; -	bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION);  	struct snd_soc_codec_conf *codec_conf; -	bool append_dai_type = false; -	bool ignore_pch_dmic = false; -	int codec_conf_num = 0; -	int codec_conf_index = 0; -	bool group_generated[SDW_MAX_GROUPS] = { }; -	int ssp_codec_index, ssp_mask; +	struct sof_sdw_codec_info *ssp_info; +	struct sof_sdw_endpoint *sof_ends; +	struct sof_sdw_dailink *sof_dais; +	int num_devs = 0; +	int num_ends = 0;  	struct snd_soc_dai_link *dai_links; -	int num_links, link_index = 0; -	char *name, *cpu_dai_name; -	char *codec_name, *codec_dai_name; -	int i, j, be_id = 0; -	int codec_index; +	int num_links; +	int be_id = 0;  	int hdmi_num; +	unsigned long ssp_mask;  	int ret; -	ret = get_dailink_info(dev, adr_link, &sdw_be_num, &codec_conf_num); +	ret = count_sdw_endpoints(card, &num_devs, &num_ends);  	if (ret < 0) { -		dev_err(dev, "failed to get sdw link info %d\n", ret); +		dev_err(dev, "failed to count devices/endpoints: %d\n", ret);  		return ret;  	} +	/* One per DAI link, worst case is a DAI link for every endpoint */ +	sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL); +	if (!sof_dais) +		return -ENOMEM; + +	/* One per endpoint, ie. each DAI on each codec/amp */ +	sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL); +	if (!sof_ends) { +		ret = -ENOMEM; +		goto err_dai; +	} + +	ret = parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); +	if (ret < 0) +		goto err_end; + +	sdw_be_num = ret; +  	/*  	 * on generic tgl platform, I2S or sdw mode is supported  	 * based on board rework. A ACPI device is registered in  	 * system only when I2S mode is supported, not sdw mode.  	 * Here check ACPI ID to confirm I2S is supported.  	 */ -	ssp_codec_index = find_codec_info_acpi(mach->id); -	if (ssp_codec_index >= 0) { +	ssp_info = find_codec_info_acpi(mach->id); +	if (ssp_info) {  		ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);  		ssp_num = hweight_long(ssp_mask);  	} @@ -1701,204 +1959,73 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)  		sdw_be_num, ssp_num, dmic_num,  		ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); +	codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); +	if (!codec_conf) { +		ret = -ENOMEM; +		goto err_end; +	} +  	/* allocate BE dailinks */  	num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;  	dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); -	if (!dai_links) -		return -ENOMEM; - -	/* allocate codec conf, will be populated when dailinks are created */ -	codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf), -				  GFP_KERNEL); -	if (!codec_conf) -		return -ENOMEM; - -	/* SDW */ -	if (!sdw_be_num) -		goto SSP; - -	for (i = 0; i < SDW_MAX_LINKS; i++) -		ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; - -	for (; adr_link->num_adr; adr_link++) { -		/* -		 * If there are two or more different devices on the same sdw link, we have to -		 * append the codec type to the dai link name to prevent duplicated dai link name. -		 * The same type devices on the same sdw link will be in the same -		 * snd_soc_acpi_adr_device array. They won't be described in different adr_links. -		 */ -		for (i = 0; i < adr_link->num_adr; i++) { -			/* find codec info to get dai_num */ -			codec_index = find_codec_info_part(adr_link->adr_d[i].adr); -			if (codec_index < 0) -				return codec_index; -			if (codec_info_list[codec_index].dai_num > 1) { -				append_dai_type = true; -				goto out; -			} -			for (j = 0; j < i; j++) { -				if ((SDW_PART_ID(adr_link->adr_d[i].adr) != -				    SDW_PART_ID(adr_link->adr_d[j].adr)) || -				    (SDW_MFG_ID(adr_link->adr_d[i].adr) != -				    SDW_MFG_ID(adr_link->adr_d[j].adr))) { -					append_dai_type = true; -					goto out; -				} -			} -		} +	if (!dai_links) { +		ret = -ENOMEM; +		goto err_end;  	} -out: - -	/* generate DAI links by each sdw link */ -	for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) { -		for (i = 0; i < adr_link->num_adr; i++) { -			const struct snd_soc_acpi_endpoint *endpoint; - -			endpoint = adr_link->adr_d[i].endpoints; -			/* this group has been generated */ -			if (endpoint->aggregated && -			    group_generated[endpoint->group_id]) -				continue; - -			/* find codec info to get dai_num */ -			codec_index = find_codec_info_part(adr_link->adr_d[i].adr); -			if (codec_index < 0) -				return codec_index; - -			for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { -				int current_be_id; - -				ret = create_sdw_dailink(card, &link_index, dai_links, -							 sdw_be_num, adr_link, -							 codec_conf, codec_conf_num, -							 ¤t_be_id, &codec_conf_index, -							 &ignore_pch_dmic, append_dai_type, i, j); -				if (ret < 0) { -					dev_err(dev, "failed to create dai link %d\n", link_index); -					return ret; -				} - -				/* Update the be_id to match the highest ID used for SDW link */ -				if (be_id < current_be_id) -					be_id = current_be_id; -			} +	card->codec_conf = codec_conf; +	card->num_configs = num_devs; +	card->dai_link = dai_links; +	card->num_links = num_links; -			if (aggregation && endpoint->aggregated) -				group_generated[endpoint->group_id] = true; -		} +	/* SDW */ +	if (sdw_be_num) { +		ret = create_sdw_dailinks(card, &dai_links, &be_id, +					  sof_dais, &codec_conf); +		if (ret) +			goto err_end;  	} -SSP:  	/* SSP */ -	if (!ssp_num) -		goto DMIC; - -	for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) { -		struct sof_sdw_codec_info *info; -		int playback, capture; - -		if (!(ssp_mask & 0x1)) -			continue; - -		info = &codec_info_list[ssp_codec_index]; - -		name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); -		cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); -		codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", -					    info->acpi_id, j++); - -		playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; -		capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - -		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, -					   playback, capture, cpu_dai_name, -					   codec_name, info->dais[0].dai_name, -					   NULL, info->ops); +	if (ssp_num) { +		ret = create_ssp_dailinks(card, &dai_links, &be_id, +					  ssp_info, ssp_mask);  		if (ret) -			return ret; - -		ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0); -		if (ret < 0) -			return ret; - -		link_index++; +			goto err_end;  	} -DMIC:  	/* dmic */  	if (dmic_num > 0) { -		if (ignore_pch_dmic) { +		if (ctx->ignore_pch_dmic) {  			dev_warn(dev, "Ignoring PCH DMIC\n"); -			goto HDMI; +		} else { +			ret = create_dmic_dailinks(card, &dai_links, &be_id); +			if (ret) +				goto err_end;  		} - -		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic01", -					   0, 1, // DMIC only supports capture -					   "DMIC01 Pin", "dmic-codec", "dmic-hifi", -					   sof_sdw_dmic_init, NULL); -		if (ret) -			return ret; - -		link_index++; - -		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic16k", -					   0, 1, // DMIC only supports capture -					   "DMIC16k Pin", "dmic-codec", "dmic-hifi", -					   /* don't call sof_sdw_dmic_init() twice */ -					   NULL, NULL); -		if (ret) -			return ret; - -		link_index++;  	} -HDMI:  	/* HDMI */ -	for (i = 0; i < hdmi_num; i++) { -		name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); -		cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); - -		if (ctx->hdmi.idisp_codec) { -			codec_name = "ehdaudio0D2"; -			codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, -							"intel-hdmi-hifi%d", i + 1); -		} else { -			codec_name = "snd-soc-dummy"; -			codec_dai_name = "snd-soc-dummy-dai"; -		} - -		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, -					   1, 0, // HDMI only supports playback -					   cpu_dai_name, codec_name, codec_dai_name, -					   i == 0 ? sof_sdw_hdmi_init : NULL, NULL); -		if (ret) -			return ret; - -		link_index++; -	} +	ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num); +	if (ret) +		goto err_end; +	/* BT */  	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { -		int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> -				SOF_BT_OFFLOAD_SSP_SHIFT; - -		name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); -		cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); - -		ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, -					   1, 1, cpu_dai_name, snd_soc_dummy_dlc.name, -					   snd_soc_dummy_dlc.dai_name, NULL, NULL); +		ret = create_bt_dailinks(card, &dai_links, &be_id);  		if (ret) -			return ret; +			goto err_end;  	} -	card->dai_link = dai_links; -	card->num_links = num_links; +	WARN_ON(codec_conf != card->codec_conf + card->num_configs); +	WARN_ON(dai_links != card->dai_link + card->num_links); -	card->codec_conf = codec_conf; -	card->num_configs = codec_conf_num; +err_end: +	kfree(sof_ends); +err_dai: +	kfree(sof_dais); -	return 0; +	return ret;  }  static int sof_sdw_card_late_probe(struct snd_soc_card *card) @@ -1922,15 +2049,6 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card)  	return ret;  } -/* SoC card */ -static const char sdw_card_long_name[] = "Intel Soundwire SOF"; - -static struct snd_soc_card card_sof_sdw = { -	.name = "soundwire", -	.owner = THIS_MODULE, -	.late_probe = sof_sdw_card_late_probe, -}; -  /* helper to get the link that the codec DAI is used */  static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card,  						       const char *dai_name) @@ -1982,20 +2100,24 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card)  static int mc_probe(struct platform_device *pdev)  { -	struct snd_soc_card *card = &card_sof_sdw;  	struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); +	struct snd_soc_card *card;  	struct mc_private *ctx;  	int amp_num = 0, i;  	int ret; -	card->dev = &pdev->dev; - -	dev_dbg(card->dev, "Entry\n"); +	dev_dbg(&pdev->dev, "Entry\n"); -	ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL); +	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);  	if (!ctx)  		return -ENOMEM; +	card = &ctx->card; +	card->dev = &pdev->dev; +	card->name = "soundwire", +	card->owner = THIS_MODULE, +	card->late_probe = sof_sdw_card_late_probe, +  	snd_soc_card_set_drvdata(card, ctx);  	dmi_check_system(sof_sdw_quirk_table); @@ -2031,9 +2153,7 @@ static int mc_probe(struct platform_device *pdev)  		amp_num += codec_info_list[i].amp_num;  	card->components = devm_kasprintf(card->dev, GFP_KERNEL, -					  "cfg-spk:%d cfg-amp:%d", -					  (sof_sdw_quirk & SOF_SDW_FOUR_SPK) -					  ? 4 : 2, amp_num); +					  " cfg-amp:%d", amp_num);  	if (!card->components)  		return -ENOMEM; @@ -2046,8 +2166,6 @@ static int mc_probe(struct platform_device *pdev)  			return -ENOMEM;  	} -	card->long_name = sdw_card_long_name; -  	/* Register the card */  	ret = devm_snd_soc_register_card(card->dev, card);  	if (ret) { @@ -2092,4 +2210,3 @@ MODULE_AUTHOR("Rander Wang <[email protected]>");  MODULE_AUTHOR("Pierre-Louis Bossart <[email protected]>");  MODULE_LICENSE("GPL v2");  MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);  |