Linux Audio

Check our new training course

Yocto distribution development and maintenance

Need a Yocto distribution for your embedded project?
Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// Copyright(c) 2022 Intel Corporation
  4
  5/*
  6 * sof_ssp_amp.c - ASoc Machine driver for Intel platforms
  7 * with RT1308/CS35L41 codec.
  8 */
  9
 10#include <linux/acpi.h>
 11#include <linux/delay.h>
 12#include <linux/dmi.h>
 13#include <linux/module.h>
 14#include <linux/platform_device.h>
 15#include <sound/core.h>
 16#include <sound/jack.h>
 17#include <sound/pcm.h>
 18#include <sound/pcm_params.h>
 19#include <sound/sof.h>
 20#include "sof_board_helpers.h"
 
 21#include "sof_realtek_common.h"
 22#include "sof_cirrus_common.h"
 23
 24/* Driver-specific board quirks: from bit 0 to 7 */
 25#define SOF_HDMI_PLAYBACK_PRESENT		BIT(0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 26
 27/* Default: SSP2  */
 28static unsigned long sof_ssp_amp_quirk = SOF_SSP_PORT_AMP(2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 29
 30static const struct dmi_system_id chromebook_platforms[] = {
 31	{
 32		.ident = "Google Chromebooks",
 33		.matches = {
 34			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 35		}
 36	},
 37	{},
 38};
 39
 
 
 
 
 
 
 
 
 
 40static int sof_card_late_probe(struct snd_soc_card *card)
 41{
 42	return sof_intel_board_card_late_probe(card);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 43}
 44
 45static struct snd_soc_card sof_ssp_amp_card = {
 46	.name         = "ssp_amp",
 47	.owner        = THIS_MODULE,
 
 
 
 
 48	.fully_routed = true,
 49	.late_probe = sof_card_late_probe,
 50};
 51
 52/* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */
 53#define HDMI_IN_BE_ID		0
 54#define SPK_BE_ID		2
 55#define DMIC01_BE_ID		3
 56#define INTEL_HDMI_BE_ID	5
 57/* extra BE links to support no-hdmi-in boards */
 58#define DMIC16K_BE_ID		4
 59#define BT_OFFLOAD_BE_ID	8
 60
 61#define SSP_AMP_LINK_ORDER	SOF_LINK_ORDER(SOF_LINK_HDMI_IN, \
 62					SOF_LINK_AMP,            \
 63					SOF_LINK_DMIC01,         \
 64					SOF_LINK_DMIC16K,        \
 65					SOF_LINK_IDISP_HDMI,     \
 66					SOF_LINK_BT_OFFLOAD,     \
 67					SOF_LINK_NONE)
 68
 69#define SSP_AMP_LINK_IDS	SOF_LINK_ORDER(HDMI_IN_BE_ID, \
 70					SPK_BE_ID,            \
 71					DMIC01_BE_ID,         \
 72					DMIC16K_BE_ID,        \
 73					INTEL_HDMI_BE_ID,     \
 74					BT_OFFLOAD_BE_ID,     \
 75					0)
 76
 77static int
 78sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
 79			  struct sof_card_private *ctx)
 80{
 81	int ret;
 
 
 82
 83	ret = sof_intel_board_set_dai_link(dev, card, ctx);
 84	if (ret)
 85		return ret;
 86
 87	if (ctx->amp_type == CODEC_NONE)
 88		return 0;
 
 89
 90	if (!ctx->amp_link) {
 91		dev_err(dev, "amp link not available");
 92		return -EINVAL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 93	}
 94
 95	/* codec-specific fields for speaker amplifier */
 96	switch (ctx->amp_type) {
 97	case CODEC_CS35L41:
 98		cs35l41_set_dai_link(ctx->amp_link);
 99		break;
100	case CODEC_RT1308:
101		sof_rt1308_dai_link(ctx->amp_link);
102		break;
103	default:
104		dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
105		return -EINVAL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106	}
107
108	return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109}
110
111static int sof_ssp_amp_probe(struct platform_device *pdev)
112{
113	struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
 
114	struct sof_card_private *ctx;
115	int ret;
 
 
 
 
 
116
117	if (pdev->id_entry && pdev->id_entry->driver_data)
118		sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
119
120	dev_dbg(&pdev->dev, "sof_ssp_amp_quirk = %lx\n", sof_ssp_amp_quirk);
121
122	/* initialize ctx with board quirk */
123	ctx = sof_intel_board_get_ctx(&pdev->dev, sof_ssp_amp_quirk);
124	if (!ctx)
125		return -ENOMEM;
 
 
 
126
127	if (!dmi_check_system(chromebook_platforms) &&
128	    (mach->mach_params.dmic_num == 0))
129		ctx->dmic_be_num = 0;
130
131	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
 
 
 
 
 
 
132		if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
133			ctx->hdmi.idisp_codec = true;
134	} else {
135		ctx->hdmi_num = 0;
136	}
137
138	ctx->link_order_overwrite = SSP_AMP_LINK_ORDER;
 
