xref: /linux/sound/soc/intel/boards/sof_ssp_amp.c (revision 2b0cfa6e49566c8fa6759734cf821aa6e8271a9e)
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 "sof_board_helpers.h"
21 #include "sof_realtek_common.h"
22 #include "sof_cirrus_common.h"
23 #include "sof_ssp_common.h"
24 
25 /* SSP port ID for speaker amplifier */
26 #define SOF_AMPLIFIER_SSP(quirk)		((quirk) & GENMASK(3, 0))
27 #define SOF_AMPLIFIER_SSP_MASK			(GENMASK(3, 0))
28 
29 /* HDMI capture*/
30 #define SOF_HDMI_CAPTURE_SSP_MASK_SHIFT		4
31 #define SOF_HDMI_CAPTURE_SSP_MASK_MASK		(GENMASK(9, 4))
32 #define SOF_HDMI_CAPTURE_SSP_MASK(quirk)	\
33 	(((quirk) << SOF_HDMI_CAPTURE_SSP_MASK_SHIFT) & SOF_HDMI_CAPTURE_SSP_MASK_MASK)
34 
35 /* HDMI playback */
36 #define SOF_HDMI_PLAYBACK_PRESENT		BIT(13)
37 #define SOF_NO_OF_HDMI_PLAYBACK_SHIFT		14
38 #define SOF_NO_OF_HDMI_PLAYBACK_MASK		(GENMASK(16, 14))
39 #define SOF_NO_OF_HDMI_PLAYBACK(quirk)	\
40 	(((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK)
41 
42 /* BT audio offload */
43 #define SOF_SSP_BT_OFFLOAD_PRESENT		BIT(17)
44 #define SOF_BT_OFFLOAD_SSP_SHIFT		18
45 #define SOF_BT_OFFLOAD_SSP_MASK			(GENMASK(20, 18))
46 #define SOF_BT_OFFLOAD_SSP(quirk)	\
47 	(((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK)
48 
49 /* Default: SSP2  */
50 static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2);
51 
52 static const struct dmi_system_id chromebook_platforms[] = {
53 	{
54 		.ident = "Google Chromebooks",
55 		.matches = {
56 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
57 		}
58 	},
59 	{},
60 };
61 
62 static int sof_card_late_probe(struct snd_soc_card *card)
63 {
64 	return sof_intel_board_card_late_probe(card);
65 }
66 
67 static struct snd_soc_card sof_ssp_amp_card = {
68 	.name         = "ssp_amp",
69 	.owner        = THIS_MODULE,
70 	.fully_routed = true,
71 	.late_probe = sof_card_late_probe,
72 };
73 
74 /* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */
75 #define HDMI_IN_BE_ID		0
76 #define SPK_BE_ID		2
77 #define DMIC01_BE_ID		3
78 #define DMIC16K_BE_ID		4
79 #define INTEL_HDMI_BE_ID	5
80 
81 static struct snd_soc_dai_link *
82 sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type,
83 			  int ssp_amp, int dmic_be_num, int hdmi_num,
84 			  bool idisp_codec)
85 {
86 	struct snd_soc_dai_link *links;
87 	int i;
88 	int id = 0;
89 	int ret;
90 	bool fixed_be = false;
91 	int be_id;
92 	unsigned long ssp_mask_hdmi_in;
93 
94 	links = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
95 					sizeof(struct snd_soc_dai_link), GFP_KERNEL);
96 	if (!links)
97 		return NULL;
98 
99 	/* HDMI-In SSP */
100 	ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >>
101 				SOF_HDMI_CAPTURE_SSP_MASK_SHIFT;
102 
103 	if (ssp_mask_hdmi_in) {
104 		int port = 0;
105 
106 		/* the topology supports HDMI-IN uses fixed BE ID for DAI links */
107 		fixed_be = true;
108 
109 		be_id = HDMI_IN_BE_ID;
110 		for_each_set_bit(port, &ssp_mask_hdmi_in, 32) {
111 			ret = sof_intel_board_set_hdmi_in_link(dev, &links[id],
112 							       be_id, port);
113 			if (ret)
114 				return NULL;
115 
116 			id++;
117 			be_id++;
118 		}
119 	}
120 
121 	/* codec SSP */
122 	if (amp_type != CODEC_NONE) {
123 		be_id = fixed_be ? SPK_BE_ID : id;
124 		ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], be_id,
125 						       amp_type, ssp_amp);
126 		if (ret)
127 			return NULL;
128 
129 		/* codec-specific fields */
130 		switch (amp_type) {
131 		case CODEC_CS35L41:
132 			cs35l41_set_dai_link(&links[id]);
133 			break;
134 		case CODEC_RT1308:
135 			sof_rt1308_dai_link(&links[id]);
136 			break;
137 		default:
138 			dev_err(dev, "invalid amp type %d\n", amp_type);
139 			return NULL;
140 		}
141 
142 		id++;
143 	}
144 
145 	/* dmic */
146 	if (dmic_be_num > 0) {
147 		/* at least we have dmic01 */
148 		be_id = fixed_be ? DMIC01_BE_ID : id;
149 		ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id,
150 						    SOF_DMIC_01);
151 		if (ret)
152 			return NULL;
153 
154 		id++;
155 	}
156 
157 	if (dmic_be_num > 1) {
158 		/* set up 2 BE links at most */
159 		be_id = fixed_be ? DMIC16K_BE_ID : id;
160 		ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id,
161 						    SOF_DMIC_16K);
162 		if (ret)
163 			return NULL;
164 
165 		id++;
166 	}
167 
168 	/* HDMI playback */
169 	for (i = 1; i <= hdmi_num; i++) {
170 		be_id = fixed_be ? (INTEL_HDMI_BE_ID + i - 1) : id;
171 		ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], be_id,
172 							  i, idisp_codec);
173 		if (ret)
174 			return NULL;
175 
176 		id++;
177 	}
178 
179 	/* BT audio offload */
180 	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
181 		int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
182 				SOF_BT_OFFLOAD_SSP_SHIFT;
183 
184 		ret = sof_intel_board_set_bt_link(dev, &links[id], id, port);
185 		if (ret)
186 			return NULL;
187 
188 		id++;
189 	}
190 
191 	return links;
192 }
193 
194 static int sof_ssp_amp_probe(struct platform_device *pdev)
195 {
196 	struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
197 	struct snd_soc_dai_link *dai_links;
198 	struct sof_card_private *ctx;
199 	int ret;
200 
201 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
202 	if (!ctx)
203 		return -ENOMEM;
204 
205 	if (pdev->id_entry && pdev->id_entry->driver_data)
206 		sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data;
207 
208 	ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev);
209 
210 	if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0)
211 		ctx->dmic_be_num = 2;
212 	else
213 		ctx->dmic_be_num = 0;
214 
215 	/* port number/mask of peripherals attached to ssp interface */
216 	ctx->ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >>
217 			SOF_HDMI_CAPTURE_SSP_MASK_SHIFT;
218 
219 	ctx->ssp_bt = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
220 			SOF_BT_OFFLOAD_SSP_SHIFT;
221 
222 	ctx->ssp_amp = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK;
223 
224 	/* set number of dai links */
225 	sof_ssp_amp_card.num_links = ctx->dmic_be_num;
226 
227 	if (ctx->amp_type != CODEC_NONE)
228 		sof_ssp_amp_card.num_links++;
229 
230 	if (ctx->ssp_mask_hdmi_in)
231 		sof_ssp_amp_card.num_links += hweight32(ctx->ssp_mask_hdmi_in);
232 
233 	if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
234 		ctx->hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >>
235 				SOF_NO_OF_HDMI_PLAYBACK_SHIFT;
236 		/* default number of HDMI DAI's */
237 		if (!ctx->hdmi_num)
238 			ctx->hdmi_num = 3;
239 
240 		if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
241 			ctx->hdmi.idisp_codec = true;
242 
243 		sof_ssp_amp_card.num_links += ctx->hdmi_num;
244 	} else {
245 		ctx->hdmi_num = 0;
246 	}
247 
248 	if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
249 		ctx->bt_offload_present = true;
250 		sof_ssp_amp_card.num_links++;
251 	}
252 
253 	dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type,
254 					      ctx->ssp_amp, ctx->dmic_be_num,
255 					      ctx->hdmi_num,
256 					      ctx->hdmi.idisp_codec);
257 	if (!dai_links)
258 		return -ENOMEM;
259 
260 	sof_ssp_amp_card.dai_link = dai_links;
261 
262 	/* update codec_conf */
263 	switch (ctx->amp_type) {
264 	case CODEC_CS35L41:
265 		cs35l41_set_codec_conf(&sof_ssp_amp_card);
266 		break;
267 	case CODEC_NONE:
268 	case CODEC_RT1308:
269 		/* no codec conf required */
270 		break;
271 	default:
272 		dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
273 		return -EINVAL;
274 	}
275 
276 	sof_ssp_amp_card.dev = &pdev->dev;
277 
278 	/* set platform name for each dailink */
279 	ret = snd_soc_fixup_dai_links_platform_name(&sof_ssp_amp_card,
280 						    mach->mach_params.platform);
281 	if (ret)
282 		return ret;
283 
284 	snd_soc_card_set_drvdata(&sof_ssp_amp_card, ctx);
285 
286 	return devm_snd_soc_register_card(&pdev->dev, &sof_ssp_amp_card);
287 }
288 
289 static const struct platform_device_id board_ids[] = {
290 	{
291 		.name = "sof_ssp_amp",
292 	},
293 	{
294 		.name = "tgl_rt1308_hdmi_ssp",
295 		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) |
296 					SOF_HDMI_CAPTURE_SSP_MASK(0x22)),
297 					/* SSP 1 and SSP 5 are used for HDMI IN */
298 	},
299 	{
300 		.name = "adl_cs35l41",
301 		.driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) |
302 					SOF_NO_OF_HDMI_PLAYBACK(4) |
303 					SOF_HDMI_PLAYBACK_PRESENT |
304 					SOF_BT_OFFLOAD_SSP(2) |
305 					SOF_SSP_BT_OFFLOAD_PRESENT),
306 	},
307 	{
308 		.name = "adl_lt6911_hdmi_ssp",
309 		.driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) |
310 					/* SSP 0 and SSP 2 are used for HDMI IN */
311 					SOF_NO_OF_HDMI_PLAYBACK(3) |
312 					SOF_HDMI_PLAYBACK_PRESENT),
313 	},
314 	{
315 		.name = "rpl_lt6911_hdmi_ssp",
316 		.driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) |
317 					/* SSP 0 and SSP 2 are used for HDMI IN */
318 					SOF_NO_OF_HDMI_PLAYBACK(3) |
319 					SOF_HDMI_PLAYBACK_PRESENT),
320 	},
321 	{
322 		.name = "mtl_lt6911_hdmi_ssp",
323 		.driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) |
324 				/* SSP 0 and SSP 2 are used for HDMI IN */
325 				SOF_NO_OF_HDMI_PLAYBACK(3) |
326 				SOF_HDMI_PLAYBACK_PRESENT),
327 	},
328 	{ }
329 };
330 MODULE_DEVICE_TABLE(platform, board_ids);
331 
332 static struct platform_driver sof_ssp_amp_driver = {
333 	.probe          = sof_ssp_amp_probe,
334 	.driver = {
335 		.name   = "sof_ssp_amp",
336 		.pm = &snd_soc_pm_ops,
337 	},
338 	.id_table = board_ids,
339 };
340 module_platform_driver(sof_ssp_amp_driver);
341 
342 MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver");
343 MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>");
344 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
345 MODULE_LICENSE("GPL");
346 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
347 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON);
348 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON);
349 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);
350