xref: /linux/sound/soc/intel/boards/sof_maxim_common.c (revision 9c2f5b6eb8b7da05e13cde60c32e0a8b1f5873b0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Copyright(c) 2020 Intel Corporation
4 #include <linux/module.h>
5 #include <linux/string.h>
6 #include <sound/pcm.h>
7 #include <sound/pcm_params.h>
8 #include <sound/soc.h>
9 #include <sound/soc-acpi.h>
10 #include <sound/soc-dai.h>
11 #include <sound/soc-dapm.h>
12 #include <uapi/sound/asound.h>
13 #include "../common/soc-intel-quirks.h"
14 #include "sof_maxim_common.h"
15 
16 /*
17  * Common structures and functions
18  */
19 static const struct snd_kcontrol_new maxim_2spk_kcontrols[] = {
20 	SOC_DAPM_PIN_SWITCH("Left Spk"),
21 	SOC_DAPM_PIN_SWITCH("Right Spk"),
22 
23 };
24 
25 static const struct snd_soc_dapm_widget maxim_2spk_widgets[] = {
26 	SND_SOC_DAPM_SPK("Left Spk", NULL),
27 	SND_SOC_DAPM_SPK("Right Spk", NULL),
28 };
29 
30 /* helper function to get the number of specific codec */
31 static unsigned int get_num_codecs(const char *hid)
32 {
33 	struct acpi_device *adev;
34 	unsigned int dev_num = 0;
35 
36 	for_each_acpi_dev_match(adev, hid, NULL, -1)
37 		dev_num++;
38 
39 	return dev_num;
40 }
41 
42 #define MAX_98373_PIN_NAME 16
43 
44 const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
45 	/* speaker */
46 	{ "Left Spk", NULL, "Left BE_OUT" },
47 	{ "Right Spk", NULL, "Right BE_OUT" },
48 };
49 EXPORT_SYMBOL_NS(max_98373_dapm_routes, SND_SOC_INTEL_SOF_MAXIM_COMMON);
50 
51 static struct snd_soc_codec_conf max_98373_codec_conf[] = {
52 	{
53 		.dlc = COMP_CODEC_CONF(MAX_98373_DEV0_NAME),
54 		.name_prefix = "Right",
55 	},
56 	{
57 		.dlc = COMP_CODEC_CONF(MAX_98373_DEV1_NAME),
58 		.name_prefix = "Left",
59 	},
60 };
61 
62 struct snd_soc_dai_link_component max_98373_components[] = {
63 	{  /* For Right */
64 		.name = MAX_98373_DEV0_NAME,
65 		.dai_name = MAX_98373_CODEC_DAI,
66 	},
67 	{  /* For Left */
68 		.name = MAX_98373_DEV1_NAME,
69 		.dai_name = MAX_98373_CODEC_DAI,
70 	},
71 };
72 EXPORT_SYMBOL_NS(max_98373_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
73 
74 static int max_98373_hw_params(struct snd_pcm_substream *substream,
75 			       struct snd_pcm_hw_params *params)
76 {
77 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
78 	struct snd_soc_dai *codec_dai;
79 	int ret = 0;
80 	int j;
81 
82 	for_each_rtd_codec_dais(rtd, j, codec_dai) {
83 		if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) {
84 			/* DEV0 tdm slot configuration */
85 			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32);
86 		} else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) {
87 			/* DEV1 tdm slot configuration */
88 			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32);
89 		}
90 		if (ret < 0) {
91 			dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
92 				ret);
93 			return ret;
94 		}
95 	}
96 	return 0;
97 }
98 
99 int max_98373_trigger(struct snd_pcm_substream *substream, int cmd)
100 {
101 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
102 	struct snd_soc_dai *codec_dai;
103 	struct snd_soc_dai *cpu_dai;
104 	int j;
105 	int ret = 0;
106 
107 	/* set spk pin by playback only */
108 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
109 		return 0;
110 
111 	cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
112 	for_each_rtd_codec_dais(rtd, j, codec_dai) {
113 		struct snd_soc_dapm_context *dapm =
114 				snd_soc_component_get_dapm(cpu_dai->component);
115 		char pin_name[MAX_98373_PIN_NAME];
116 
117 		snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
118 			 codec_dai->component->name_prefix);
119 
120 		switch (cmd) {
121 		case SNDRV_PCM_TRIGGER_START:
122 		case SNDRV_PCM_TRIGGER_RESUME:
123 		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
124 			ret = snd_soc_dapm_enable_pin(dapm, pin_name);
125 			if (!ret)
126 				snd_soc_dapm_sync(dapm);
127 			break;
128 		case SNDRV_PCM_TRIGGER_STOP:
129 		case SNDRV_PCM_TRIGGER_SUSPEND:
130 		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
131 			ret = snd_soc_dapm_disable_pin(dapm, pin_name);
132 			if (!ret)
133 				snd_soc_dapm_sync(dapm);
134 			break;
135 		default:
136 			break;
137 		}
138 	}
139 
140 	return ret;
141 }
142 EXPORT_SYMBOL_NS(max_98373_trigger, SND_SOC_INTEL_SOF_MAXIM_COMMON);
143 
144 struct snd_soc_ops max_98373_ops = {
145 	.hw_params = max_98373_hw_params,
146 	.trigger = max_98373_trigger,
147 };
148 EXPORT_SYMBOL_NS(max_98373_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON);
149 
150 int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
151 {
152 	struct snd_soc_card *card = rtd->card;
153 	unsigned int num_codecs = get_num_codecs(MAX_98373_ACPI_HID);
154 	int ret;
155 
156 	switch (num_codecs) {
157 	case 2:
158 		ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets,
159 						ARRAY_SIZE(maxim_2spk_widgets));
160 		if (ret) {
161 			dev_err(rtd->dev, "fail to add max98373 widgets, ret %d\n",
162 				ret);
163 			return ret;
164 		}
165 
166 		ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols,
167 						ARRAY_SIZE(maxim_2spk_kcontrols));
168 		if (ret) {
169 			dev_err(rtd->dev, "fail to add max98373 kcontrols, ret %d\n",
170 				ret);
171 			return ret;
172 		}
173 
174 		ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes,
175 					      ARRAY_SIZE(max_98373_dapm_routes));
176 		if (ret) {
177 			dev_err(rtd->dev, "fail to add max98373 routes, ret %d\n",
178 				ret);
179 			return ret;
180 		}
181 		break;
182 	default:
183 		dev_err(rtd->dev, "max98373: invalid num_codecs %d\n", num_codecs);
184 		return -EINVAL;
185 	}
186 
187 	return ret;
188 }
189 EXPORT_SYMBOL_NS(max_98373_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON);
190 
191 void max_98373_set_codec_conf(struct snd_soc_card *card)
192 {
193 	card->codec_conf = max_98373_codec_conf;
194 	card->num_configs = ARRAY_SIZE(max_98373_codec_conf);
195 }
196 EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON);
197 
198 /*
199  * Maxim MAX98390
200  */
201 static const struct snd_soc_dapm_route max_98390_dapm_routes[] = {
202 	/* speaker */
203 	{ "Left Spk", NULL, "Left BE_OUT" },
204 	{ "Right Spk", NULL, "Right BE_OUT" },
205 };
206 
207 static const struct snd_kcontrol_new max_98390_tt_kcontrols[] = {
208 	SOC_DAPM_PIN_SWITCH("TL Spk"),
209 	SOC_DAPM_PIN_SWITCH("TR Spk"),
210 };
211 
212 static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = {
213 	SND_SOC_DAPM_SPK("TL Spk", NULL),
214 	SND_SOC_DAPM_SPK("TR Spk", NULL),
215 };
216 
217 static const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = {
218 	/* Tweeter speaker */
219 	{ "TL Spk", NULL, "Tweeter Left BE_OUT" },
220 	{ "TR Spk", NULL, "Tweeter Right BE_OUT" },
221 };
222 
223 static struct snd_soc_codec_conf max_98390_cml_codec_conf[] = {
224 	{
225 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
226 		.name_prefix = "Left",
227 	},
228 	{
229 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
230 		.name_prefix = "Right",
231 	},
232 };
233 
234 static struct snd_soc_codec_conf max_98390_codec_conf[] = {
235 	{
236 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
237 		.name_prefix = "Right",
238 	},
239 	{
240 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
241 		.name_prefix = "Left",
242 	},
243 	{
244 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME),
245 		.name_prefix = "Tweeter Right",
246 	},
247 	{
248 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV3_NAME),
249 		.name_prefix = "Tweeter Left",
250 	},
251 };
252 
253 static struct snd_soc_dai_link_component max_98390_components[] = {
254 	{
255 		.name = MAX_98390_DEV0_NAME,
256 		.dai_name = MAX_98390_CODEC_DAI,
257 	},
258 	{
259 		.name = MAX_98390_DEV1_NAME,
260 		.dai_name = MAX_98390_CODEC_DAI,
261 	},
262 	{
263 		.name = MAX_98390_DEV2_NAME,
264 		.dai_name = MAX_98390_CODEC_DAI,
265 	},
266 	{
267 		.name = MAX_98390_DEV3_NAME,
268 		.dai_name = MAX_98390_CODEC_DAI,
269 	},
270 };
271 
272 static const struct {
273 	unsigned int tx;
274 	unsigned int rx;
275 } max_98390_tdm_mask[] = {
276 	{.tx = 0x01, .rx = 0x3},
277 	{.tx = 0x02, .rx = 0x3},
278 	{.tx = 0x04, .rx = 0x3},
279 	{.tx = 0x08, .rx = 0x3},
280 };
281 
282 static int max_98390_hw_params(struct snd_pcm_substream *substream,
283 			       struct snd_pcm_hw_params *params)
284 {
285 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
286 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
287 	struct snd_soc_dai *codec_dai;
288 	int i, ret;
289 
290 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
291 		if (i >= ARRAY_SIZE(max_98390_tdm_mask)) {
292 			dev_err(codec_dai->dev, "invalid codec index %d\n", i);
293 			return -ENODEV;
294 		}
295 
296 		switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
297 		case SND_SOC_DAIFMT_DSP_A:
298 		case SND_SOC_DAIFMT_DSP_B:
299 			/* 4-slot TDM */
300 			ret = snd_soc_dai_set_tdm_slot(codec_dai,
301 						       max_98390_tdm_mask[i].tx,
302 						       max_98390_tdm_mask[i].rx,
303 						       4,
304 						       params_width(params));
305 			if (ret < 0) {
306 				dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
307 					ret);
308 				return ret;
309 			}
310 			break;
311 		default:
312 			dev_dbg(codec_dai->dev, "codec is in I2S mode\n");
313 			break;
314 		}
315 	}
316 	return 0;
317 }
318 
319 static int max_98390_init(struct snd_soc_pcm_runtime *rtd)
320 {
321 	struct snd_soc_card *card = rtd->card;
322 	unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
323 	int ret;
324 
325 	switch (num_codecs) {
326 	case 4:
327 		/* add widgets/controls/dapm for tweeter speakers */
328 		ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets,
329 						ARRAY_SIZE(max_98390_tt_dapm_widgets));
330 		if (ret) {
331 			dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n",
332 				ret);
333 			/* Don't need to add routes if widget addition failed */
334 			return ret;
335 		}
336 
337 		ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols,
338 						ARRAY_SIZE(max_98390_tt_kcontrols));
339 		if (ret) {
340 			dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n",
341 				ret);
342 			return ret;
343 		}
344 
345 		ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes,
346 					      ARRAY_SIZE(max_98390_tt_dapm_routes));
347 		if (ret) {
348 			dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n",
349 				ret);
350 			return ret;
351 		}
352 
353 		fallthrough;
354 	case 2:
355 		/* add regular speakers dapm route */
356 		ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets,
357 						ARRAY_SIZE(maxim_2spk_widgets));
358 		if (ret) {
359 			dev_err(rtd->dev, "fail to add max98390 woofer widgets, ret %d\n",
360 				ret);
361 			return ret;
362 		}
363 
364 		ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols,
365 						ARRAY_SIZE(maxim_2spk_kcontrols));
366 		if (ret) {
367 			dev_err(rtd->dev, "fail to add max98390 woofer kcontrols, ret %d\n",
368 				ret);
369 			return ret;
370 		}
371 
372 		ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes,
373 					      ARRAY_SIZE(max_98390_dapm_routes));
374 		if (ret) {
375 			dev_err(rtd->dev, "unable to add dapm routes, ret %d\n",
376 				ret);
377 			return ret;
378 		}
379 		break;
380 	default:
381 		dev_err(rtd->dev, "invalid codec number %d\n", num_codecs);
382 		return -EINVAL;
383 	}
384 
385 	return ret;
386 }
387 
388 static const struct snd_soc_ops max_98390_ops = {
389 	.hw_params = max_98390_hw_params,
390 };
391 
392 void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link)
393 {
394 	unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
395 
396 	link->codecs = max_98390_components;
397 
398 	switch (num_codecs) {
399 	case 2:
400 	case 4:
401 		link->num_codecs = num_codecs;
402 		break;
403 	default:
404 		dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
405 			MAX_98390_ACPI_HID);
406 		break;
407 	}
408 
409 	link->init = max_98390_init;
410 	link->ops = &max_98390_ops;
411 }
412 EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
413 
414 void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card)
415 {
416 	unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
417 
418 	card->codec_conf = max_98390_codec_conf;
419 
420 	switch (num_codecs) {
421 	case 2:
422 		if (soc_intel_is_cml())
423 			card->codec_conf = max_98390_cml_codec_conf;
424 
425 		fallthrough;
426 	case 4:
427 		card->num_configs = num_codecs;
428 		break;
429 	default:
430 		dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
431 			MAX_98390_ACPI_HID);
432 		break;
433 	}
434 }
435 EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON);
436 
437 /*
438  * Maxim MAX98357A/MAX98360A
439  */
440 static const struct snd_kcontrol_new max_98357a_kcontrols[] = {
441 	SOC_DAPM_PIN_SWITCH("Spk"),
442 };
443 
444 static const struct snd_soc_dapm_widget max_98357a_dapm_widgets[] = {
445 	SND_SOC_DAPM_SPK("Spk", NULL),
446 };
447 
448 static const struct snd_soc_dapm_route max_98357a_dapm_routes[] = {
449 	/* speaker */
450 	{"Spk", NULL, "Speaker"},
451 };
452 
453 static struct snd_soc_dai_link_component max_98357a_components[] = {
454 	{
455 		.name = MAX_98357A_DEV0_NAME,
456 		.dai_name = MAX_98357A_CODEC_DAI,
457 	}
458 };
459 
460 static struct snd_soc_dai_link_component max_98360a_components[] = {
461 	{
462 		.name = MAX_98360A_DEV0_NAME,
463 		.dai_name = MAX_98357A_CODEC_DAI,
464 	}
465 };
466 
467 static int max_98357a_init(struct snd_soc_pcm_runtime *rtd)
468 {
469 	struct snd_soc_card *card = rtd->card;
470 	int ret;
471 
472 	ret = snd_soc_dapm_new_controls(&card->dapm, max_98357a_dapm_widgets,
473 					ARRAY_SIZE(max_98357a_dapm_widgets));
474 	if (ret) {
475 		dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
476 		/* Don't need to add routes if widget addition failed */
477 		return ret;
478 	}
479 
480 	ret = snd_soc_add_card_controls(card, max_98357a_kcontrols,
481 					ARRAY_SIZE(max_98357a_kcontrols));
482 	if (ret) {
483 		dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
484 		return ret;
485 	}
486 
487 	ret = snd_soc_dapm_add_routes(&card->dapm, max_98357a_dapm_routes,
488 				      ARRAY_SIZE(max_98357a_dapm_routes));
489 
490 	if (ret)
491 		dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret);
492 
493 	return ret;
494 }
495 
496 void max_98357a_dai_link(struct snd_soc_dai_link *link)
497 {
498 	link->codecs = max_98357a_components;
499 	link->num_codecs = ARRAY_SIZE(max_98357a_components);
500 	link->init = max_98357a_init;
501 }
502 EXPORT_SYMBOL_NS(max_98357a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
503 
504 void max_98360a_dai_link(struct snd_soc_dai_link *link)
505 {
506 	link->codecs = max_98360a_components;
507 	link->num_codecs = ARRAY_SIZE(max_98360a_components);
508 	link->init = max_98357a_init;
509 }
510 EXPORT_SYMBOL_NS(max_98360a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
511 
512 MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers");
513 MODULE_LICENSE("GPL");
514