139
140	if (ctx->ssp_mask_hdmi_in) {
141		/* the topology supports HDMI-IN uses fixed BE ID for DAI links */
142		ctx->link_id_overwrite = SSP_AMP_LINK_IDS;
143	}
144
145	/* update dai_link */
146	ret = sof_card_dai_links_create(&pdev->dev, &sof_ssp_amp_card, ctx);
147	if (ret)
148		return ret;
149
150	/* update codec_conf */
151	switch (ctx->amp_type) {
152	case CODEC_CS35L41:
153		cs35l41_set_codec_conf(&sof_ssp_amp_card);
154		break;
155	case CODEC_RT1308:
156	case CODEC_NONE:
157		/* no codec conf required */
158		break;
159	default:
160		dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
161		return -EINVAL;
162	}
163
 
 
164	sof_ssp_amp_card.dev = &pdev->dev;
165
166	/* set platform name for each dailink */
167	ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
168						    mach->mach_params.platform);
169	if (ret)
170		return ret;
171
 
 
172	snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
173
174	return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
175}
176
177static const struct platform_device_id board_ids[] = {
178	{
179		.name = "sof_ssp_amp",
180	},
181	{
182		.name = "tgl_rt1308_hdmi_ssp",
183		.driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(2) |
184					SOF_SSP_MASK_HDMI_CAPTURE(0x22)),
185					/* SSP 1 and SSP 5 are used for HDMI IN */
 
 
 
186	},
187	{
188		.name = "adl_cs35l41",
189		.driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(1) |
190					SOF_NUM_IDISP_HDMI(4) |
191					SOF_HDMI_PLAYBACK_PRESENT |
192					SOF_SSP_PORT_BT_OFFLOAD(2) |
193					SOF_BT_OFFLOAD_PRESENT),
194	},
195	{
196		.name = "adl_lt6911_hdmi_ssp",
197		.driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
198					/* SSP 0 and SSP 2 are used for HDMI IN */
199					SOF_HDMI_PLAYBACK_PRESENT),
200	},
201	{
202		.name = "rpl_lt6911_hdmi_ssp",
203		.driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
204					/* SSP 0 and SSP 2 are used for HDMI IN */
205					SOF_HDMI_PLAYBACK_PRESENT),
206	},
207	{
208		.name = "mtl_lt6911_hdmi_ssp",
209		.driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
210					/* SSP 0 and SSP 2 are used for HDMI IN */
211					SOF_HDMI_PLAYBACK_PRESENT),
212	},
213	{
214		.name = "arl_lt6911_hdmi_ssp",
215		.driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) |
216					/* SSP 0 and SSP 2 are used for HDMI IN */
217					SOF_HDMI_PLAYBACK_PRESENT),
218	},
219	{ }
220};
221MODULE_DEVICE_TABLE(platform, board_ids);
222
223static struct platform_driver sof_ssp_amp_driver = {
224	.probe          = sof_ssp_amp_probe,
225	.driver = {
226		.name   = "sof_ssp_amp",
227		.pm = &snd_soc_pm_ops,
228	},
229	.id_table = board_ids,
230};
231module_platform_driver(sof_ssp_amp_driver);
232
233MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
234MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>");
235MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
236MODULE_LICENSE("GPL");
237MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
238MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON");
239MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_CIRRUS_COMMON");
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// Copyright(c) 2022 Intel Corporation. All rights reserved.
  4
  5/*
  6 * sof_ssp_amp.c - ASoc Machine driver for Intel platforms
  7 * with RT1308/CS35L41 codec.
  8 */
  9
 10#include <linux/acpi.h>
 11#include <linux/delay.h>
 12#include <linux/dmi.h>
 13#include <linux/module.h>
 14#include <linux/platform_device.h>
 15#include <sound/core.h>
 16#include <sound/jack.h>
 17#include <sound/pcm.h>
 18#include <sound/pcm_params.h>
 19#include <sound/sof.h>
 20#include "../../codecs/hdac_hdmi.h"
 21#include "hda_dsp_common.h"
 22#include "sof_realtek_common.h"
 23#include "sof_cirrus_common.h"
 24
 25#define NAME_SIZE 32
 26
 27/* SSP port ID for speaker amplifier */
 28#define SOF_AMPLIFIER_SSP(quirk)		((quirk) & GENMASK(3, 0))
 29#define SOF_AMPLIFIER_SSP_MASK			(GENMASK(3, 0))
 30
 31/* HDMI capture*/
 32#define SOF_SSP_HDMI_CAPTURE_PRESENT		BIT(4)
 33#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT		5
 34#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK		(GENMASK(6, 5))
 35#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk)	\
 36	(((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
 37
 38#define SOF_HDMI_CAPTURE_1_SSP_SHIFT		7
 39#define SOF_HDMI_CAPTURE_1_SSP_MASK		(GENMASK(9, 7))
 40#define SOF_HDMI_CAPTURE_1_SSP(quirk)	\
 41	(((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
 42
 43#define SOF_HDMI_CAPTURE_2_SSP_SHIFT		10
 44#define SOF_HDMI_CAPTURE_2_SSP_MASK		(GENMASK(12, 10))
 45#define SOF_HDMI_CAPTURE_2_SSP(quirk)	\
 46	(((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
 47
 48/* HDMI playback */
 49#define SOF_HDMI_PLAYBACK_PRESENT		BIT(13)
 50#define SOF_NO_OF_HDMI_PLAYBACK_SHIFT		14
 51#define SOF_NO_OF_HDMI_PLAYBACK_MASK		(GENMASK(16, 14))
 52#define SOF_NO_OF_HDMI_PLAYBACK(quirk)	\
 53	(((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK)
 54
 55/* BT audio offload */
 56#define SOF_SSP_BT_OFFLOAD_PRESENT		BIT(17)
 57#define SOF_BT_OFFLOAD_SSP_SHIFT		18
 58#define SOF_BT_OFFLOAD_SSP_MASK			(GENMASK(20, 18))
 59#define SOF_BT_OFFLOAD_SSP(quirk)	\
 60	(((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
 61
 62/* Speaker amplifiers */
 63#define SOF_RT1308_SPEAKER_AMP_PRESENT		BIT(21)
 64#define SOF_CS35L41_SPEAKER_AMP_PRESENT		BIT(22)
 65
 66/* Default: SSP2  */
 67static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2);
 68
 69struct sof_hdmi_pcm {
 70	struct list_head head;
 71	struct snd_soc_jack sof_hdmi;
 72	struct snd_soc_dai *codec_dai;
 73	int device;
 74};
 75
 76struct sof_card_private {
 77	struct list_head hdmi_pcm_list;
 78	bool common_hdmi_codec_drv;
 79	bool idisp_codec;
 80};
 81
 82static const struct dmi_system_id chromebook_platforms[] = {
 83	{
 84		.ident = "Google Chromebooks",
 85		.matches = {
 86			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 87		}
 88	},
 89	{},
 90};
 91
 92static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = {
 93	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
 94};
 95
 96static const struct snd_soc_dapm_route sof_ssp_amp_dapm_routes[] = {
 97	/* digital mics */
 98	{"DMic", NULL, "SoC DMIC"},
 99};
100
101static int sof_card_late_probe(struct snd_soc_card *card)
102{
103	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
104	struct snd_soc_component *component = NULL;
105	char jack_name[NAME_SIZE];
106	struct sof_hdmi_pcm *pcm;
107	int err;
108	int i;
109
110	if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT))
111		return 0;
112
113	/* HDMI is not supported by SOF on Baytrail/CherryTrail */
114	if (!ctx->idisp_codec)
115		return 0;
116
117	if (list_empty(&ctx->hdmi_pcm_list))
118		return -EINVAL;
119
120	if (ctx->common_hdmi_codec_drv) {
121		pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
122				       head);
123		component = pcm->codec_dai->component;
124		return hda_dsp_hdmi_build_controls(card, component);
125	}
126
127	i = 0;
128	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
129		component = pcm->codec_dai->component;
130		snprintf(jack_name, sizeof(jack_name),
131			 "HDMI/DP, pcm=%d Jack", pcm->device);
132		err = snd_soc_card_jack_new(card, jack_name,
133					    SND_JACK_AVOUT, &pcm->sof_hdmi);
134
135		if (err)
136			return err;
137
138		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
139					  &pcm->sof_hdmi);
140		if (err < 0)
141			return err;
142
143		i++;
144	}
145
146	return hdac_hdmi_jack_port_init(component, &card->dapm);
147}
148
149static struct snd_soc_card sof_ssp_amp_card = {
150	.name         = "ssp_amp",
151	.owner        = THIS_MODULE,
152	.dapm_widgets = sof_ssp_amp_dapm_widgets,
153	.num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets),
154	.dapm_routes = sof_ssp_amp_dapm_routes,
155	.num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes),
156	.fully_routed = true,
157	.late_probe = sof_card_late_probe,
158};
159
160static struct snd_soc_dai_link_component platform_component[] = {
161	{
162		/* name might be overridden during probe */
163		.name = "0000:00:1f.3"
164	}
165};
166
167static struct snd_soc_dai_link_component dmic_component[] = {
168	{
169		.name = "dmic-codec",
170		.dai_name = "dmic-hifi",
171	}
172};
173
174static struct snd_soc_dai_link_component dummy_component[] = {
175	{
176		.name = "snd-soc-dummy",
177		.dai_name = "snd-soc-dummy-dai",
178	}
179};
180
181static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
 
 
 
 
 
 
182{
183	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
184	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
185	struct sof_hdmi_pcm *pcm;
186
187	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
188	if (!pcm)
189		return -ENOMEM;
190
191	/* dai_link id is 1:1 mapped to the PCM device */
192	pcm->device = rtd->dai_link->id;
193	pcm->codec_dai = dai;
194
195	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
196
197	return 0;
198}
199
200#define IDISP_CODEC_MASK	0x4
201
202static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
203							  int ssp_codec,
204							  int dmic_be_num,
205							  int hdmi_num,
206							  bool idisp_codec)
207{
208	struct snd_soc_dai_link_component *idisp_components;
209	struct snd_soc_dai_link_component *cpus;
210	struct snd_soc_dai_link *links;
211	int i, id = 0;
212
213	links = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
214					sizeof(struct snd_soc_dai_link), GFP_KERNEL);
215	cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
216					sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
217	if (!links || !cpus)
218		return NULL;
219
220	/* HDMI-In SSP */
221	if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
222		int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
223				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
224
225		for (i = 1; i <= num_of_hdmi_ssp; i++) {
226			int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
227						SOF_HDMI_CAPTURE_1_SSP_SHIFT :
228						(sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
229						SOF_HDMI_CAPTURE_2_SSP_SHIFT);
230
231			links[id].cpus = &cpus[id];
232			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
233								  "SSP%d Pin", port);
234			if (!links[id].cpus->dai_name)
235				return NULL;
236			links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
237			if (!links[id].name)
238				return NULL;
239			links[id].id = id;
240			links[id].codecs = dummy_component;
241			links[id].num_codecs = ARRAY_SIZE(dummy_component);
242			links[id].platforms = platform_component;
243			links[id].num_platforms = ARRAY_SIZE(platform_component);
244			links[id].dpcm_capture = 1;
245			links[id].no_pcm = 1;
246			links[id].num_cpus = 1;
247			id++;
248		}
249	}
250
251	/* codec SSP */
252	links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
253	if (!links[id].name)
254		return NULL;
255
256	links[id].id = id;
257	if (sof_ssp_amp_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) {
258		sof_rt1308_dai_link(&links[id]);
259	} else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
260		cs35l41_set_dai_link(&links[id]);
261	}
262	links[id].platforms = platform_component;
263	links[id].num_platforms = ARRAY_SIZE(platform_component);
264	links[id].dpcm_playback = 1;
265	/* feedback from amplifier or firmware-generated echo reference */
266	links[id].dpcm_capture = 1;
267	links[id].no_pcm = 1;
268	links[id].cpus = &cpus[id];
269	links[id].num_cpus = 1;
270	links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec);
271	if (!links[id].cpus->dai_name)
272		return NULL;
273
274	id++;
275
276	/* dmic */
277	if (dmic_be_num > 0) {
278		/* at least we have dmic01 */
279		links[id].name = "dmic01";
280		links[id].cpus = &cpus[id];
281		links[id].cpus->dai_name = "DMIC01 Pin";
282		if (dmic_be_num > 1) {
283			/* set up 2 BE links at most */
284			links[id + 1].name = "dmic16k";
285			links[id + 1].cpus = &cpus[id + 1];
286			links[id + 1].cpus->dai_name = "DMIC16k Pin";
287			dmic_be_num = 2;
288		}
289	}
290
291	for (i = 0; i < dmic_be_num; i++) {
292		links[id].id = id;
293		links[id].num_cpus = 1;
294		links[id].codecs = dmic_component;
295		links[id].num_codecs = ARRAY_SIZE(dmic_component);
296		links[id].platforms = platform_component;
297		links[id].num_platforms = ARRAY_SIZE(platform_component);
298		links[id].ignore_suspend = 1;
299		links[id].dpcm_capture = 1;
300		links[id].no_pcm = 1;
301		id++;
302	}
303
304	/* HDMI playback */
305	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
306		/* HDMI */
307		if (hdmi_num > 0) {
308			idisp_components = devm_kcalloc(dev,
309					   hdmi_num,
310					   sizeof(struct snd_soc_dai_link_component),
311					   GFP_KERNEL);
312			if (!idisp_components)
313				goto devm_err;
314		}
315		for (i = 1; i <= hdmi_num; i++) {
316			links[id].name = devm_kasprintf(dev, GFP_KERNEL,
317							"iDisp%d", i);
318			if (!links[id].name)
319				goto devm_err;
320
321			links[id].id = id;
322			links[id].cpus = &cpus[id];
323			links[id].num_cpus = 1;
324			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
325								  "iDisp%d Pin", i);
326			if (!links[id].cpus->dai_name)
327				goto devm_err;
328
329			if (idisp_codec) {
330				idisp_components[i - 1].name = "ehdaudio0D2";
331				idisp_components[i - 1].dai_name = devm_kasprintf(dev,
332										  GFP_KERNEL,
333										  "intel-hdmi-hifi%d",
334										  i);
335				if (!idisp_components[i - 1].dai_name)
336					goto devm_err;
337			} else {
338				idisp_components[i - 1].name = "snd-soc-dummy";
339				idisp_components[i - 1].dai_name = "snd-soc-dummy-dai";
340			}
341
342			links[id].codecs = &idisp_components[i - 1];
343			links[id].num_codecs = 1;
344			links[id].platforms = platform_component;
345			links[id].num_platforms = ARRAY_SIZE(platform_component);
346			links[id].init = sof_hdmi_init;
347			links[id].dpcm_playback = 1;
348			links[id].no_pcm = 1;
349			id++;
350		}
351	}
352
353	/* BT audio offload */
354	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
355		int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
356				SOF_BT_OFFLOAD_SSP_SHIFT;
357
358		links[id].id = id;
359		links[id].cpus = &cpus[id];
360		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
361							  "SSP%d Pin", port);
362		if (!links[id].cpus->dai_name)
363			goto devm_err;
364		links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
365		if (!links[id].name)
366			goto devm_err;
367		links[id].codecs = dummy_component;
368		links[id].num_codecs = ARRAY_SIZE(dummy_component);
369		links[id].platforms = platform_component;
370		links[id].num_platforms = ARRAY_SIZE(platform_component);
371		links[id].dpcm_playback = 1;
372		links[id].dpcm_capture = 1;
373		links[id].no_pcm = 1;
374		links[id].num_cpus = 1;
375		id++;
376	}
377
378	return links;
379devm_err:
380	return NULL;
381}
382
383static int sof_ssp_amp_probe(struct platform_device *pdev)
384{
385	struct snd_soc_dai_link *dai_links;
386	struct snd_soc_acpi_mach *mach;
387	struct sof_card_private *ctx;
388	int dmic_be_num = 0, hdmi_num = 0;
389	int ret, ssp_codec;
390
391	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
392	if (!ctx)
393		return -ENOMEM;
394
395	if (pdev->id_entry && pdev->id_entry->driver_data)
396		sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
397
398	mach = pdev->dev.platform_data;
399
400	if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0)
401		dmic_be_num = 2;
402
403	ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
404
405	/* set number of dai links */
406	sof_ssp_amp_card.num_links = 1 + dmic_be_num;
407
408	if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
409		sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
410				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
411
412	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
413		hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
414				SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
415		/* default number of HDMI DAI's */
416		if (!hdmi_num)
417			hdmi_num = 3;
418
419		if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
420			ctx->idisp_codec = true;
421
422		sof_ssp_amp_card.num_links += hdmi_num;
423	}
424
425	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
426		sof_ssp_amp_card.num_links++;
427
428	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num, hdmi_num, ctx->idisp_codec);
429	if (!dai_links)
430		return -ENOMEM;
 
