diff mbox series

[7/8] ASoC: Intel: sof_ssp_amp: rename driver and support cs35l41 amplifier

Message ID 20220301194903.60859-8-pierre-louis.bossart@linux.intel.com
State New
Headers show
Series ASoC: Intel: machine driver updates for 5.18 | expand

Commit Message

Pierre-Louis Bossart March 1, 2022, 7:49 p.m. UTC
From: Brent Lu <brent.lu@intel.com>

Add support of CS35L41 amplifier to the machine driver, as well as
the support of HDMI playback and BT offload DAI Link.

Rename the driver to a generic name to support different amplifiers
from different vendors.

Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Brent Lu <brent.lu@intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/soc/intel/boards/Kconfig                |  12 +-
 sound/soc/intel/boards/Makefile               |   4 +-
 sound/soc/intel/boards/sof_rt1308.c           | 257 ----------
 sound/soc/intel/boards/sof_ssp_amp.c          | 483 ++++++++++++++++++
 .../intel/common/soc-acpi-intel-adl-match.c   |   6 +
 5 files changed, 499 insertions(+), 263 deletions(-)
 delete mode 100644 sound/soc/intel/boards/sof_rt1308.c
 create mode 100644 sound/soc/intel/boards/sof_ssp_amp.c

Comments

Amadeusz Sławiński March 2, 2022, 2:56 p.m. UTC | #1
On 3/1/2022 8:49 PM, Pierre-Louis Bossart wrote:
> From: Brent Lu <brent.lu@intel.com>
> 
> Add support of CS35L41 amplifier to the machine driver, as well as
> the support of HDMI playback and BT offload DAI Link.
> 
> Rename the driver to a generic name to support different amplifiers
> from different vendors.
> 
> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
> Signed-off-by: Brent Lu <brent.lu@intel.com>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> ---

Eh... rename should happen in separate patch, as there seems to be some 
changes done to the file and it is quite hard to review it, when whole 
file is in diff due to being moved.
Pierre-Louis Bossart March 2, 2022, 3:50 p.m. UTC | #2
On 3/2/22 8:56 AM, Amadeusz Sławiński wrote:
> On 3/1/2022 8:49 PM, Pierre-Louis Bossart wrote:
>> From: Brent Lu <brent.lu@intel.com>
>>
>> Add support of CS35L41 amplifier to the machine driver, as well as
>> the support of HDMI playback and BT offload DAI Link.
>>
>> Rename the driver to a generic name to support different amplifiers
>> from different vendors.
>>
>> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
>> Signed-off-by: Brent Lu <brent.lu@intel.com>
>> Signed-off-by: Pierre-Louis Bossart 
>> <pierre-louis.bossart@linux.intel.com>
>> ---
> 
> Eh... rename should happen in separate patch, as there seems to be some 
> changes done to the file and it is quite hard to review it, when whole 
> file is in diff due to being moved.

that was a conscious decision on my side to keep the patches as is, 
first add the initial contribution for the rt1308 amp from our embedded 
Linux team, and show how it was extended to support another amplifier 
for Chrome.

Indeed it leads to a bit of a tick-tock patch with the rename but it's 
not that bad, is it? The alternative would lead to a much bigger patch 
if I squash the whole thing.
Amadeusz Sławiński March 2, 2022, 4:05 p.m. UTC | #3
On 3/2/2022 4:50 PM, Pierre-Louis Bossart wrote:
> 
> 
> On 3/2/22 8:56 AM, Amadeusz Sławiński wrote:
>> On 3/1/2022 8:49 PM, Pierre-Louis Bossart wrote:
>>> From: Brent Lu <brent.lu@intel.com>
>>>
>>> Add support of CS35L41 amplifier to the machine driver, as well as
>>> the support of HDMI playback and BT offload DAI Link.
>>>
>>> Rename the driver to a generic name to support different amplifiers
>>> from different vendors.
>>>
>>> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
>>> Signed-off-by: Brent Lu <brent.lu@intel.com>
>>> Signed-off-by: Pierre-Louis Bossart 
>>> <pierre-louis.bossart@linux.intel.com>
>>> ---
>>
>> Eh... rename should happen in separate patch, as there seems to be 
>> some changes done to the file and it is quite hard to review it, when 
>> whole file is in diff due to being moved.
> 
> that was a conscious decision on my side to keep the patches as is, 
> first add the initial contribution for the rt1308 amp from our embedded 
> Linux team, and show how it was extended to support another amplifier 
> for Chrome.
> 
> Indeed it leads to a bit of a tick-tock patch with the rename but it's 
> not that bad, is it? The alternative would lead to a much bigger patch 
> if I squash the whole thing.

