xref: /linux/sound/soc/intel/boards/sof_cs42l42.c (revision bdd1a21b52557ea8f61d0a5dc2f77151b576eb70)
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/soc-acpi.h>
20 #include <dt-bindings/sound/cs42l42.h>
21 #include "../../codecs/hdac_hdmi.h"
22 #include "../common/soc-intel-quirks.h"
23 #include "hda_dsp_common.h"
24 #include "sof_maxim_common.h"
25 
26 #define NAME_SIZE 32
27 
28 #define SOF_CS42L42_SSP_CODEC(quirk)		((quirk) & GENMASK(2, 0))
29 #define SOF_CS42L42_SSP_CODEC_MASK		(GENMASK(2, 0))
30 #define SOF_SPEAKER_AMP_PRESENT			BIT(3)
31 #define SOF_CS42L42_SSP_AMP_SHIFT		4
32 #define SOF_CS42L42_SSP_AMP_MASK		(GENMASK(6, 4))
33 #define SOF_CS42L42_SSP_AMP(quirk)	\
34 	(((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK)
35 #define SOF_CS42L42_NUM_HDMIDEV_SHIFT		7
36 #define SOF_CS42L42_NUM_HDMIDEV_MASK		(GENMASK(9, 7))
37 #define SOF_CS42L42_NUM_HDMIDEV(quirk)	\
38 	(((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK)
39 #define SOF_MAX98357A_SPEAKER_AMP_PRESENT	BIT(10)
40 
41 /* Default: SSP2 */
42 static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2);
43 
44 struct sof_hdmi_pcm {
45 	struct list_head head;
46 	struct snd_soc_dai *codec_dai;
47 	struct snd_soc_jack hdmi_jack;
48 	int device;
49 };
50 
51 struct sof_card_private {
52 	struct snd_soc_jack headset_jack;
53 	struct list_head hdmi_pcm_list;
54 	bool common_hdmi_codec_drv;
55 };
56 
57 static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
58 {
59 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
60 	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
61 	struct sof_hdmi_pcm *pcm;
62 
63 	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
64 	if (!pcm)
65 		return -ENOMEM;
66 
67 	/* dai_link id is 1:1 mapped to the PCM device */
68 	pcm->device = rtd->dai_link->id;
69 	pcm->codec_dai = dai;
70 
71 	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
72 
73 	return 0;
74 }
75 
76 static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
77 {
78 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
79 	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
80 	struct snd_soc_jack *jack = &ctx->headset_jack;
81 	int ret;
82 
83 	/*
84 	 * Headset buttons map to the google Reference headset.
85 	 * These can be configured by userspace.
86 	 */
87 	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
88 				    SND_JACK_HEADSET | SND_JACK_BTN_0 |
89 				    SND_JACK_BTN_1 | SND_JACK_BTN_2 |
90 				    SND_JACK_BTN_3,
91 				    jack, NULL, 0);
92 	if (ret) {
93 		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
94 		return ret;
95 	}
96 
97 	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
98 	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
99 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
100 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
101 
102 	ret = snd_soc_component_set_jack(component, jack, NULL);
103 	if (ret) {
104 		dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
105 		return ret;
106 	}
107 
108 	return ret;
109 };
110 
111 static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd)
112 {
113 	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
114 
115 	snd_soc_component_set_jack(component, NULL, NULL);
116 }
117 
118 static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream,
119 				 struct snd_pcm_hw_params *params)
120 {
121 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
122 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
123 	int clk_freq, ret;
124 
125 	clk_freq = 3072000; /* BCLK freq */
126 
127 	/* Configure sysclk for codec */
128 	ret = snd_soc_dai_set_sysclk(codec_dai, 0,
129 				     clk_freq, SND_SOC_CLOCK_IN);
130 	if (ret < 0)
131 		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
132 
133 	return ret;
134 }
135 
136 static const struct snd_soc_ops sof_cs42l42_ops = {
137 	.hw_params = sof_cs42l42_hw_params,
138 };
139 
140 static struct snd_soc_dai_link_component platform_component[] = {
141 	{
142 		/* name might be overridden during probe */
143 		.name = "0000:00:1f.3"
144 	}
145 };
146 
147 static int sof_card_late_probe(struct snd_soc_card *card)
148 {
149 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
150 	struct snd_soc_component *component = NULL;
151 	char jack_name[NAME_SIZE];
152 	struct sof_hdmi_pcm *pcm;
153 	int err;
154 
155 	if (list_empty(&ctx->hdmi_pcm_list))
156 		return -EINVAL;
157 
158 	if (ctx->common_hdmi_codec_drv) {
159 		pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
160 				       head);
161 		component = pcm->codec_dai->component;
162 		return hda_dsp_hdmi_build_controls(card, component);
163 	}
164 
165 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
166 		component = pcm->codec_dai->component;
167 		snprintf(jack_name, sizeof(jack_name),
168 			 "HDMI/DP, pcm=%d Jack", pcm->device);
169 		err = snd_soc_card_jack_new(card, jack_name,
170 					    SND_JACK_AVOUT, &pcm->hdmi_jack,
171 					    NULL, 0);
172 
173 		if (err)
174 			return err;
175 
176 		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
177 					  &pcm->hdmi_jack);
178 		if (err < 0)
179 			return err;
180 	}
181 
182 	return hdac_hdmi_jack_port_init(component, &card->dapm);
183 }
184 
185 static const struct snd_kcontrol_new sof_controls[] = {
186 	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
187 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
188 };
189 
190 static const struct snd_soc_dapm_widget sof_widgets[] = {
191 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
192 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
193 };
194 
195 static const struct snd_soc_dapm_widget dmic_widgets[] = {
196 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
197 };
198 
199 static const struct snd_soc_dapm_route sof_map[] = {
200 	/* HP jack connectors - unknown if we have jack detection */
201 	{"Headphone Jack", NULL, "HP"},
202 
203 	/* other jacks */
204 	{"HS", NULL, "Headset Mic"},
205 };
206 
207 static const struct snd_soc_dapm_route dmic_map[] = {
208 	/* digital mics */
209 	{"DMic", NULL, "SoC DMIC"},
210 };
211 
212 static int dmic_init(struct snd_soc_pcm_runtime *rtd)
213 {
214 	struct snd_soc_card *card = rtd->card;
215 	int ret;
216 
217 	ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
218 					ARRAY_SIZE(dmic_widgets));
219 	if (ret) {
220 		dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
221 		/* Don't need to add routes if widget addition failed */
222 		return ret;
223 	}
224 
225 	ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
226 				      ARRAY_SIZE(dmic_map));
227 
228 	if (ret)
229 		dev_err(card->dev, "DMic map addition failed: %d\n", ret);
230 
231 	return ret;
232 }
233 
234 /* sof audio machine driver for cs42l42 codec */
235 static struct snd_soc_card sof_audio_card_cs42l42 = {
236 	.name = "cs42l42", /* the sof- prefix is added by the core */
237 	.owner = THIS_MODULE,
238 	.controls = sof_controls,
239 	.num_controls = ARRAY_SIZE(sof_controls),
240 	.dapm_widgets = sof_widgets,
241 	.num_dapm_widgets = ARRAY_SIZE(sof_widgets),
242 	.dapm_routes = sof_map,
243 	.num_dapm_routes = ARRAY_SIZE(sof_map),
244 	.fully_routed = true,
245 	.late_probe = sof_card_late_probe,
246 };
247 
248 static struct snd_soc_dai_link_component cs42l42_component[] = {
249 	{
250 		.name = "i2c-10134242:00",
251 		.dai_name = "cs42l42",
252 	}
253 };
254 
255 static struct snd_soc_dai_link_component dmic_component[] = {
256 	{
257 		.name = "dmic-codec",
258 		.dai_name = "dmic-hifi",
259 	}
260 };
261 
262 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
263 							  int ssp_codec,
264 							  int ssp_amp,
265 							  int dmic_be_num,
266 							  int hdmi_num)
267 {
268 	struct snd_soc_dai_link_component *idisp_components;
269 	struct snd_soc_dai_link_component *cpus;
270 	struct snd_soc_dai_link *links;
271 	int i, id = 0;
272 
273 	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
274 			     sof_audio_card_cs42l42.num_links, GFP_KERNEL);
275 	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
276 			     sof_audio_card_cs42l42.num_links, GFP_KERNEL);
277 	if (!links || !cpus)
278 		goto devm_err;
279 
280 	/* speaker amp */
281 	if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT) {
282 		links[id].name = devm_kasprintf(dev, GFP_KERNEL,
283 						"SSP%d-Codec", ssp_amp);
284 		if (!links[id].name)
285 			goto devm_err;
286 
287 		links[id].id = id;
288 
289 		if (sof_cs42l42_quirk & SOF_MAX98357A_SPEAKER_AMP_PRESENT) {
290 			max_98357a_dai_link(&links[id]);
291 		} else {
292 			dev_err(dev, "no amp defined\n");
293 			goto devm_err;
294 		}
295 
296 		links[id].platforms = platform_component;
297 		links[id].num_platforms = ARRAY_SIZE(platform_component);
298 		links[id].dpcm_playback = 1;
299 		links[id].no_pcm = 1;
300 		links[id].cpus = &cpus[id];
301 		links[id].num_cpus = 1;
302 
303 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
304 							  "SSP%d Pin",
305 							  ssp_amp);
306 		if (!links[id].cpus->dai_name)
307 			goto devm_err;
308 
309 		id++;
310 	}
311 
312 	/* codec SSP */
313 	links[id].name = devm_kasprintf(dev, GFP_KERNEL,
314 					"SSP%d-Codec", ssp_codec);
315 	if (!links[id].name)
316 		goto devm_err;
317 
318 	links[id].id = id;
319 	links[id].codecs = cs42l42_component;
320 	links[id].num_codecs = ARRAY_SIZE(cs42l42_component);
321 	links[id].platforms = platform_component;
322 	links[id].num_platforms = ARRAY_SIZE(platform_component);
323 	links[id].init = sof_cs42l42_init;
324 	links[id].exit = sof_cs42l42_exit;
325 	links[id].ops = &sof_cs42l42_ops;
326 	links[id].dpcm_playback = 1;
327 	links[id].dpcm_capture = 1;
328 	links[id].no_pcm = 1;
329 	links[id].cpus = &cpus[id];
330 	links[id].num_cpus = 1;
331 
332 	links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
333 						  "SSP%d Pin",
334 						  ssp_codec);
335 	if (!links[id].cpus->dai_name)
336 		goto devm_err;
337 
338 	id++;
339 
340 	/* dmic */
341 	if (dmic_be_num > 0) {
342 		/* at least we have dmic01 */
343 		links[id].name = "dmic01";
344 		links[id].cpus = &cpus[id];
345 		links[id].cpus->dai_name = "DMIC01 Pin";
346 		links[id].init = dmic_init;
347 		if (dmic_be_num > 1) {
348 			/* set up 2 BE links at most */
349 			links[id + 1].name = "dmic16k";
350 			links[id + 1].cpus = &cpus[id + 1];
351 			links[id + 1].cpus->dai_name = "DMIC16k Pin";
352 			dmic_be_num = 2;
353 		}
354 	}
355 
356 	for (i = 0; i < dmic_be_num; i++) {
357 		links[id].id = id;
358 		links[id].num_cpus = 1;
359 		links[id].codecs = dmic_component;
360 		links[id].num_codecs = ARRAY_SIZE(dmic_component);
361 		links[id].platforms = platform_component;
362 		links[id].num_platforms = ARRAY_SIZE(platform_component);
363 		links[id].ignore_suspend = 1;
364 		links[id].dpcm_capture = 1;
365 		links[id].no_pcm = 1;
366 		id++;
367 	}
368 
369 	/* HDMI */
370 	if (hdmi_num > 0) {
371 		idisp_components = devm_kzalloc(dev,
372 						sizeof(struct snd_soc_dai_link_component) *
373 						hdmi_num, GFP_KERNEL);
374 		if (!idisp_components)
375 			goto devm_err;
376 	}
377 	for (i = 1; i <= hdmi_num; i++) {
378 		links[id].name = devm_kasprintf(dev, GFP_KERNEL,
379 						"iDisp%d", i);
380 		if (!links[id].name)
381 			goto devm_err;
382 
383 		links[id].id = id;
384 		links[id].cpus = &cpus[id];
385 		links[id].num_cpus = 1;
386 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
387 							  "iDisp%d Pin", i);
388 		if (!links[id].cpus->dai_name)
389 			goto devm_err;
390 
391 		idisp_components[i - 1].name = "ehdaudio0D2";
392 		idisp_components[i - 1].dai_name = devm_kasprintf(dev,
393 								  GFP_KERNEL,
394 								  "intel-hdmi-hifi%d",
395 								  i);
396 		if (!idisp_components[i - 1].dai_name)
397 			goto devm_err;
398 
399 		links[id].codecs = &idisp_components[i - 1];
400 		links[id].num_codecs = 1;
401 		links[id].platforms = platform_component;
402 		links[id].num_platforms = ARRAY_SIZE(platform_component);
403 		links[id].init = sof_hdmi_init;
404 		links[id].dpcm_playback = 1;
405 		links[id].no_pcm = 1;
406 		id++;
407 	}
408 
409 	return links;
410 devm_err:
411 	return NULL;
412 }
413 
414 static int sof_audio_probe(struct platform_device *pdev)
415 {
416 	struct snd_soc_dai_link *dai_links;
417 	struct snd_soc_acpi_mach *mach;
418 	struct sof_card_private *ctx;
419 	int dmic_be_num, hdmi_num;
420 	int ret, ssp_amp, ssp_codec;
421 
422 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
423 	if (!ctx)
424 		return -ENOMEM;
425 
426 	if (pdev->id_entry && pdev->id_entry->driver_data)
427 		sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data;
428 
429 	mach = pdev->dev.platform_data;
430 
431 	if (soc_intel_is_glk()) {
432 		dmic_be_num = 1;
433 		hdmi_num = 3;
434 	} else {
435 		dmic_be_num = 2;
436 		hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >>
437 			 SOF_CS42L42_NUM_HDMIDEV_SHIFT;
438 		/* default number of HDMI DAI's */
439 		if (!hdmi_num)
440 			hdmi_num = 3;
441 	}
442 
443 	dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
444 
445 	ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
446 			SOF_CS42L42_SSP_AMP_SHIFT;
447 
448 	ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK;
449 
450 	/* compute number of dai links */
451 	sof_audio_card_cs42l42.num_links = 1 + dmic_be_num + hdmi_num;
452 
453 	if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT)
454 		sof_audio_card_cs42l42.num_links++;
455 
456 	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
457 					      dmic_be_num, hdmi_num);
458 	if (!dai_links)
459 		return -ENOMEM;
460 
461 	sof_audio_card_cs42l42.dai_link = dai_links;
462 
463 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
464 
465 	sof_audio_card_cs42l42.dev = &pdev->dev;
466 
467 	/* set platform name for each dailink */
468 	ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42,
469 						    mach->mach_params.platform);
470 	if (ret)
471 		return ret;
472 
473 	ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
474 
475 	snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx);
476 
477 	return devm_snd_soc_register_card(&pdev->dev,
478 					  &sof_audio_card_cs42l42);
479 }
480 
481 static const struct platform_device_id board_ids[] = {
482 	{
483 		.name = "glk_cs4242_mx98357a",
484 		.driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) |
485 					SOF_SPEAKER_AMP_PRESENT |
486 					SOF_MAX98357A_SPEAKER_AMP_PRESENT |
487 					SOF_CS42L42_SSP_AMP(1)),
488 	},
489 	{ }
490 };
491 MODULE_DEVICE_TABLE(platform, board_ids);
492 
493 static struct platform_driver sof_audio = {
494 	.probe = sof_audio_probe,
495 	.driver = {
496 		.name = "sof_cs42l42",
497 		.pm = &snd_soc_pm_ops,
498 	},
499 	.id_table = board_ids,
500 };
501 module_platform_driver(sof_audio)
502 
503 /* Module information */
504 MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42");
505 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
506 MODULE_LICENSE("GPL");
507 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
508 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
509