1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright(c) 2019 Intel Corporation.
3
4/*
5 * Intel SOF Machine driver for DA7219 + MAX98373/MAX98360A codec
6 */
7
8#include <linux/input.h>
9#include <linux/module.h>
10#include <sound/jack.h>
11#include <sound/pcm.h>
12#include <sound/pcm_params.h>
13#include <linux/platform_device.h>
14#include <sound/soc.h>
15#include <sound/soc-acpi.h>
16#include "../../codecs/da7219.h"
17#include "hda_dsp_common.h"
18
19#define DIALOG_CODEC_DAI	"da7219-hifi"
20#define MAX98373_CODEC_DAI	"max98373-aif1"
21#define MAXIM_DEV0_NAME		"i2c-MX98373:00"
22#define MAXIM_DEV1_NAME		"i2c-MX98373:01"
23
24struct hdmi_pcm {
25	struct list_head head;
26	struct snd_soc_dai *codec_dai;
27	int device;
28};
29
30struct card_private {
31	struct snd_soc_jack headset;
32	struct list_head hdmi_pcm_list;
33	struct snd_soc_jack hdmi[3];
34};
35
36static int platform_clock_control(struct snd_soc_dapm_widget *w,
37				  struct snd_kcontrol *k, int  event)
38{
39	struct snd_soc_dapm_context *dapm = w->dapm;
40	struct snd_soc_card *card = dapm->card;
41	struct snd_soc_dai *codec_dai;
42	int ret = 0;
43
44	codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI);
45	if (!codec_dai) {
46		dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
47		return -EIO;
48	}
49
50	if (SND_SOC_DAPM_EVENT_OFF(event)) {
51		ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK,
52					  0, 0);
53		if (ret)
54			dev_err(card->dev, "failed to stop PLL: %d\n", ret);
55	} else if (SND_SOC_DAPM_EVENT_ON(event)) {
56		ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
57					  0, DA7219_PLL_FREQ_OUT_98304);
58		if (ret)
59			dev_err(card->dev, "failed to start PLL: %d\n", ret);
60	}
61
62	return ret;
63}
64
65static const struct snd_kcontrol_new controls[] = {
66	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
67	SOC_DAPM_PIN_SWITCH("Headset Mic"),
68	SOC_DAPM_PIN_SWITCH("Line Out"),
69	SOC_DAPM_PIN_SWITCH("Left Spk"),
70	SOC_DAPM_PIN_SWITCH("Right Spk"),
71};
72
73static const struct snd_kcontrol_new m98360a_controls[] = {
74	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
75	SOC_DAPM_PIN_SWITCH("Headset Mic"),
76	SOC_DAPM_PIN_SWITCH("Line Out"),
77	SOC_DAPM_PIN_SWITCH("Spk"),
78};
79
80/* For MAX98373 amp */
81static const struct snd_soc_dapm_widget widgets[] = {
82	SND_SOC_DAPM_HP("Headphone Jack", NULL),
83	SND_SOC_DAPM_MIC("Headset Mic", NULL),
84	SND_SOC_DAPM_LINE("Line Out", NULL),
85
86	SND_SOC_DAPM_SPK("Left Spk", NULL),
87	SND_SOC_DAPM_SPK("Right Spk", NULL),
88
89	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
90			    platform_clock_control, SND_SOC_DAPM_POST_PMD |
91			    SND_SOC_DAPM_PRE_PMU),
92
93	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
94};
95
96static const struct snd_soc_dapm_route audio_map[] = {
97	{ "Headphone Jack", NULL, "HPL" },
98	{ "Headphone Jack", NULL, "HPR" },
99
100	{ "MIC", NULL, "Headset Mic" },
101
102	{ "Headphone Jack", NULL, "Platform Clock" },
103	{ "Headset Mic", NULL, "Platform Clock" },
104	{ "Line Out", NULL, "Platform Clock" },
105
106	{ "Left Spk", NULL, "Left BE_OUT" },
107	{ "Right Spk", NULL, "Right BE_OUT" },
108
109	/* digital mics */
110	{"DMic", NULL, "SoC DMIC"},
111};
112
113/* For MAX98360A amp */
114static const struct snd_soc_dapm_widget max98360a_widgets[] = {
115	SND_SOC_DAPM_HP("Headphone Jack", NULL),
116	SND_SOC_DAPM_MIC("Headset Mic", NULL),
117	SND_SOC_DAPM_LINE("Line Out", NULL),
118
119	SND_SOC_DAPM_SPK("Spk", NULL),
120
121	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
122			    platform_clock_control, SND_SOC_DAPM_POST_PMD |
123			    SND_SOC_DAPM_PRE_PMU),
124
125	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
126};
127
128static const struct snd_soc_dapm_route max98360a_map[] = {
129	{ "Headphone Jack", NULL, "HPL" },
130	{ "Headphone Jack", NULL, "HPR" },
131
132	{ "MIC", NULL, "Headset Mic" },
133
134	{ "Headphone Jack", NULL, "Platform Clock" },
135	{ "Headset Mic", NULL, "Platform Clock" },
136	{ "Line Out", NULL, "Platform Clock" },
137
138	{"Spk", NULL, "Speaker"},
139
140	/* digital mics */
141	{"DMic", NULL, "SoC DMIC"},
142};
143
144static struct snd_soc_jack_pin jack_pins[] = {
145	{
146		.pin    = "Headphone Jack",
147		.mask   = SND_JACK_HEADPHONE,
148	},
149	{
150		.pin    = "Headset Mic",
151		.mask   = SND_JACK_MICROPHONE,
152	},
153	{
154		.pin    = "Line Out",
155		.mask   = SND_JACK_LINEOUT,
156	},
157};
158
159static struct snd_soc_jack headset;
160
161static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
162{
163	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
164	struct snd_soc_component *component = codec_dai->component;
165	struct snd_soc_jack *jack;
166	int ret;
167
168	/* Configure sysclk for codec */
169	ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24000000,
170				     SND_SOC_CLOCK_IN);
171	if (ret) {
172		dev_err(rtd->dev, "can't set codec sysclk configuration\n");
173		return ret;
174	}
175
176	/*
177	 * Headset buttons map to the google Reference headset.
178	 * These can be configured by userspace.
179	 */
180	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
181					 SND_JACK_HEADSET | SND_JACK_BTN_0 |
182					 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
183					 SND_JACK_BTN_3 | SND_JACK_LINEOUT,
184					 &headset,
185					 jack_pins,
186					 ARRAY_SIZE(jack_pins));
187	if (ret) {
188		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
189		return ret;
190	}
191
192	jack = &headset;
193	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
194	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
195	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
196	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
197	snd_soc_component_set_jack(component, jack, NULL);
198
199	return ret;
200}
201
202static int ssp1_hw_params(struct snd_pcm_substream *substream,
203			      struct snd_pcm_hw_params *params)
204{
205	struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
206	int ret, j;
207
208	for (j = 0; j < runtime->dai_link->num_codecs; j++) {
209		struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, j);
210
211		if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
212			/* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */
213			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16);
214			if (ret < 0) {
215				dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
216				return ret;
217			}
218		}
219		if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
220			/* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */
221			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16);
222			if (ret < 0) {
223				dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
224				return ret;
225			}
226		}
227	}
228
229	return 0;
230}
231
232static struct snd_soc_ops ssp1_ops = {
233	.hw_params = ssp1_hw_params,
234};
235
236static struct snd_soc_codec_conf max98373_codec_conf[] = {
237	{
238		.dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME),
239		.name_prefix = "Right",
240	},
241	{
242		.dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME),
243		.name_prefix = "Left",
244	},
245};
246
247static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
248{
249	struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
250	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
251	struct hdmi_pcm *pcm;
252
253	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
254	if (!pcm)
255		return -ENOMEM;
256
257	pcm->device = dai->id;
258	pcm->codec_dai = dai;
259
260	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
261
262	return 0;
263}
264
265static int card_late_probe(struct snd_soc_card *card)
266{
267	struct card_private *ctx = snd_soc_card_get_drvdata(card);
268	struct snd_soc_acpi_mach *mach = (card->dev)->platform_data;
269	struct hdmi_pcm *pcm;
270
271	if (mach->mach_params.common_hdmi_codec_drv) {
272		pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm,
273				       head);
274		return hda_dsp_hdmi_build_controls(card,
275						   pcm->codec_dai->component);
276	}
277
278	return -EINVAL;
279}
280
281SND_SOC_DAILINK_DEF(ssp0_pin,
282	DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
283SND_SOC_DAILINK_DEF(ssp0_codec,
284	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI)));
285
286SND_SOC_DAILINK_DEF(ssp1_pin,
287	DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
288SND_SOC_DAILINK_DEF(ssp1_amps,
289	DAILINK_COMP_ARRAY(
290	/* Left */	COMP_CODEC(MAXIM_DEV0_NAME, MAX98373_CODEC_DAI),
291	/* Right */	COMP_CODEC(MAXIM_DEV1_NAME, MAX98373_CODEC_DAI)));
292
293SND_SOC_DAILINK_DEF(ssp1_m98360a,
294	DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
295
296SND_SOC_DAILINK_DEF(dmic_pin,
297	DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
298SND_SOC_DAILINK_DEF(dmic_codec,
299	DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
300
301SND_SOC_DAILINK_DEF(dmic16k_pin,
302	DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
303
304SND_SOC_DAILINK_DEF(idisp1_pin,
305	DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
306SND_SOC_DAILINK_DEF(idisp1_codec,
307	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
308
309SND_SOC_DAILINK_DEF(idisp2_pin,
310	DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
311SND_SOC_DAILINK_DEF(idisp2_codec,
312	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
313
314SND_SOC_DAILINK_DEF(idisp3_pin,
315	DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
316SND_SOC_DAILINK_DEF(idisp3_codec,
317	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
318
319SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */
320	DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
321
322static struct snd_soc_dai_link dais[] = {
323	/* Back End DAI links */
324	{
325		.name = "SSP1-Codec",
326		.id = 0,
327		.ignore_pmdown_time = 1,
328		.no_pcm = 1,
329		.dpcm_playback = 1,
330		.dpcm_capture = 1, /* IV feedback */
331		.ops = &ssp1_ops,
332		SND_SOC_DAILINK_REG(ssp1_pin, ssp1_amps, platform),
333	},
334	{
335		.name = "SSP0-Codec",
336		.id = 1,
337		.no_pcm = 1,
338		.init = da7219_codec_init,
339		.ignore_pmdown_time = 1,
340		.dpcm_playback = 1,
341		.dpcm_capture = 1,
342		SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
343	},
344	{
345		.name = "dmic01",
346		.id = 2,
347		.ignore_suspend = 1,
348		.dpcm_capture = 1,
349		.no_pcm = 1,
350		SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
351	},
352	{
353		.name = "iDisp1",
354		.id = 3,
355		.init = hdmi_init,
356		.dpcm_playback = 1,
357		.no_pcm = 1,
358		SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
359	},
360	{
361		.name = "iDisp2",
362		.id = 4,
363		.init = hdmi_init,
364		.dpcm_playback = 1,
365		.no_pcm = 1,
366		SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
367	},
368	{
369		.name = "iDisp3",
370		.id = 5,
371		.init = hdmi_init,
372		.dpcm_playback = 1,
373		.no_pcm = 1,
374		SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
375	},
376	{
377		.name = "dmic16k",
378		.id = 6,
379		.ignore_suspend = 1,
380		.dpcm_capture = 1,
381		.no_pcm = 1,
382		SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform),
383	}
384};
385
386static struct snd_soc_card card_da7219_m98373 = {
387	.name = "da7219max",
388	.owner = THIS_MODULE,
389	.dai_link = dais,
390	.num_links = ARRAY_SIZE(dais),
391	.controls = controls,
392	.num_controls = ARRAY_SIZE(controls),
393	.dapm_widgets = widgets,
394	.num_dapm_widgets = ARRAY_SIZE(widgets),
395	.dapm_routes = audio_map,
396	.num_dapm_routes = ARRAY_SIZE(audio_map),
397	.codec_conf = max98373_codec_conf,
398	.num_configs = ARRAY_SIZE(max98373_codec_conf),
399	.fully_routed = true,
400	.late_probe = card_late_probe,
401};
402
403static struct snd_soc_card card_da7219_m98360a = {
404	.name = "da7219max98360a",
405	.owner = THIS_MODULE,
406	.dai_link = dais,
407	.num_links = ARRAY_SIZE(dais),
408	.controls = m98360a_controls,
409	.num_controls = ARRAY_SIZE(m98360a_controls),
410	.dapm_widgets = max98360a_widgets,
411	.num_dapm_widgets = ARRAY_SIZE(max98360a_widgets),
412	.dapm_routes = max98360a_map,
413	.num_dapm_routes = ARRAY_SIZE(max98360a_map),
414	.fully_routed = true,
415	.late_probe = card_late_probe,
416};
417
418static int audio_probe(struct platform_device *pdev)
419{
420	static struct snd_soc_card *card;
421	struct snd_soc_acpi_mach *mach;
422	struct card_private *ctx;
423	int ret;
424
425	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
426	if (!ctx)
427		return -ENOMEM;
428
429	/* By default dais[0] is configured for max98373 */
430	if (!strcmp(pdev->name, "sof_da7219_mx98360a")) {
431		dais[0] = (struct snd_soc_dai_link) {
432			.name = "SSP1-Codec",
433			.id = 0,
434			.no_pcm = 1,
435			.dpcm_playback = 1,
436			.ignore_pmdown_time = 1,
437			SND_SOC_DAILINK_REG(ssp1_pin, ssp1_m98360a, platform) };
438	}
439
440	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
441	card = (struct snd_soc_card *)pdev->id_entry->driver_data;
442	card->dev = &pdev->dev;
443
444	mach = pdev->dev.platform_data;
445	ret = snd_soc_fixup_dai_links_platform_name(card,
446						    mach->mach_params.platform);
447	if (ret)
448		return ret;
449
450	snd_soc_card_set_drvdata(card, ctx);
451
452	return devm_snd_soc_register_card(&pdev->dev, card);
453}
454
455static const struct platform_device_id board_ids[] = {
456	{
457		.name = "sof_da7219_mx98373",
458		.driver_data = (kernel_ulong_t)&card_da7219_m98373,
459	},
460	{
461		.name = "sof_da7219_mx98360a",
462		.driver_data = (kernel_ulong_t)&card_da7219_m98360a,
463	},
464	{ }
465};
466MODULE_DEVICE_TABLE(platform, board_ids);
467
468static struct platform_driver audio = {
469	.probe = audio_probe,
470	.driver = {
471		.name = "sof_da7219_max98_360a_373",
472		.pm = &snd_soc_pm_ops,
473	},
474	.id_table = board_ids,
475};
476module_platform_driver(audio)
477
478/* Module information */
479MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver");
480MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
481MODULE_LICENSE("GPL v2");
482MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
483