I think you've misunderstood me, I'm not talking about squashing, but 
splitting patch 7 into two separate patches - one doing rename and 
another adding/changing things.

I was looking at:
+	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
+					sof_ssp_amp_card.num_links, GFP_KERNEL);
+	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
+					sof_ssp_amp_card.num_links, GFP_KERNEL);

and wondered where sof_ssp_amp_card.num_links comes from, and it only 
shows up 4 times in removed file, but 6 times in added one, which tells 
me that things changed, but it is hard to see what, when the diff shows 
whole files being moved instead of things that changed.
Mark Brown March 2, 2022, 4:10 p.m. UTC | #4
On Wed, Mar 02, 2022 at 05:05:05PM +0100, Amadeusz Sławiński wrote:

> I think you've misunderstood me, I'm not talking about squashing, but
> splitting patch 7 into two separate patches - one doing rename and another
> adding/changing things.

> I was looking at:
> +	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
> +					sof_ssp_amp_card.num_links, GFP_KERNEL);
> +	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
> +					sof_ssp_amp_card.num_links, GFP_KERNEL);

> and wondered where sof_ssp_amp_card.num_links comes from, and it only shows
> up 4 times in removed file, but 6 times in added one, which tells me that
> things changed, but it is hard to see what, when the diff shows whole files
> being moved instead of things that changed.

That would've been a bit nicer but TBH it was fine - I've already queued
the patches.
diff mbox series

Patch

diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index f29f9b731ed9..da59504d2322 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -606,16 +606,20 @@  config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH
 
 endif ## SND_SOC_SOF_JASPERLAKE
 
-config SND_SOC_INTEL_SOF_RT1308_MACH
-	tristate "SOF with RT1308 in I2S Mode"
+config SND_SOC_INTEL_SOF_SSP_AMP_MACH
+	tristate "SOF with amplifiers in I2S Mode"
 	depends on I2C && ACPI && GPIOLIB
 	depends on MFD_INTEL_LPSS || COMPILE_TEST
 	select SND_SOC_RT1308
+	select SND_SOC_CS35L41_I2C
 	select SND_SOC_DMIC
+	select SND_SOC_HDAC_HDMI
+	select SND_SOC_INTEL_HDA_DSP_COMMON
 	select SND_SOC_INTEL_SOF_REALTEK_COMMON
+	select SND_SOC_INTEL_SOF_CIRRUS_COMMON
 	help
-	   This adds support for ASoC machine driver for Tigerlake platforms
-	   with RT1308 I2S audio codec.
+	   This adds support for ASoC machine driver for SOF platforms
+	   with RT1308/CS35L41 I2S audio codec.
 	   Say Y if you have such a device.
 	   If unsure select "N".
 
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index d0ef71b7af6e..40c0c3d1c500 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -35,7 +35,7 @@  snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
 snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
 snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o
 snd-soc-ehl-rt5660-objs := ehl_rt5660.o
-snd-soc-sof-rt1308-objs := sof_rt1308.o
+snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
 snd-soc-sof-sdw-objs += sof_sdw.o				\
 			sof_sdw_max98373.o			\
 			sof_sdw_rt1308.o sof_sdw_rt1316.o	\
@@ -80,7 +80,7 @@  obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o
 obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o
 obj-$(CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH) += snd-soc-ehl-rt5660.o
 obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH) += snd-soc-sof-sdw.o
