xref: /linux/sound/soc/intel/boards/sof_cs42l42.c (revision b8e85e6f3a09fc56b0ff574887798962ef8a8f80)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright(c) 2021 Intel Corporation.
3 
4 /*
5  * Intel SOF Machine Driver with Cirrus Logic CS42L42 Codec
6  * and speaker codec MAX98357A
7  */
8 #include <linux/i2c.h>
9 #include <linux/input.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/regulator/consumer.h>
13 #include <linux/dmi.h>
14 #include <sound/core.h>
15 #include <sound/jack.h>
16 #include <sound/pcm.h>
17 #include <sound/pcm_params.h>
18 #include <sound/soc.h>
19 #include <sound/sof.h>
20 #include <sound/soc-acpi.h>
21 #include <dt-bindings/sound/cs42l42.h>
22 #include "../common/soc-intel-quirks.h"
23 #include "sof_board_helpers.h"
24 #include "sof_maxim_common.h"
25 #include "sof_ssp_common.h"
26 
27 #define SOF_CS42L42_SSP_CODEC(quirk)		((quirk) & GENMASK(2, 0))
28 #define SOF_CS42L42_SSP_CODEC_MASK		(GENMASK(2, 0))
29 #define SOF_CS42L42_SSP_AMP_SHIFT		4
30 #define SOF_CS42L42_SSP_AMP_MASK		(GENMASK(6, 4))
31 #define SOF_CS42L42_SSP_AMP(quirk)	\
32 	(((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK)
33 #define SOF_CS42L42_NUM_HDMIDEV_SHIFT		7
34 #define SOF_CS42L42_NUM_HDMIDEV_MASK		(GENMASK(9, 7))
35 #define SOF_CS42L42_NUM_HDMIDEV(quirk)	\
36 	(((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK)
37 #define SOF_CS42L42_DAILINK_SHIFT		10
38 #define SOF_CS42L42_DAILINK_MASK		(GENMASK(24, 10))
39 #define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \
40 	((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK)
41 #define SOF_BT_OFFLOAD_PRESENT			BIT(25)
42 #define SOF_CS42L42_SSP_BT_SHIFT		26
43 #define SOF_CS42L42_SSP_BT_MASK			(GENMASK(28, 26))
44 #define SOF_CS42L42_SSP_BT(quirk)	\
45 	(((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK)
46 
47 enum {
48 	LINK_NONE = 0,
49 	LINK_HP = 1,
50 	LINK_SPK = 2,
51 	LINK_DMIC = 3,
52 	LINK_HDMI = 4,
53 	LINK_BT = 5,
54 };
55 
56 static struct snd_soc_jack_pin jack_pins[] = {
57 	{
58 		.pin    = "Headphone Jack",
59 		.mask   = SND_JACK_HEADPHONE,
60 	},
61 	{
62 		.pin    = "Headset Mic",
63 		.mask   = SND_JACK_MICROPHONE,
64 	},
65 };
66 
67 /* Default: SSP2 */
68 static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2);
69 
70 static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
71 {
72 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
73 	struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
74 	struct snd_soc_jack *jack = &ctx->headset_jack;
75 	int ret;
76 
77 	/*
78 	 * Headset buttons map to the google Reference headset.
79 	 * These can be configured by userspace.
80 	 */
81 	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
82 					 SND_JACK_HEADSET | SND_JACK_BTN_0 |
83 					 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
84 					 SND_JACK_BTN_3,
85 					 jack,
86 					 jack_pins,
87 					 ARRAY_SIZE(jack_pins));
88 	if (ret) {
89 		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
90 		return ret;
91 	}
92 
93 	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
94 	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
95 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
96 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
97 
98 	ret = snd_soc_component_set_jack(component, jack, NULL);
99 	if (ret) {
100 		dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
101 		return ret;
102 	}
103 
104 	return ret;
105 };
106 
107 static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd)
108 {
109 	struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
110 
111 	snd_soc_component_set_jack(component, NULL, NULL);
112 }
113 
114 static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream,
115 				 struct snd_pcm_hw_params *params)
116 {
117 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
118 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
119 	int clk_freq, ret;
120 
121 	clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
122 
123 	if (clk_freq <= 0) {
124 		dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq);
125 		return -EINVAL;
126 	}
127 
128 	/* Configure sysclk for codec */
129 	ret = snd_soc_dai_set_sysclk(codec_dai, 0,
130 				     clk_freq, SND_SOC_CLOCK_IN);
131 	if (ret < 0)
132 		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
133 
134 	return ret;
135 }
136 
137 static const struct snd_soc_ops sof_cs42l42_ops = {
138 	.hw_params = sof_cs42l42_hw_params,
139 };
140 
141 static int sof_card_late_probe(struct snd_soc_card *card)
142 {
143 	return sof_intel_board_card_late_probe(card);
144 }
145 
146 static const struct snd_kcontrol_new sof_controls[] = {
147 	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
148 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
149 };
150 
151 static const struct snd_soc_dapm_widget sof_widgets[] = {
152 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
153 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
154 };
155 
156 static const struct snd_soc_dapm_route sof_map[] = {
157 	/* HP jack connectors - unknown if we have jack detection */
158 	{"Headphone Jack", NULL, "HP"},
159 
160 	/* other jacks */
161 	{"HS", NULL, "Headset Mic"},
162 };
163 
164 /* sof audio machine driver for cs42l42 codec */
165 static struct snd_soc_card sof_audio_card_cs42l42 = {
166 	.name = "cs42l42", /* the sof- prefix is added by the core */
167 	.owner = THIS_MODULE,
168 	.controls = sof_controls,
169 	.num_controls = ARRAY_SIZE(sof_controls),
170 	.dapm_widgets = sof_widgets,
171 	.num_dapm_widgets = ARRAY_SIZE(sof_widgets),
172 	.dapm_routes = sof_map,
173 	.num_dapm_routes = ARRAY_SIZE(sof_map),
174 	.fully_routed = true,
175 	.late_probe = sof_card_late_probe,
176 };
177 
178 static struct snd_soc_dai_link_component cs42l42_component[] = {
179 	{
180 		.name = "i2c-10134242:00",
181 		.dai_name = "cs42l42",
182 	}
183 };
184 
185 static struct snd_soc_dai_link *
186 sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type,
187 			  int ssp_codec, int ssp_amp, int ssp_bt,
188 			  int dmic_be_num, int hdmi_num, bool idisp_codec)
189 {
190 	struct snd_soc_dai_link *links;
191 	int ret;
192 	int id = 0;
193 	int link_seq;
194 	int i;
195 
196 	links = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links,
197 			    sizeof(struct snd_soc_dai_link), GFP_KERNEL);
198 	if (!links)
199 		goto devm_err;
200 
201 	link_seq = (sof_cs42l42_quirk & SOF_CS42L42_DAILINK_MASK) >> SOF_CS42L42_DAILINK_SHIFT;
202 
203 	while (link_seq) {
204 		int link_type = link_seq & 0x07;
205 
206 		switch (link_type) {
207 		case LINK_HP:
208 			ret = sof_intel_board_set_codec_link(dev, &links[id], id,
209 							     CODEC_CS42L42,
210 							     ssp_codec);
211 			if (ret) {
212 				dev_err(dev, "fail to create hp codec dai links, ret %d\n",
213 					ret);
214 				goto devm_err;
215 			}
216 
217 			/* codec-specific fields */
218 			links[id].codecs = cs42l42_component;
219 			links[id].num_codecs = ARRAY_SIZE(cs42l42_component);
220 			links[id].init = sof_cs42l42_init;
221 			links[id].exit = sof_cs42l42_exit;
222 			links[id].ops = &sof_cs42l42_ops;
223 
224 			id++;
225 			break;
226 		case LINK_SPK:
227 			if (amp_type != CODEC_NONE) {
228 				ret = sof_intel_board_set_ssp_amp_link(dev,
229 								       &links[id],
230 								       id,
231 								       amp_type,
232 								       ssp_amp);
233 				if (ret) {
234 					dev_err(dev, "fail to create spk amp dai links, ret %d\n",
235 						ret);
236 					goto devm_err;
237 				}
238 
239 				/* codec-specific fields */
240 				switch (amp_type) {
241 				case CODEC_MAX98357A:
242 					max_98357a_dai_link(&links[id]);
243 					break;
244 				case CODEC_MAX98360A:
245 					max_98360a_dai_link(&links[id]);
246 					break;
247 				default:
248 					dev_err(dev, "invalid amp type %d\n",
249 						amp_type);
250 					goto devm_err;
251 				}
252 
253 				id++;
254 			}
255 			break;
256 		case LINK_DMIC:
257 			if (dmic_be_num > 0) {
258 				/* at least we have dmic01 */
259 				ret = sof_intel_board_set_dmic_link(dev,
260 								    &links[id],
261 								    id,
262 								    SOF_DMIC_01);
263 				if (ret) {
264 					dev_err(dev, "fail to create dmic01 link, ret %d\n",
265 						ret);
266 					goto devm_err;
267 				}
268 
269 				id++;
270 			}
271 
272 			if (dmic_be_num > 1) {
273 				/* set up 2 BE links at most */
274 				ret = sof_intel_board_set_dmic_link(dev,
275 								    &links[id],
276 								    id,
277 								    SOF_DMIC_16K);
278 				if (ret) {
279 					dev_err(dev, "fail to create dmic16k link, ret %d\n",
280 						ret);
281 					goto devm_err;
282 				}
283 
284 				id++;
285 			}
286 			break;
287 		case LINK_HDMI:
288 			for (i = 1; i <= hdmi_num; i++) {
289 				ret = sof_intel_board_set_intel_hdmi_link(dev,
290 									  &links[id],
291 									  id, i,
292 									  idisp_codec);
293 				if (ret) {
294 					dev_err(dev, "fail to create hdmi link, ret %d\n",
295 						ret);
296 					goto devm_err;
297 				}
298 
299 				id++;
300 			}
301 			break;
302 		case LINK_BT:
303 			if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) {
304 				ret = sof_intel_board_set_bt_link(dev,
305 								  &links[id], id,
306 								  ssp_bt);
307 				if (ret) {
308 					dev_err(dev, "fail to create bt offload dai links, ret %d\n",
309 						ret);
310 					goto devm_err;
311 				}
312 
313 				id++;
314 			}
315 			break;
316 		case LINK_NONE:
317 			/* caught here if it's not used as terminator in macro */
318 		default:
319 			dev_err(dev, "invalid link type %d\n", link_type);
320 			goto devm_err;
321 		}
322 
323 		link_seq >>= 3;
324 	}
325 
326 	return links;
327 devm_err:
328 	return NULL;
329 }
330 
331 static int sof_audio_probe(struct platform_device *pdev)
332 {
333 	struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
334 	struct snd_soc_dai_link *dai_links;
335 	struct sof_card_private *ctx;
336 	int ret;
337 
338 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
339 	if (!ctx)
340 		return -ENOMEM;
341 
342 	if (pdev->id_entry && pdev->id_entry->driver_data)
343 		sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data;
344 
345 	ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev);
346 	ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev);
347 
348 	if (soc_intel_is_glk()) {
349 		ctx->dmic_be_num = 1;
350 		ctx->hdmi_num = 3;
351 	} else {
352 		ctx->dmic_be_num = 2;
353 		ctx->hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >>
354 			 SOF_CS42L42_NUM_HDMIDEV_SHIFT;
355 		/* default number of HDMI DAI's */
356 		if (!ctx->hdmi_num)
357 			ctx->hdmi_num = 3;
358 	}
359 
360 	if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
361 		ctx->hdmi.idisp_codec = true;
362 
363 	dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
364 
365 	/* port number of peripherals attached to ssp interface */
366 	ctx->ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >>
367 			SOF_CS42L42_SSP_BT_SHIFT;
368 
369 	ctx->ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
370 			SOF_CS42L42_SSP_AMP_SHIFT;
371 
372 	ctx->ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK;
373 
374 	/* compute number of dai links */
375 	sof_audio_card_cs42l42.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num;
376 
377 	if (ctx->amp_type != CODEC_NONE)
378 		sof_audio_card_cs42l42.num_links++;
379 	if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) {
380 		ctx->bt_offload_present = true;
381 		sof_audio_card_cs42l42.num_links++;
382 	}
383 
384 	dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type,
385 					      ctx->ssp_codec, ctx->ssp_amp,
386 					      ctx->ssp_bt, ctx->dmic_be_num,
387 					      ctx->hdmi_num,
388 					      ctx->hdmi.idisp_codec);
389 	if (!dai_links)
390 		return -ENOMEM;
391 
392 	sof_audio_card_cs42l42.dai_link = dai_links;
393 
394 	sof_audio_card_cs42l42.dev = &pdev->dev;
395 
396 	/* set platform name for each dailink */
397 	ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42,
398 						    mach->mach_params.platform);
399 	if (ret)
400 		return ret;
401 
402 	snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx);
403 
404 	return devm_snd_soc_register_card(&pdev->dev,
405 					  &sof_audio_card_cs42l42);
406 }
407 
408 static const struct platform_device_id board_ids[] = {
409 	{
410 		.name = "glk_cs4242_mx98357a",
411 		.driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) |
412 					SOF_CS42L42_SSP_AMP(1)) |
413 					SOF_CS42L42_DAILINK(LINK_SPK, LINK_HP, LINK_DMIC, LINK_HDMI, LINK_NONE),
414 	},
415 	{
416 		.name = "jsl_cs4242_mx98360a",
417 		.driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
418 					SOF_CS42L42_SSP_AMP(1)) |
419 					SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_NONE),
420 	},
421 	{
422 		.name = "adl_mx98360a_cs4242",
423 		.driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
424 				SOF_CS42L42_SSP_AMP(1) |
425 				SOF_CS42L42_NUM_HDMIDEV(4) |
426 				SOF_BT_OFFLOAD_PRESENT |
427 				SOF_CS42L42_SSP_BT(2) |
428 				SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_BT)),
429 	},
430 	{ }
431 };
432 MODULE_DEVICE_TABLE(platform, board_ids);
433 
434 static struct platform_driver sof_audio = {
435 	.probe = sof_audio_probe,
436 	.driver = {
437 		.name = "sof_cs42l42",
438 		.pm = &snd_soc_pm_ops,
439 	},
440 	.id_table = board_ids,
441 };
442 module_platform_driver(sof_audio)
443 
444 /* Module information */
445 MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42");
446 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
447 MODULE_LICENSE("GPL");
448 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
449 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
450 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);
451