431
432	sof_ssp_amp_card.dai_link = dai_links;
 
 
 
433
434	/* update codec_conf */
435	if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
 
436		cs35l41_set_codec_conf(&sof_ssp_amp_card);
 
 
 
 
 
 
 
 
437	}
438
439	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
440
441	sof_ssp_amp_card.dev = &pdev->dev;
442
443	/* set platform name for each dailink */
444	ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
445						    mach->mach_params.platform);
446	if (ret)
447		return ret;
448
449	ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
450
451	snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
452
453	return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
454}
455
456static const struct platform_device_id board_ids[] = {
457	{
458		.name = "sof_ssp_amp",
459	},
460	{
461		.name = "tgl_rt1308_hdmi_ssp",
462		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
463					SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
464					SOF_HDMI_CAPTURE_1_SSP(1) |
465					SOF_HDMI_CAPTURE_2_SSP(5) |
466					SOF_SSP_HDMI_CAPTURE_PRESENT |
467					SOF_RT1308_SPEAKER_AMP_PRESENT),
468	},
469	{
470		.name = "adl_cs35l41",
471		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
472					SOF_NO_OF_HDMI_PLAYBACK(4) |
473					SOF_HDMI_PLAYBACK_PRESENT |
474					SOF_BT_OFFLOAD_SSP(2) |
475					SOF_SSP_BT_OFFLOAD_PRESENT |
476					SOF_CS35L41_SPEAKER_AMP_PRESENT),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477	},
478	{ }
479};
480MODULE_DEVICE_TABLE(platform, board_ids);
481
482static struct platform_driver sof_ssp_amp_driver = {
483	.probe          = sof_ssp_amp_probe,
484	.driver = {
485		.name   = "sof_ssp_amp",
486		.pm = &snd_soc_pm_ops,
487	},
488	.id_table = board_ids,
489};
490module_platform_driver(sof_ssp_amp_driver);
491
492MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
493MODULE_AUTHOR("balamurugan.c <balamurugan.c@intel.com>");
494MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
495MODULE_LICENSE("GPL");
496MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
497MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
498MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);