xref: /openbmc/linux/sound/soc/intel/boards/sof_maxim_common.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: GPL-2.0-only
2e2e404a6SSathyanarayana Nujella //
3e2e404a6SSathyanarayana Nujella // Copyright(c) 2020 Intel Corporation. All rights reserved.
49c5046e4SPierre-Louis Bossart #include <linux/module.h>
5e2e404a6SSathyanarayana Nujella #include <linux/string.h>
6e2e404a6SSathyanarayana Nujella #include <sound/pcm.h>
7*36eb9868SBrent Lu #include <sound/pcm_params.h>
8e2e404a6SSathyanarayana Nujella #include <sound/soc.h>
9f316c9d9SMac Chiang #include <sound/soc-acpi.h>
10e2e404a6SSathyanarayana Nujella #include <sound/soc-dai.h>
11e2e404a6SSathyanarayana Nujella #include <sound/soc-dapm.h>
12e2e404a6SSathyanarayana Nujella #include <uapi/sound/asound.h>
13e2e404a6SSathyanarayana Nujella #include "sof_maxim_common.h"
14e2e404a6SSathyanarayana Nujella 
15*36eb9868SBrent Lu /* helper function to get the number of specific codec */
get_num_codecs(const char * hid)16*36eb9868SBrent Lu static unsigned int get_num_codecs(const char *hid)
17*36eb9868SBrent Lu {
18*36eb9868SBrent Lu 	struct acpi_device *adev;
19*36eb9868SBrent Lu 	unsigned int dev_num = 0;
20*36eb9868SBrent Lu 
21*36eb9868SBrent Lu 	for_each_acpi_dev_match(adev, hid, NULL, -1)
22*36eb9868SBrent Lu 		dev_num++;
23*36eb9868SBrent Lu 
24*36eb9868SBrent Lu 	return dev_num;
25*36eb9868SBrent Lu }
26*36eb9868SBrent Lu 
2794d2d089SDharageswari R #define MAX_98373_PIN_NAME 16
2894d2d089SDharageswari R 
29be82e888SNaveen Manohar const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
30e2e404a6SSathyanarayana Nujella 	/* speaker */
31e2e404a6SSathyanarayana Nujella 	{ "Left Spk", NULL, "Left BE_OUT" },
32e2e404a6SSathyanarayana Nujella 	{ "Right Spk", NULL, "Right BE_OUT" },
33e2e404a6SSathyanarayana Nujella };
349c5046e4SPierre-Louis Bossart EXPORT_SYMBOL_NS(max_98373_dapm_routes, SND_SOC_INTEL_SOF_MAXIM_COMMON);
35e2e404a6SSathyanarayana Nujella 
36e2e404a6SSathyanarayana Nujella static struct snd_soc_codec_conf max_98373_codec_conf[] = {
37e2e404a6SSathyanarayana Nujella 	{
38e2e404a6SSathyanarayana Nujella 		.dlc = COMP_CODEC_CONF(MAX_98373_DEV0_NAME),
39e2e404a6SSathyanarayana Nujella 		.name_prefix = "Right",
40e2e404a6SSathyanarayana Nujella 	},
41e2e404a6SSathyanarayana Nujella 	{
42e2e404a6SSathyanarayana Nujella 		.dlc = COMP_CODEC_CONF(MAX_98373_DEV1_NAME),
43e2e404a6SSathyanarayana Nujella 		.name_prefix = "Left",
44e2e404a6SSathyanarayana Nujella 	},
45e2e404a6SSathyanarayana Nujella };
46e2e404a6SSathyanarayana Nujella 
47e2e404a6SSathyanarayana Nujella struct snd_soc_dai_link_component max_98373_components[] = {
48c8090048SDharageswari R 	{  /* For Right */
49e2e404a6SSathyanarayana Nujella 		.name = MAX_98373_DEV0_NAME,
50e2e404a6SSathyanarayana Nujella 		.dai_name = MAX_98373_CODEC_DAI,
51e2e404a6SSathyanarayana Nujella 	},
52c8090048SDharageswari R 	{  /* For Left */
53e2e404a6SSathyanarayana Nujella 		.name = MAX_98373_DEV1_NAME,
54e2e404a6SSathyanarayana Nujella 		.dai_name = MAX_98373_CODEC_DAI,
55e2e404a6SSathyanarayana Nujella 	},
56e2e404a6SSathyanarayana Nujella };
579c5046e4SPierre-Louis Bossart EXPORT_SYMBOL_NS(max_98373_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
58e2e404a6SSathyanarayana Nujella 
max_98373_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)599c5046e4SPierre-Louis Bossart static int max_98373_hw_params(struct snd_pcm_substream *substream,
60e2e404a6SSathyanarayana Nujella 			       struct snd_pcm_hw_params *params)
61e2e404a6SSathyanarayana Nujella {
622207b93bSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
63e2e404a6SSathyanarayana Nujella 	struct snd_soc_dai *codec_dai;
64e2e404a6SSathyanarayana Nujella 	int j;
65e2e404a6SSathyanarayana Nujella 
66e2e404a6SSathyanarayana Nujella 	for_each_rtd_codec_dais(rtd, j, codec_dai) {
67e2e404a6SSathyanarayana Nujella 		if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) {
68e2e404a6SSathyanarayana Nujella 			/* DEV0 tdm slot configuration */
690d7f2459SSathyanarayana Nujella 			snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32);
70e2e404a6SSathyanarayana Nujella 		}
71e2e404a6SSathyanarayana Nujella 		if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) {
72e2e404a6SSathyanarayana Nujella 			/* DEV1 tdm slot configuration */
730d7f2459SSathyanarayana Nujella 			snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32);
74e2e404a6SSathyanarayana Nujella 		}
75e2e404a6SSathyanarayana Nujella 	}
76e2e404a6SSathyanarayana Nujella 	return 0;
77e2e404a6SSathyanarayana Nujella }
78e2e404a6SSathyanarayana Nujella 
max_98373_trigger(struct snd_pcm_substream * substream,int cmd)799c5046e4SPierre-Louis Bossart int max_98373_trigger(struct snd_pcm_substream *substream, int cmd)
8094d2d089SDharageswari R {
812207b93bSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
8294d2d089SDharageswari R 	struct snd_soc_dai *codec_dai;
831183c350SBard Liao 	struct snd_soc_dai *cpu_dai;
8494d2d089SDharageswari R 	int j;
8594d2d089SDharageswari R 	int ret = 0;
8694d2d089SDharageswari R 
87e300486aSRander Wang 	/* set spk pin by playback only */
88e300486aSRander Wang 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
89e300486aSRander Wang 		return 0;
90e300486aSRander Wang 
911183c350SBard Liao 	cpu_dai = asoc_rtd_to_cpu(rtd, 0);
9294d2d089SDharageswari R 	for_each_rtd_codec_dais(rtd, j, codec_dai) {
9394d2d089SDharageswari R 		struct snd_soc_dapm_context *dapm =
941183c350SBard Liao 				snd_soc_component_get_dapm(cpu_dai->component);
9594d2d089SDharageswari R 		char pin_name[MAX_98373_PIN_NAME];
9694d2d089SDharageswari R 
9794d2d089SDharageswari R 		snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
9894d2d089SDharageswari R 			 codec_dai->component->name_prefix);
9994d2d089SDharageswari R 
10094d2d089SDharageswari R 		switch (cmd) {
10194d2d089SDharageswari R 		case SNDRV_PCM_TRIGGER_START:
10294d2d089SDharageswari R 		case SNDRV_PCM_TRIGGER_RESUME:
10394d2d089SDharageswari R 		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
10494d2d089SDharageswari R 			ret = snd_soc_dapm_enable_pin(dapm, pin_name);
10594d2d089SDharageswari R 			if (!ret)
10694d2d089SDharageswari R 				snd_soc_dapm_sync(dapm);
10794d2d089SDharageswari R 			break;
10894d2d089SDharageswari R 		case SNDRV_PCM_TRIGGER_STOP:
10994d2d089SDharageswari R 		case SNDRV_PCM_TRIGGER_SUSPEND:
11094d2d089SDharageswari R 		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
11194d2d089SDharageswari R 			ret = snd_soc_dapm_disable_pin(dapm, pin_name);
11294d2d089SDharageswari R 			if (!ret)
11394d2d089SDharageswari R 				snd_soc_dapm_sync(dapm);
11494d2d089SDharageswari R 			break;
11594d2d089SDharageswari R 		default:
11694d2d089SDharageswari R 			break;
11794d2d089SDharageswari R 		}
11894d2d089SDharageswari R 	}
11994d2d089SDharageswari R 
12094d2d089SDharageswari R 	return ret;
12194d2d089SDharageswari R }
1229c5046e4SPierre-Louis Bossart EXPORT_SYMBOL_NS(max_98373_trigger, SND_SOC_INTEL_SOF_MAXIM_COMMON);
12394d2d089SDharageswari R 
124e2e404a6SSathyanarayana Nujella struct snd_soc_ops max_98373_ops = {
1259c5046e4SPierre-Louis Bossart 	.hw_params = max_98373_hw_params,
1269c5046e4SPierre-Louis Bossart 	.trigger = max_98373_trigger,
127e2e404a6SSathyanarayana Nujella };
1289c5046e4SPierre-Louis Bossart EXPORT_SYMBOL_NS(max_98373_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON);
129e2e404a6SSathyanarayana Nujella 
max_98373_spk_codec_init(struct snd_soc_pcm_runtime * rtd)1309c5046e4SPierre-Louis Bossart int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
131e2e404a6SSathyanarayana Nujella {
132e2e404a6SSathyanarayana Nujella 	struct snd_soc_card *card = rtd->card;
133e2e404a6SSathyanarayana Nujella 	int ret;
134e2e404a6SSathyanarayana Nujella 
135e2e404a6SSathyanarayana Nujella 	ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes,
136e2e404a6SSathyanarayana Nujella 				      ARRAY_SIZE(max_98373_dapm_routes));
137e2e404a6SSathyanarayana Nujella 	if (ret)
138e2e404a6SSathyanarayana Nujella 		dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
139e2e404a6SSathyanarayana Nujella 	return ret;
140e2e404a6SSathyanarayana Nujella }
1419c5046e4SPierre-Louis Bossart EXPORT_SYMBOL_NS(max_98373_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON);
142e2e404a6SSathyanarayana Nujella 
max_98373_set_codec_conf(struct snd_soc_card * card)1439c5046e4SPierre-Louis Bossart void max_98373_set_codec_conf(struct snd_soc_card *card)
144e2e404a6SSathyanarayana Nujella {
145e2e404a6SSathyanarayana Nujella 	card->codec_conf = max_98373_codec_conf;
146e2e404a6SSathyanarayana Nujella 	card->num_configs = ARRAY_SIZE(max_98373_codec_conf);
147e2e404a6SSathyanarayana Nujella }
1489c5046e4SPierre-Louis Bossart EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON);
1499c5046e4SPierre-Louis Bossart 
150a21515b5SBrent Lu /*
151f316c9d9SMac Chiang  * Maxim MAX98390
152f316c9d9SMac Chiang  */
153639cd58bSPierre-Louis Bossart static const struct snd_soc_dapm_route max_98390_dapm_routes[] = {
154f316c9d9SMac Chiang 	/* speaker */
155f316c9d9SMac Chiang 	{ "Left Spk", NULL, "Left BE_OUT" },
156f316c9d9SMac Chiang 	{ "Right Spk", NULL, "Right BE_OUT" },
157f316c9d9SMac Chiang };
158f316c9d9SMac Chiang 
159f316c9d9SMac Chiang static const struct snd_kcontrol_new max_98390_tt_kcontrols[] = {
160f316c9d9SMac Chiang 	SOC_DAPM_PIN_SWITCH("TL Spk"),
161f316c9d9SMac Chiang 	SOC_DAPM_PIN_SWITCH("TR Spk"),
162f316c9d9SMac Chiang };
163f316c9d9SMac Chiang 
164f316c9d9SMac Chiang static const struct snd_soc_dapm_widget max_98390_tt_dapm_widgets[] = {
165f316c9d9SMac Chiang 	SND_SOC_DAPM_SPK("TL Spk", NULL),
166f316c9d9SMac Chiang 	SND_SOC_DAPM_SPK("TR Spk", NULL),
167f316c9d9SMac Chiang };
168f316c9d9SMac Chiang 
169639cd58bSPierre-Louis Bossart static const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = {
170f316c9d9SMac Chiang 	/* Tweeter speaker */
171f316c9d9SMac Chiang 	{ "TL Spk", NULL, "Tweeter Left BE_OUT" },
172f316c9d9SMac Chiang 	{ "TR Spk", NULL, "Tweeter Right BE_OUT" },
173f316c9d9SMac Chiang };
174f316c9d9SMac Chiang 
175f316c9d9SMac Chiang static struct snd_soc_codec_conf max_98390_codec_conf[] = {
176f316c9d9SMac Chiang 	{
177f316c9d9SMac Chiang 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
178f316c9d9SMac Chiang 		.name_prefix = "Right",
179f316c9d9SMac Chiang 	},
180f316c9d9SMac Chiang 	{
181f316c9d9SMac Chiang 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
182f316c9d9SMac Chiang 		.name_prefix = "Left",
183f316c9d9SMac Chiang 	},
184f316c9d9SMac Chiang 	{
185f316c9d9SMac Chiang 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME),
186f316c9d9SMac Chiang 		.name_prefix = "Tweeter Right",
187f316c9d9SMac Chiang 	},
188f316c9d9SMac Chiang 	{
189f316c9d9SMac Chiang 		.dlc = COMP_CODEC_CONF(MAX_98390_DEV3_NAME),
190f316c9d9SMac Chiang 		.name_prefix = "Tweeter Left",
191f316c9d9SMac Chiang 	},
192f316c9d9SMac Chiang };
193f316c9d9SMac Chiang 
194*36eb9868SBrent Lu static struct snd_soc_dai_link_component max_98390_components[] = {
195f316c9d9SMac Chiang 	{
196f316c9d9SMac Chiang 		.name = MAX_98390_DEV0_NAME,
197f316c9d9SMac Chiang 		.dai_name = MAX_98390_CODEC_DAI,
198f316c9d9SMac Chiang 	},
199f316c9d9SMac Chiang 	{
200f316c9d9SMac Chiang 		.name = MAX_98390_DEV1_NAME,
201f316c9d9SMac Chiang 		.dai_name = MAX_98390_CODEC_DAI,
202f316c9d9SMac Chiang 	},
203f316c9d9SMac Chiang 	{
204f316c9d9SMac Chiang 		.name = MAX_98390_DEV2_NAME,
205f316c9d9SMac Chiang 		.dai_name = MAX_98390_CODEC_DAI,
206f316c9d9SMac Chiang 	},
207f316c9d9SMac Chiang 	{
208f316c9d9SMac Chiang 		.name = MAX_98390_DEV3_NAME,
209f316c9d9SMac Chiang 		.dai_name = MAX_98390_CODEC_DAI,
210f316c9d9SMac Chiang 	},
211f316c9d9SMac Chiang };
212*36eb9868SBrent Lu 
213*36eb9868SBrent Lu static const struct {
214*36eb9868SBrent Lu 	unsigned int tx;
215*36eb9868SBrent Lu 	unsigned int rx;
216*36eb9868SBrent Lu } max_98390_tdm_mask[] = {
217*36eb9868SBrent Lu 	{.tx = 0x01, .rx = 0x3},
218*36eb9868SBrent Lu 	{.tx = 0x02, .rx = 0x3},
219*36eb9868SBrent Lu 	{.tx = 0x04, .rx = 0x3},
220*36eb9868SBrent Lu 	{.tx = 0x08, .rx = 0x3},
221*36eb9868SBrent Lu };
222f316c9d9SMac Chiang 
max_98390_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)223f316c9d9SMac Chiang static int max_98390_hw_params(struct snd_pcm_substream *substream,
224f316c9d9SMac Chiang 			       struct snd_pcm_hw_params *params)
225f316c9d9SMac Chiang {
226f316c9d9SMac Chiang 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
227f316c9d9SMac Chiang 	struct snd_soc_dai *codec_dai;
228*36eb9868SBrent Lu 	int i, ret;
229f316c9d9SMac Chiang 
230f316c9d9SMac Chiang 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
231*36eb9868SBrent Lu 		if (i >= ARRAY_SIZE(max_98390_tdm_mask)) {
232f316c9d9SMac Chiang 			dev_err(codec_dai->dev, "invalid codec index %d\n", i);
233f316c9d9SMac Chiang 			return -ENODEV;
234f316c9d9SMac Chiang 		}
235f316c9d9SMac Chiang 
236*36eb9868SBrent Lu 		ret = snd_soc_dai_set_tdm_slot(codec_dai, max_98390_tdm_mask[i].tx,
237*36eb9868SBrent Lu 					       max_98390_tdm_mask[i].rx, 4,
238*36eb9868SBrent Lu 					       params_width(params));
239*36eb9868SBrent Lu 		if (ret < 0) {
240*36eb9868SBrent Lu 			dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
241*36eb9868SBrent Lu 				ret);
242*36eb9868SBrent Lu 			return ret;
243f316c9d9SMac Chiang 		}
244f316c9d9SMac Chiang 	}
245f316c9d9SMac Chiang 	return 0;
246f316c9d9SMac Chiang }
247f316c9d9SMac Chiang 
max_98390_init(struct snd_soc_pcm_runtime * rtd)248*36eb9868SBrent Lu static int max_98390_init(struct snd_soc_pcm_runtime *rtd)
249f316c9d9SMac Chiang {
250f316c9d9SMac Chiang 	struct snd_soc_card *card = rtd->card;
251*36eb9868SBrent Lu 	unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
252f316c9d9SMac Chiang 	int ret;
253f316c9d9SMac Chiang 
254*36eb9868SBrent Lu 	switch (num_codecs) {
255*36eb9868SBrent Lu 	case 4:
256f316c9d9SMac Chiang 		/* add widgets/controls/dapm for tweeter speakers */
257f316c9d9SMac Chiang 		ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets,
258f316c9d9SMac Chiang 						ARRAY_SIZE(max_98390_tt_dapm_widgets));
259f316c9d9SMac Chiang 		if (ret) {
260*36eb9868SBrent Lu 			dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n",
261*36eb9868SBrent Lu 				ret);
262f316c9d9SMac Chiang 			/* Don't need to add routes if widget addition failed */
263f316c9d9SMac Chiang 			return ret;
264f316c9d9SMac Chiang 		}
265f316c9d9SMac Chiang 
266f316c9d9SMac Chiang 		ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols,
267f316c9d9SMac Chiang 						ARRAY_SIZE(max_98390_tt_kcontrols));
268f316c9d9SMac Chiang 		if (ret) {
269*36eb9868SBrent Lu 			dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n",
270*36eb9868SBrent Lu 				ret);
271f316c9d9SMac Chiang 			return ret;
272f316c9d9SMac Chiang 		}
273f316c9d9SMac Chiang 
274f316c9d9SMac Chiang 		ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes,
275f316c9d9SMac Chiang 					      ARRAY_SIZE(max_98390_tt_dapm_routes));
276*36eb9868SBrent Lu 		if (ret) {
277*36eb9868SBrent Lu 			dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n",
278*36eb9868SBrent Lu 				ret);
279f316c9d9SMac Chiang 			return ret;
280f316c9d9SMac Chiang 		}
281f316c9d9SMac Chiang 
282*36eb9868SBrent Lu 		fallthrough;
283*36eb9868SBrent Lu 	case 2:
284*36eb9868SBrent Lu 		/* add regular speakers dapm route */
285*36eb9868SBrent Lu 		ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes,
286*36eb9868SBrent Lu 					      ARRAY_SIZE(max_98390_dapm_routes));
287*36eb9868SBrent Lu 		if (ret) {
288*36eb9868SBrent Lu 			dev_err(rtd->dev, "unable to add dapm routes, ret %d\n",
289*36eb9868SBrent Lu 				ret);
290*36eb9868SBrent Lu 			return ret;
291*36eb9868SBrent Lu 		}
292*36eb9868SBrent Lu 		break;
293*36eb9868SBrent Lu 	default:
294*36eb9868SBrent Lu 		dev_err(rtd->dev, "invalid codec number %d\n", num_codecs);
295*36eb9868SBrent Lu 		return -EINVAL;
296*36eb9868SBrent Lu 	}
297*36eb9868SBrent Lu 
298*36eb9868SBrent Lu 	return ret;
299*36eb9868SBrent Lu }
300*36eb9868SBrent Lu 
301*36eb9868SBrent Lu static const struct snd_soc_ops max_98390_ops = {
302f316c9d9SMac Chiang 	.hw_params = max_98390_hw_params,
303f316c9d9SMac Chiang };
304f316c9d9SMac Chiang 
max_98390_dai_link(struct device * dev,struct snd_soc_dai_link * link)305*36eb9868SBrent Lu void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link)
306f316c9d9SMac Chiang {
307*36eb9868SBrent Lu 	unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
308*36eb9868SBrent Lu 
309*36eb9868SBrent Lu 	link->codecs = max_98390_components;
310*36eb9868SBrent Lu 
311*36eb9868SBrent Lu 	switch (num_codecs) {
312*36eb9868SBrent Lu 	case 2:
313*36eb9868SBrent Lu 	case 4:
314*36eb9868SBrent Lu 		link->num_codecs = num_codecs;
315*36eb9868SBrent Lu 		break;
316*36eb9868SBrent Lu 	default:
317*36eb9868SBrent Lu 		dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
318*36eb9868SBrent Lu 			MAX_98390_ACPI_HID);
319*36eb9868SBrent Lu 		break;
320*36eb9868SBrent Lu 	}
321*36eb9868SBrent Lu 
322*36eb9868SBrent Lu 	link->init = max_98390_init;
323*36eb9868SBrent Lu 	link->ops = &max_98390_ops;
324*36eb9868SBrent Lu }
325*36eb9868SBrent Lu EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
326*36eb9868SBrent Lu 
max_98390_set_codec_conf(struct device * dev,struct snd_soc_card * card)327*36eb9868SBrent Lu void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card)
328*36eb9868SBrent Lu {
329*36eb9868SBrent Lu 	unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
330*36eb9868SBrent Lu 
331f316c9d9SMac Chiang 	card->codec_conf = max_98390_codec_conf;
332*36eb9868SBrent Lu 
333*36eb9868SBrent Lu 	switch (num_codecs) {
334*36eb9868SBrent Lu 	case 2:
335*36eb9868SBrent Lu 	case 4:
336*36eb9868SBrent Lu 		card->num_configs = num_codecs;
337*36eb9868SBrent Lu 		break;
338*36eb9868SBrent Lu 	default:
339*36eb9868SBrent Lu 		dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
340*36eb9868SBrent Lu 			MAX_98390_ACPI_HID);
341*36eb9868SBrent Lu 		break;
342f316c9d9SMac Chiang 	}
343f316c9d9SMac Chiang }
344f316c9d9SMac Chiang EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON);
345f316c9d9SMac Chiang 
346f316c9d9SMac Chiang /*
34707acee58SBrent Lu  * Maxim MAX98357A/MAX98360A
348a21515b5SBrent Lu  */
349a21515b5SBrent Lu static const struct snd_kcontrol_new max_98357a_kcontrols[] = {
350a21515b5SBrent Lu 	SOC_DAPM_PIN_SWITCH("Spk"),
351a21515b5SBrent Lu };
352a21515b5SBrent Lu 
353a21515b5SBrent Lu static const struct snd_soc_dapm_widget max_98357a_dapm_widgets[] = {
354a21515b5SBrent Lu 	SND_SOC_DAPM_SPK("Spk", NULL),
355a21515b5SBrent Lu };
356a21515b5SBrent Lu 
357a21515b5SBrent Lu static const struct snd_soc_dapm_route max_98357a_dapm_routes[] = {
358a21515b5SBrent Lu 	/* speaker */
359a21515b5SBrent Lu 	{"Spk", NULL, "Speaker"},
360a21515b5SBrent Lu };
361a21515b5SBrent Lu 
362a21515b5SBrent Lu static struct snd_soc_dai_link_component max_98357a_components[] = {
363a21515b5SBrent Lu 	{
364a21515b5SBrent Lu 		.name = MAX_98357A_DEV0_NAME,
365a21515b5SBrent Lu 		.dai_name = MAX_98357A_CODEC_DAI,
366a21515b5SBrent Lu 	}
367a21515b5SBrent Lu };
368a21515b5SBrent Lu 
36907acee58SBrent Lu static struct snd_soc_dai_link_component max_98360a_components[] = {
37007acee58SBrent Lu 	{
37107acee58SBrent Lu 		.name = MAX_98360A_DEV0_NAME,
37207acee58SBrent Lu 		.dai_name = MAX_98357A_CODEC_DAI,
37307acee58SBrent Lu 	}
37407acee58SBrent Lu };
37507acee58SBrent Lu 
max_98357a_init(struct snd_soc_pcm_runtime * rtd)376a21515b5SBrent Lu static int max_98357a_init(struct snd_soc_pcm_runtime *rtd)
377a21515b5SBrent Lu {
378a21515b5SBrent Lu 	struct snd_soc_card *card = rtd->card;
379a21515b5SBrent Lu 	int ret;
380a21515b5SBrent Lu 
381a21515b5SBrent Lu 	ret = snd_soc_dapm_new_controls(&card->dapm, max_98357a_dapm_widgets,
382a21515b5SBrent Lu 					ARRAY_SIZE(max_98357a_dapm_widgets));
383a21515b5SBrent Lu 	if (ret) {
384a21515b5SBrent Lu 		dev_err(rtd->dev, "unable to add dapm controls, ret %d\n", ret);
385a21515b5SBrent Lu 		/* Don't need to add routes if widget addition failed */
386a21515b5SBrent Lu 		return ret;
387a21515b5SBrent Lu 	}
388a21515b5SBrent Lu 
389a21515b5SBrent Lu 	ret = snd_soc_add_card_controls(card, max_98357a_kcontrols,
390a21515b5SBrent Lu 					ARRAY_SIZE(max_98357a_kcontrols));
391a21515b5SBrent Lu 	if (ret) {
392a21515b5SBrent Lu 		dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
393a21515b5SBrent Lu 		return ret;
394a21515b5SBrent Lu 	}
395a21515b5SBrent Lu 
396a21515b5SBrent Lu 	ret = snd_soc_dapm_add_routes(&card->dapm, max_98357a_dapm_routes,
397a21515b5SBrent Lu 				      ARRAY_SIZE(max_98357a_dapm_routes));
398a21515b5SBrent Lu 
399a21515b5SBrent Lu 	if (ret)
400a21515b5SBrent Lu 		dev_err(rtd->dev, "unable to add dapm routes, ret %d\n", ret);
401a21515b5SBrent Lu 
402a21515b5SBrent Lu 	return ret;
403a21515b5SBrent Lu }
404a21515b5SBrent Lu 
max_98357a_dai_link(struct snd_soc_dai_link * link)405a21515b5SBrent Lu void max_98357a_dai_link(struct snd_soc_dai_link *link)
406a21515b5SBrent Lu {
407a21515b5SBrent Lu 	link->codecs = max_98357a_components;
408a21515b5SBrent Lu 	link->num_codecs = ARRAY_SIZE(max_98357a_components);
409a21515b5SBrent Lu 	link->init = max_98357a_init;
410a21515b5SBrent Lu }
411a21515b5SBrent Lu EXPORT_SYMBOL_NS(max_98357a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
412a21515b5SBrent Lu 
max_98360a_dai_link(struct snd_soc_dai_link * link)41307acee58SBrent Lu void max_98360a_dai_link(struct snd_soc_dai_link *link)
41407acee58SBrent Lu {
41507acee58SBrent Lu 	link->codecs = max_98360a_components;
41607acee58SBrent Lu 	link->num_codecs = ARRAY_SIZE(max_98360a_components);
41707acee58SBrent Lu 	link->init = max_98357a_init;
41807acee58SBrent Lu }
41907acee58SBrent Lu EXPORT_SYMBOL_NS(max_98360a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
42007acee58SBrent Lu 
4219c5046e4SPierre-Louis Bossart MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers");
4229c5046e4SPierre-Louis Bossart MODULE_LICENSE("GPL");
423