-obj-$(CONFIG_SND_SOC_INTEL_SOF_RT1308_MACH) += snd-soc-sof-rt1308.o
+obj-$(CONFIG_SND_SOC_INTEL_SOF_SSP_AMP_MACH) += snd-soc-sof-ssp-amp.o
 
 # common modules
 snd-soc-intel-hda-dsp-common-objs := hda_dsp_common.o
diff --git a/sound/soc/intel/boards/sof_rt1308.c b/sound/soc/intel/boards/sof_rt1308.c
deleted file mode 100644
index 971ab53236a5..000000000000
--- a/sound/soc/intel/boards/sof_rt1308.c
+++ /dev/null
@@ -1,257 +0,0 @@ 
-// SPDX-License-Identifier: GPL-2.0-only
-//
-// Copyright(c) 2022 Intel Corporation. All rights reserved.
-
-/*
- * sof_rt1308.c - ASoc Machine driver for Intel platforms
- * with RT1308 codec.
- */
-
-#include <linux/acpi.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/sof.h>
-#include "sof_realtek_common.h"
-
-#define SOF_RT1308_SSP_CODEC(quirk)		((quirk) & GENMASK(3, 0))
-#define SOF_RT1308_SSP_CODEC_MASK			(GENMASK(3, 0))
-
-/* HDMI capture*/
-#define SOF_SSP_HDMI_CAPTURE_PRESENT		BIT(4)
-#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT		5
-#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK		(GENMASK(6, 5))
-#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk)	\
-	(((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
-
-#define SOF_HDMI_CAPTURE_1_SSP_SHIFT		7
-#define SOF_HDMI_CAPTURE_1_SSP_MASK		(GENMASK(9, 7))
-#define SOF_HDMI_CAPTURE_1_SSP(quirk)	\
-	(((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
-
-#define SOF_HDMI_CAPTURE_2_SSP_SHIFT		10
-#define SOF_HDMI_CAPTURE_2_SSP_MASK		(GENMASK(12, 10))
-#define SOF_HDMI_CAPTURE_2_SSP(quirk)	\
-	(((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
-
-#define SOF_RT1308_SPEAKER_AMP_PRESENT		BIT(13)
-
-/* Default: SSP2  */
-static unsigned long sof_rt1308_quirk = SOF_RT1308_SSP_CODEC(2);
-
-static const struct snd_soc_dapm_widget sof_rt1308_dapm_widgets[] = {
-	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
-};
-
-static const struct snd_soc_dapm_route sof_rt1308_dapm_routes[] = {
-	/* digital mics */
-	{"DMic", NULL, "SoC DMIC"},
-};
-
-static struct snd_soc_card sof_rt1308_card = {
-	.name         = "rt1308",
-	.owner        = THIS_MODULE,
-	.dapm_widgets = sof_rt1308_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(sof_rt1308_dapm_widgets),
-	.dapm_routes = sof_rt1308_dapm_routes,
-	.num_dapm_routes = ARRAY_SIZE(sof_rt1308_dapm_routes),
-	.fully_routed = true,
-};
-
-static struct snd_soc_dai_link_component platform_component[] = {
-	{
-		/* name might be overridden during probe */
-		.name = "0000:00:1f.3"
-	}
-};
-
-static struct snd_soc_dai_link_component dmic_component[] = {
-	{
-		.name = "dmic-codec",
-		.dai_name = "dmic-hifi",
-	}
-};
-
-static struct snd_soc_dai_link_component dummy_component[] = {
-	{
-		.name = "snd-soc-dummy",
-		.dai_name = "snd-soc-dummy-dai",
-	}
-};
-
-static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
-							  int ssp_codec,
-							  int dmic_be_num)
-{
-	struct snd_soc_dai_link_component *cpus;
-	struct snd_soc_dai_link *links;
-	int i, id = 0;
-
-	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
-					sof_rt1308_card.num_links, GFP_KERNEL);
-	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
-					sof_rt1308_card.num_links, GFP_KERNEL);
-	if (!links || !cpus)
-		return NULL;
-
-	/* HDMI-In SSP */
-	if (sof_rt1308_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
-		int num_of_hdmi_ssp = (sof_rt1308_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
-				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
-
-		for (i = 1; i <= num_of_hdmi_ssp; i++) {
-			int port = (i == 1 ? (sof_rt1308_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
-						SOF_HDMI_CAPTURE_1_SSP_SHIFT :
-						(sof_rt1308_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
-						SOF_HDMI_CAPTURE_2_SSP_SHIFT);
-
-			links[id].cpus = &cpus[id];
-			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
-								  "SSP%d Pin", port);
-			if (!links[id].cpus->dai_name)
-				return NULL;
-			links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
-			if (!links[id].name)
-				return NULL;
-			links[id].id = id;
-			links[id].codecs = dummy_component;
-			links[id].num_codecs = ARRAY_SIZE(dummy_component);
-			links[id].platforms = platform_component;
-			links[id].num_platforms = ARRAY_SIZE(platform_component);
-			links[id].dpcm_capture = 1;
-			links[id].no_pcm = 1;
-			links[id].num_cpus = 1;
-			id++;
-		}
-	}
-
-	/* codec SSP */
-	links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
-	if (!links[id].name)
-		return NULL;
-
-	links[id].id = id;
-	if (sof_rt1308_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) {
-		sof_rt1308_dai_link(&links[id]);
-	}
-	links[id].platforms = platform_component;
-	links[id].num_platforms = ARRAY_SIZE(platform_component);
-	links[id].dpcm_playback = 1;
-	links[id].no_pcm = 1;
-	links[id].cpus = &cpus[id];
-	links[id].num_cpus = 1;
-	links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec);
-	if (!links[id].cpus->dai_name)
-		return NULL;
-
-	id++;
-
-	/* dmic */
-	if (dmic_be_num > 0) {
-		/* at least we have dmic01 */
-		links[id].name = "dmic01";
-		links[id].cpus = &cpus[id];
-		links[id].cpus->dai_name = "DMIC01 Pin";
-		if (dmic_be_num > 1) {
-			/* set up 2 BE links at most */
-			links[id + 1].name = "dmic16k";
-			links[id + 1].cpus = &cpus[id + 1];
-			links[id + 1].cpus->dai_name = "DMIC16k Pin";
-			dmic_be_num = 2;
-		}
-	}
-
-	for (i = 0; i < dmic_be_num; i++) {
-		links[id].id = id;
-		links[id].num_cpus = 1;
-		links[id].codecs = dmic_component;
-		links[id].num_codecs = ARRAY_SIZE(dmic_component);
-		links[id].platforms = platform_component;
-		links[id].num_platforms = ARRAY_SIZE(platform_component);
-		links[id].ignore_suspend = 1;
-		links[id].dpcm_capture = 1;
-		links[id].no_pcm = 1;
-		id++;
-	}
-
-	return links;
-}
-
-static int sof_rt1308_probe(struct platform_device *pdev)
-{
-	struct snd_soc_dai_link *dai_links;
-	struct snd_soc_acpi_mach *mach;
-	int dmic_be_num;
-	int ret, ssp_codec;
-
-	if (pdev->id_entry && pdev->id_entry->driver_data)
-		sof_rt1308_quirk = (unsigned long)pdev->id_entry->driver_data;
-
-	mach = pdev->dev.platform_data;
-
-	dmic_be_num = mach->mach_params.dmic_num;
-
-	ssp_codec = sof_rt1308_quirk & SOF_RT1308_SSP_CODEC_MASK;
-
-	/* set number of dai links */
-	sof_rt1308_card.num_links = 1 + dmic_be_num;
-
-	if (sof_rt1308_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
-		sof_rt1308_card.num_links += (sof_rt1308_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
-				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
-
-	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num);
-	if (!dai_links)
-		return -ENOMEM;
-
-	sof_rt1308_card.dai_link = dai_links;
-
-	sof_rt1308_card.dev = &pdev->dev;
-
-	/* set platform name for each dailink */
-	ret = snd_soc_fixup_dai_links_platform_name(&sof_rt1308_card,
-						    mach->mach_params.platform);
-	if (ret)
-		return ret;
-
-	snd_soc_card_set_drvdata(&sof_rt1308_card, NULL);
-
-	return devm_snd_soc_register_card(&pdev->dev, &sof_rt1308_card);
-}
-
-static const struct platform_device_id board_ids[] = {
-	{
-		.name = "sof_rt1308",
-	},
-	{
-		.name = "tgl_rt1308_hdmi_ssp",
-		.driver_data = (kernel_ulong_t)(SOF_RT1308_SSP_CODEC(2) |
-					SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
-					SOF_HDMI_CAPTURE_1_SSP(1) |
-					SOF_HDMI_CAPTURE_2_SSP(5) |
-					SOF_SSP_HDMI_CAPTURE_PRESENT |
-					SOF_RT1308_SPEAKER_AMP_PRESENT),
-	},
-	{ }
-};
-MODULE_DEVICE_TABLE(platform, board_ids);
-
-static struct platform_driver sof_rt1308_driver = {
-	.probe          = sof_rt1308_probe,
-	.driver = {
-		.name   = "sof_rt1308",
-		.pm = &snd_soc_pm_ops,
-	},
-	.id_table = board_ids,
-};
-module_platform_driver(sof_rt1308_driver);
-
-MODULE_DESCRIPTION("ASoC Intel(R) SOF + RT1308 Machine driver");
-MODULE_AUTHOR("balamurugan.c <balamurugan.c@intel.com>");
-MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
-MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c
new file mode 100644
index 000000000000..88530e9de543
--- /dev/null
+++ b/sound/soc/intel/boards/sof_ssp_amp.c
@@ -0,0 +1,483 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+
+/*
+ * sof_ssp_amp.c - ASoc Machine driver for Intel platforms
+ * with RT1308/CS35L41 codec.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/sof.h>
+#include "../../codecs/hdac_hdmi.h"
+#include "hda_dsp_common.h"
+#include "sof_realtek_common.h"
+#include "sof_cirrus_common.h"
+
+#define NAME_SIZE 32
+
+/* SSP port ID for speaker amplifier */
+#define SOF_AMPLIFIER_SSP(quirk)		((quirk) & GENMASK(3, 0))
+#define SOF_AMPLIFIER_SSP_MASK			(GENMASK(3, 0))
+
+/* HDMI capture*/
+#define SOF_SSP_HDMI_CAPTURE_PRESENT		BIT(4)
+#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT		5
+#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK		(GENMASK(6, 5))
+#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk)	\
+	(((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
+
+#define SOF_HDMI_CAPTURE_1_SSP_SHIFT		7
+#define SOF_HDMI_CAPTURE_1_SSP_MASK		(GENMASK(9, 7))
+#define SOF_HDMI_CAPTURE_1_SSP(quirk)	\
+	(((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
+
+#define SOF_HDMI_CAPTURE_2_SSP_SHIFT		10
+#define SOF_HDMI_CAPTURE_2_SSP_MASK		(GENMASK(12, 10))
+#define SOF_HDMI_CAPTURE_2_SSP(quirk)	\
+	(((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
+
+/* HDMI playback */
+#define SOF_HDMI_PLAYBACK_PRESENT		BIT(13)
+#define SOF_NO_OF_HDMI_PLAYBACK_SHIFT		14
+#define SOF_NO_OF_HDMI_PLAYBACK_MASK		(GENMASK(16, 14))
+#define SOF_NO_OF_HDMI_PLAYBACK(quirk)	\
+	(((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK)
+
+/* BT audio offload */
+#define SOF_SSP_BT_OFFLOAD_PRESENT		BIT(17)
+#define SOF_BT_OFFLOAD_SSP_SHIFT		18
+#define SOF_BT_OFFLOAD_SSP_MASK			(GENMASK(20, 18))
+#define SOF_BT_OFFLOAD_SSP(quirk)	\
+	(((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
+
+/* Speaker amplifiers */
+#define SOF_RT1308_SPEAKER_AMP_PRESENT		BIT(21)
+#define SOF_CS35L41_SPEAKER_AMP_PRESENT		BIT(22)
+
+/* Default: SSP2  */
+static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2);
+
+struct sof_hdmi_pcm {
+	struct list_head head;
+	struct snd_soc_jack sof_hdmi;
+	struct snd_soc_dai *codec_dai;
+	int device;
+};
+
+struct sof_card_private {
+	struct list_head hdmi_pcm_list;
+	bool common_hdmi_codec_drv;
+	bool idisp_codec;
+};
+
+static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = {
+	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_route sof_ssp_amp_dapm_routes[] = {
+	/* digital mics */
+	{"DMic", NULL, "SoC DMIC"},
+};
+
+static int sof_card_late_probe(struct snd_soc_card *card)
+{
+	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
+	struct snd_soc_component *component = NULL;
+	char jack_name[NAME_SIZE];
+	struct sof_hdmi_pcm *pcm;
+	int err;
+	int i = 0;
+
+	if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT))
+		return 0;
+
+	/* HDMI is not supported by SOF on Baytrail/CherryTrail */
+	if (!ctx->idisp_codec)
+		return 0;
+
+	if (list_empty(&ctx->hdmi_pcm_list))
+		return -EINVAL;
+
+	if (ctx->common_hdmi_codec_drv) {
+		pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
+				       head);
+		component = pcm->codec_dai->component;
+		return hda_dsp_hdmi_build_controls(card, component);
+	}
+
+	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+		component = pcm->codec_dai->component;
+		snprintf(jack_name, sizeof(jack_name),
+			 "HDMI/DP, pcm=%d Jack", pcm->device);
+		err = snd_soc_card_jack_new(card, jack_name,
+					    SND_JACK_AVOUT, &pcm->sof_hdmi,
+					    NULL, 0);
+
+		if (err)
+			return err;
+
+		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+					  &pcm->sof_hdmi);
+		if (err < 0)
+			return err;
+
+		i++;
+	}
+
+	return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
+
+static struct snd_soc_card sof_ssp_amp_card = {
+	.name         = "ssp_amp",
+	.owner        = THIS_MODULE,
+	.dapm_widgets = sof_ssp_amp_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets),
+	.dapm_routes = sof_ssp_amp_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes),
+	.fully_routed = true,
+	.late_probe = sof_card_late_probe,
+};
+
+static struct snd_soc_dai_link_component platform_component[] = {
+	{
+		/* name might be overridden during probe */
+		.name = "0000:00:1f.3"
+	}
+};
+
+static struct snd_soc_dai_link_component dmic_component[] = {
+	{
+		.name = "dmic-codec",
+		.dai_name = "dmic-hifi",
+	}
+};
+
+static struct snd_soc_dai_link_component dummy_component[] = {
+	{
+		.name = "snd-soc-dummy",
+		.dai_name = "snd-soc-dummy-dai",
+	}
+};
+
+static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
+	struct sof_hdmi_pcm *pcm;
+
+	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+	if (!pcm)
+		return -ENOMEM;
+
+	/* dai_link id is 1:1 mapped to the PCM device */
+	pcm->device = rtd->dai_link->id;
+	pcm->codec_dai = dai;
+
+	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+	return 0;
+}
+
+#define IDISP_CODEC_MASK	0x4
+
+static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
+							  int ssp_codec,
+							  int dmic_be_num,
+							  int hdmi_num,
+							  bool idisp_codec)
+{
+	struct snd_soc_dai_link_component *idisp_components;
+	struct snd_soc_dai_link_component *cpus;
+	struct snd_soc_dai_link *links;
+	int i, id = 0;
+
+	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
+					sof_ssp_amp_card.num_links, GFP_KERNEL);
+	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
+					sof_ssp_amp_card.num_links, GFP_KERNEL);
+	if (!links || !cpus)
+		return NULL;
+
+	/* HDMI-In SSP */
+	if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
+		int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
+				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+
+		for (i = 1; i <= num_of_hdmi_ssp; i++) {
+			int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
+						SOF_HDMI_CAPTURE_1_SSP_SHIFT :
+						(sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
+						SOF_HDMI_CAPTURE_2_SSP_SHIFT);
+
+			links[id].cpus = &cpus[id];
+			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+								  "SSP%d Pin", port);
+			if (!links[id].cpus->dai_name)
+				return NULL;
+			links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
+			if (!links[id].name)
+				return NULL;
+			links[id].id = id;
+			links[id].codecs = dummy_component;
+			links[id].num_codecs = ARRAY_SIZE(dummy_component);
+			links[id].platforms = platform_component;
+			links[id].num_platforms = ARRAY_SIZE(platform_component);
+			links[id].dpcm_capture = 1;
+			links[id].no_pcm = 1;
+			links[id].num_cpus = 1;
+			id++;
+		}
+	}
+
+	/* codec SSP */
+	links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
+	if (!links[id].name)
+		return NULL;
+
+	links[id].id = id;
+	if (sof_ssp_amp_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) {
+		sof_rt1308_dai_link(&links[id]);
+	} else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
+		cs35l41_set_dai_link(&links[id]);
+	}
+	links[id].platforms = platform_component;
+	links[id].num_platforms = ARRAY_SIZE(platform_component);
+	links[id].dpcm_playback = 1;
+	links[id].no_pcm = 1;
+	links[id].cpus = &cpus[id];
+	links[id].num_cpus = 1;
+	links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec);
+	if (!links[id].cpus->dai_name)
+		return NULL;
+
+	id++;
+
+	/* dmic */
+	if (dmic_be_num > 0) {
+		/* at least we have dmic01 */
+		links[id].name = "dmic01";
+		links[id].cpus = &cpus[id];
+		links[id].cpus->dai_name = "DMIC01 Pin";
+		if (dmic_be_num > 1) {
+			/* set up 2 BE links at most */
+			links[id + 1].name = "dmic16k";
+			links[id + 1].cpus = &cpus[id + 1];
+			links[id + 1].cpus->dai_name = "DMIC16k Pin";
+			dmic_be_num = 2;
+		}
+	}
+
+	for (i = 0; i < dmic_be_num; i++) {
+		links[id].id = id;
+		links[id].num_cpus = 1;
+		links[id].codecs = dmic_component;
+		links[id].num_codecs = ARRAY_SIZE(dmic_component);
+		links[id].platforms = platform_component;
+		links[id].num_platforms = ARRAY_SIZE(platform_component);
+		links[id].ignore_suspend = 1;
+		links[id].dpcm_capture = 1;
+		links[id].no_pcm = 1;
+		id++;
+	}
+
+	/* HDMI playback */
+	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
+		/* HDMI */
+		if (hdmi_num > 0) {
+			idisp_components = devm_kzalloc(dev,
+					   sizeof(struct snd_soc_dai_link_component) *
+					   hdmi_num, GFP_KERNEL);
+			if (!idisp_components)
+				goto devm_err;
+		}
+		for (i = 1; i <= hdmi_num; i++) {
+			links[id].name = devm_kasprintf(dev, GFP_KERNEL,
+							"iDisp%d", i);
+			if (!links[id].name)
+				goto devm_err;
+
+			links[id].id = id;
+			links[id].cpus = &cpus[id];
+			links[id].num_cpus = 1;
+			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+								  "iDisp%d Pin", i);
+			if (!links[id].cpus->dai_name)
+				goto devm_err;
+
+			if (idisp_codec) {
+				idisp_components[i - 1].name = "ehdaudio0D2";
+				idisp_components[i - 1].dai_name = devm_kasprintf(dev,
+										  GFP_KERNEL,
+										  "intel-hdmi-hifi%d",
+										  i);
+				if (!idisp_components[i - 1].dai_name)
+					goto devm_err;
+			} else {
+				idisp_components[i - 1].name = "snd-soc-dummy";
+				idisp_components[i - 1].dai_name = "snd-soc-dummy-dai";
+			}
+
+			links[id].codecs = &idisp_components[i - 1];
+			links[id].num_codecs = 1;
+			links[id].platforms = platform_component;
+			links[id].num_platforms = ARRAY_SIZE(platform_component);
+			links[id].init = sof_hdmi_init;
+			links[id].dpcm_playback = 1;
+			links[id].no_pcm = 1;
+			id++;
+		}
+	}
+
+	/* BT audio offload */
+	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
+		int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
+				SOF_BT_OFFLOAD_SSP_SHIFT;
+
+		links[id].id = id;
+		links[id].cpus = &cpus[id];
+		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+							  "SSP%d Pin", port);
+		if (!links[id].cpus->dai_name)
+			goto devm_err;
+		links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
+		if (!links[id].name)
+			goto devm_err;
+		links[id].codecs = dummy_component;
+		links[id].num_codecs = ARRAY_SIZE(dummy_component);
+		links[id].platforms = platform_component;
+		links[id].num_platforms = ARRAY_SIZE(platform_component);
+		links[id].dpcm_playback = 1;
+		links[id].dpcm_capture = 1;
+		links[id].no_pcm = 1;
+		links[id].num_cpus = 1;
+		id++;
+	}
+
+	return links;
+devm_err:
+	return NULL;
+}
+
+static int sof_ssp_amp_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dai_link *dai_links;
+	struct snd_soc_acpi_mach *mach;
+	struct sof_card_private *ctx;
+	int dmic_be_num, hdmi_num = 0;
+	int ret, ssp_codec;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	if (pdev->id_entry && pdev->id_entry->driver_data)
+		sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
+
+	mach = pdev->dev.platform_data;
+
+	dmic_be_num = mach->mach_params.dmic_num;
+
+	ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
+
+	/* set number of dai links */
+	sof_ssp_amp_card.num_links = 1 + dmic_be_num;
+
+	if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
+		sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
+				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+
+	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
+		hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
+				SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
+		/* default number of HDMI DAI's */
+		if (!hdmi_num)
+			hdmi_num = 3;
+
+		if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
+			ctx->idisp_codec = true;
+
+		sof_ssp_amp_card.num_links += hdmi_num;
+	}
+
+	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
+		sof_ssp_amp_card.num_links++;
+
+	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num, hdmi_num, ctx->idisp_codec);
+	if (!dai_links)
+		return -ENOMEM;
+
+	sof_ssp_amp_card.dai_link = dai_links;
+
+	/* update codec_conf */
+	if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
+		cs35l41_set_codec_conf(&sof_ssp_amp_card);
+	}
+
+	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+	sof_ssp_amp_card.dev = &pdev->dev;
+
+	/* set platform name for each dailink */
+	ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
+						    mach->mach_params.platform);
+	if (ret)
+		return ret;
+
+	ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
+
+	snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
+
+	return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
+}
+
+static const struct platform_device_id board_ids[] = {
+	{
+		.name = "sof_ssp_amp",
+	},
+	{
+		.name = "tgl_rt1308_hdmi_ssp",
+		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
+					SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+					SOF_HDMI_CAPTURE_1_SSP(1) |
+					SOF_HDMI_CAPTURE_2_SSP(5) |
+					SOF_SSP_HDMI_CAPTURE_PRESENT |
+					SOF_RT1308_SPEAKER_AMP_PRESENT),
+	},
+	{
+		.name = "adl_cs35l41",
+		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
+					SOF_NO_OF_HDMI_PLAYBACK(4) |
+					SOF_HDMI_PLAYBACK_PRESENT |
+					SOF_BT_OFFLOAD_SSP(2) |
+					SOF_SSP_BT_OFFLOAD_PRESENT |
+					SOF_CS35L41_SPEAKER_AMP_PRESENT),
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, board_ids);
+
+static struct platform_driver sof_ssp_amp_driver = {
+	.probe          = sof_ssp_amp_probe,
+	.driver = {
+		.name   = "sof_ssp_amp",
+		.pm = &snd_soc_pm_ops,
+	},
+	.id_table = board_ids,
+};
+module_platform_driver(sof_ssp_amp_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
+MODULE_AUTHOR("balamurugan.c <balamurugan.c@intel.com>");
+MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
+MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
+MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
index 86444e331d80..f120d7e2aecb 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -444,6 +444,12 @@  struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
 		.drv_name = "adl_rt5682",
 		.sof_tplg_filename = "sof-adl-rt5682.tplg",
 	},
+	/* place amp-only boards in the end of table */
+	{
+		.id = "CSC3541",
+		.drv_name = "adl_cs35l41",
+		.sof_tplg_filename = "sof-adl-cs35l41.tplg",
+	},
 	{},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines);