xref: /linux/sound/soc/intel/boards/sof_ssp_amp.c (revision 8a922b7728a93d837954315c98b84f6b78de0c4f)
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  */
67 static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2);
68 
69 struct 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 
76 struct sof_card_private {
77 	struct list_head hdmi_pcm_list;
78 	bool common_hdmi_codec_drv;
79 	bool idisp_codec;
80 };
81 
82 static 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 
92 static const struct snd_soc_dapm_widget sof_ssp_amp_dapm_widgets[] = {
93 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
94 };
95 
96 static const struct snd_soc_dapm_route sof_ssp_amp_dapm_routes[] = {
97 	/* digital mics */
98 	{"DMic", NULL, "SoC DMIC"},
99 };
100 
101 static 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 
109 	if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT))
110 		return 0;
111 
112 	/* HDMI is not supported by SOF on Baytrail/CherryTrail */
113 	if (!ctx->idisp_codec)
114 		return 0;
115 
116 	if (list_empty(&ctx->hdmi_pcm_list))
117 		return -EINVAL;
118 
119 	if (ctx->common_hdmi_codec_drv) {
120 		pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
121 				       head);
122 		component = pcm->codec_dai->component;
123 		return hda_dsp_hdmi_build_controls(card, component);
124 	}
125 
126 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
127 		component = pcm->codec_dai->component;
128 		snprintf(jack_name, sizeof(jack_name),
129 			 "HDMI/DP, pcm=%d Jack", pcm->device);
130 		err = snd_soc_card_jack_new(card, jack_name,
131 					    SND_JACK_AVOUT, &pcm->sof_hdmi);
132 
133 		if (err)
134 			return err;
135 
136 		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
137 					  &pcm->sof_hdmi);
138 		if (err < 0)
139 			return err;
140 	}
141 
142 	return hdac_hdmi_jack_port_init(component, &card->dapm);
143 }
144 
145 static struct snd_soc_card sof_ssp_amp_card = {
146 	.name         = "ssp_amp",
147 	.owner        = THIS_MODULE,
148 	.dapm_widgets = sof_ssp_amp_dapm_widgets,
149 	.num_dapm_widgets = ARRAY_SIZE(sof_ssp_amp_dapm_widgets),
150 	.dapm_routes = sof_ssp_amp_dapm_routes,
151 	.num_dapm_routes = ARRAY_SIZE(sof_ssp_amp_dapm_routes),
152 	.fully_routed = true,
153 	.late_probe = sof_card_late_probe,
154 };
155 
156 static struct snd_soc_dai_link_component platform_component[] = {
157 	{
158 		/* name might be overridden during probe */
159 		.name = "0000:00:1f.3"
160 	}
161 };
162 
163 static struct snd_soc_dai_link_component dmic_component[] = {
164 	{
165 		.name = "dmic-codec",
166 		.dai_name = "dmic-hifi",
167 	}
168 };
169 
170 static struct snd_soc_dai_link_component dummy_component[] = {
171 	{
172 		.name = "snd-soc-dummy",
173 		.dai_name = "snd-soc-dummy-dai",
174 	}
175 };
176 
177 static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
178 {
179 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
180 	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
181 	struct sof_hdmi_pcm *pcm;
182 
183 	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
184 	if (!pcm)
185 		return -ENOMEM;
186 
187 	/* dai_link id is 1:1 mapped to the PCM device */
188 	pcm->device = rtd->dai_link->id;
189 	pcm->codec_dai = dai;
190 
191 	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
192 
193 	return 0;
194 }
195 
196 #define IDISP_CODEC_MASK	0x4
197 
198 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
199 							  int ssp_codec,
200 							  int dmic_be_num,
201 							  int hdmi_num,
202 							  bool idisp_codec)
203 {
204 	struct snd_soc_dai_link_component *idisp_components;
205 	struct snd_soc_dai_link_component *cpus;
206 	struct snd_soc_dai_link *links;
207 	int i, id = 0;
208 
209 	links = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
210 					sizeof(struct snd_soc_dai_link), GFP_KERNEL);
211 	cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
212 					sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
213 	if (!links || !cpus)
214 		return NULL;
215 
216 	/* HDMI-In SSP */
217 	if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
218 		int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
219 				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
220 
221 		for (i = 1; i <= num_of_hdmi_ssp; i++) {
222 			int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
223 						SOF_HDMI_CAPTURE_1_SSP_SHIFT :
224 						(sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
225 						SOF_HDMI_CAPTURE_2_SSP_SHIFT);
226 
227 			links[id].cpus = &cpus[id];
228 			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
229 								  "SSP%d Pin", port);
230 			if (!links[id].cpus->dai_name)
231 				return NULL;
232 			links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
233 			if (!links[id].name)
234 				return NULL;
235 			links[id].id = id;
236 			links[id].codecs = dummy_component;
237 			links[id].num_codecs = ARRAY_SIZE(dummy_component);
238 			links[id].platforms = platform_component;
239 			links[id].num_platforms = ARRAY_SIZE(platform_component);
240 			links[id].dpcm_capture = 1;
241 			links[id].no_pcm = 1;
242 			links[id].num_cpus = 1;
243 			id++;
244 		}
245 	}
246 
247 	/* codec SSP */
248 	links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
249 	if (!links[id].name)
250 		return NULL;
251 
252 	links[id].id = id;
253 	if (sof_ssp_amp_quirk & SOF_RT1308_SPEAKER_AMP_PRESENT) {
254 		sof_rt1308_dai_link(&links[id]);
255 	} else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
256 		cs35l41_set_dai_link(&links[id]);
257 	}
258 	links[id].platforms = platform_component;
259 	links[id].num_platforms = ARRAY_SIZE(platform_component);
260 	links[id].dpcm_playback = 1;
261 	/* feedback from amplifier or firmware-generated echo reference */
262 	links[id].dpcm_capture = 1;
263 	links[id].no_pcm = 1;
264 	links[id].cpus = &cpus[id];
265 	links[id].num_cpus = 1;
266 	links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec);
267 	if (!links[id].cpus->dai_name)
268 		return NULL;
269 
270 	id++;
271 
272 	/* dmic */
273 	if (dmic_be_num > 0) {
274 		/* at least we have dmic01 */
275 		links[id].name = "dmic01";
276 		links[id].cpus = &cpus[id];
277 		links[id].cpus->dai_name = "DMIC01 Pin";
278 		if (dmic_be_num > 1) {
279 			/* set up 2 BE links at most */
280 			links[id + 1].name = "dmic16k";
281 			links[id + 1].cpus = &cpus[id + 1];
282 			links[id + 1].cpus->dai_name = "DMIC16k Pin";
283 			dmic_be_num = 2;
284 		}
285 	}
286 
287 	for (i = 0; i < dmic_be_num; i++) {
288 		links[id].id = id;
289 		links[id].num_cpus = 1;
290 		links[id].codecs = dmic_component;
291 		links[id].num_codecs = ARRAY_SIZE(dmic_component);
292 		links[id].platforms = platform_component;
293 		links[id].num_platforms = ARRAY_SIZE(platform_component);
294 		links[id].ignore_suspend = 1;
295 		links[id].dpcm_capture = 1;
296 		links[id].no_pcm = 1;
297 		id++;
298 	}
299 
300 	/* HDMI playback */
301 	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
302 		/* HDMI */
303 		if (hdmi_num > 0) {
304 			idisp_components = devm_kcalloc(dev,
305 					   hdmi_num,
306 					   sizeof(struct snd_soc_dai_link_component),
307 					   GFP_KERNEL);
308 			if (!idisp_components)
309 				goto devm_err;
310 		}
311 		for (i = 1; i <= hdmi_num; i++) {
312 			links[id].name = devm_kasprintf(dev, GFP_KERNEL,
313 							"iDisp%d", i);
314 			if (!links[id].name)
315 				goto devm_err;
316 
317 			links[id].id = id;
318 			links[id].cpus = &cpus[id];
319 			links[id].num_cpus = 1;
320 			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
321 								  "iDisp%d Pin", i);
322 			if (!links[id].cpus->dai_name)
323 				goto devm_err;
324 
325 			if (idisp_codec) {
326 				idisp_components[i - 1].name = "ehdaudio0D2";
327 				idisp_components[i - 1].dai_name = devm_kasprintf(dev,
328 										  GFP_KERNEL,
329 										  "intel-hdmi-hifi%d",
330 										  i);
331 				if (!idisp_components[i - 1].dai_name)
332 					goto devm_err;
333 			} else {
334 				idisp_components[i - 1].name = "snd-soc-dummy";
335 				idisp_components[i - 1].dai_name = "snd-soc-dummy-dai";
336 			}
337 
338 			links[id].codecs = &idisp_components[i - 1];
339 			links[id].num_codecs = 1;
340 			links[id].platforms = platform_component;
341 			links[id].num_platforms = ARRAY_SIZE(platform_component);
342 			links[id].init = sof_hdmi_init;
343 			links[id].dpcm_playback = 1;
344 			links[id].no_pcm = 1;
345 			id++;
346 		}
347 	}
348 
349 	/* BT audio offload */
350 	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
351 		int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
352 				SOF_BT_OFFLOAD_SSP_SHIFT;
353 
354 		links[id].id = id;
355 		links[id].cpus = &cpus[id];
356 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
357 							  "SSP%d Pin", port);
358 		if (!links[id].cpus->dai_name)
359 			goto devm_err;
360 		links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
361 		if (!links[id].name)
362 			goto devm_err;
363 		links[id].codecs = dummy_component;
364 		links[id].num_codecs = ARRAY_SIZE(dummy_component);
365 		links[id].platforms = platform_component;
366 		links[id].num_platforms = ARRAY_SIZE(platform_component);
367 		links[id].dpcm_playback = 1;
368 		links[id].dpcm_capture = 1;
369 		links[id].no_pcm = 1;
370 		links[id].num_cpus = 1;
371 		id++;
372 	}
373 
374 	return links;
375 devm_err:
376 	return NULL;
377 }
378 
379 static int sof_ssp_amp_probe(struct platform_device *pdev)
380 {
381 	struct snd_soc_dai_link *dai_links;
382 	struct snd_soc_acpi_mach *mach;
383 	struct sof_card_private *ctx;
384 	int dmic_be_num = 0, hdmi_num = 0;
385 	int ret, ssp_codec;
386 
387 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
388 	if (!ctx)
389 		return -ENOMEM;
390 
391 	if (pdev->id_entry && pdev->id_entry->driver_data)
392 		sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
393 
394 	mach = pdev->dev.platform_data;
395 
396 	if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0)
397 		dmic_be_num = 2;
398 
399 	ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
400 
401 	/* set number of dai links */
402 	sof_ssp_amp_card.num_links = 1 + dmic_be_num;
403 
404 	if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
405 		sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
406 				SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
407 
408 	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
409 		hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
410 				SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
411 		/* default number of HDMI DAI's */
412 		if (!hdmi_num)
413 			hdmi_num = 3;
414 
415 		if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
416 			ctx->idisp_codec = true;
417 
418 		sof_ssp_amp_card.num_links += hdmi_num;
419 	}
420 
421 	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
422 		sof_ssp_amp_card.num_links++;
423 
424 	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, dmic_be_num, hdmi_num, ctx->idisp_codec);
425 	if (!dai_links)
426 		return -ENOMEM;
427 
428 	sof_ssp_amp_card.dai_link = dai_links;
429 
430 	/* update codec_conf */
431 	if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
432 		cs35l41_set_codec_conf(&sof_ssp_amp_card);
433 	}
434 
435 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
436 
437 	sof_ssp_amp_card.dev = &pdev->dev;
438 
439 	/* set platform name for each dailink */
440 	ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
441 						    mach->mach_params.platform);
442 	if (ret)
443 		return ret;
444 
445 	ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
446 
447 	snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
448 
449 	return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
450 }
451 
452 static const struct platform_device_id board_ids[] = {
453 	{
454 		.name = "sof_ssp_amp",
455 	},
456 	{
457 		.name = "tgl_rt1308_hdmi_ssp",
458 		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
459 					SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
460 					SOF_HDMI_CAPTURE_1_SSP(1) |
461 					SOF_HDMI_CAPTURE_2_SSP(5) |
462 					SOF_SSP_HDMI_CAPTURE_PRESENT |
463 					SOF_RT1308_SPEAKER_AMP_PRESENT),
464 	},
465 	{
466 		.name = "adl_cs35l41",
467 		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
468 					SOF_NO_OF_HDMI_PLAYBACK(4) |
469 					SOF_HDMI_PLAYBACK_PRESENT |
470 					SOF_BT_OFFLOAD_SSP(2) |
471 					SOF_SSP_BT_OFFLOAD_PRESENT |
472 					SOF_CS35L41_SPEAKER_AMP_PRESENT),
473 	},
474 	{ }
475 };
476 MODULE_DEVICE_TABLE(platform, board_ids);
477 
478 static struct platform_driver sof_ssp_amp_driver = {
479 	.probe          = sof_ssp_amp_probe,
480 	.driver = {
481 		.name   = "sof_ssp_amp",
482 		.pm = &snd_soc_pm_ops,
483 	},
484 	.id_table = board_ids,
485 };
486 module_platform_driver(sof_ssp_amp_driver);
487 
488 MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
489 MODULE_AUTHOR("balamurugan.c <balamurugan.c@intel.com>");
490 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
491 MODULE_LICENSE("GPL");
492 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
493 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
494 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);
495