xref: /openbmc/linux/sound/soc/intel/boards/cml_rt1011_rt5682.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: GPL-2.0-only
217fe95d6SNaveen Manohar // Copyright(c) 2019 Intel Corporation.
317fe95d6SNaveen Manohar 
417fe95d6SNaveen Manohar /*
517fe95d6SNaveen Manohar  * Intel Cometlake I2S Machine driver for RT1011 + RT5682 codec
617fe95d6SNaveen Manohar  */
717fe95d6SNaveen Manohar 
817fe95d6SNaveen Manohar #include <linux/input.h>
917fe95d6SNaveen Manohar #include <linux/module.h>
1017fe95d6SNaveen Manohar #include <linux/platform_device.h>
1117fe95d6SNaveen Manohar #include <linux/clk.h>
1217fe95d6SNaveen Manohar #include <linux/dmi.h>
1317fe95d6SNaveen Manohar #include <linux/slab.h>
1417fe95d6SNaveen Manohar #include <linux/acpi.h>
1517fe95d6SNaveen Manohar #include <sound/core.h>
1617fe95d6SNaveen Manohar #include <sound/jack.h>
1717fe95d6SNaveen Manohar #include <sound/pcm.h>
1817fe95d6SNaveen Manohar #include <sound/pcm_params.h>
1917fe95d6SNaveen Manohar #include <sound/soc.h>
2017fe95d6SNaveen Manohar #include <sound/rt5682.h>
2117fe95d6SNaveen Manohar #include <sound/soc-acpi.h>
2217fe95d6SNaveen Manohar #include "../../codecs/rt1011.h"
2317fe95d6SNaveen Manohar #include "../../codecs/rt5682.h"
2417fe95d6SNaveen Manohar #include "../../codecs/hdac_hdmi.h"
2517fe95d6SNaveen Manohar #include "hda_dsp_common.h"
2617fe95d6SNaveen Manohar 
2717fe95d6SNaveen Manohar /* The platform clock outputs 24Mhz clock to codec as I2S MCLK */
2817fe95d6SNaveen Manohar #define CML_PLAT_CLK	24000000
2917fe95d6SNaveen Manohar #define CML_RT1011_CODEC_DAI "rt1011-aif"
3017fe95d6SNaveen Manohar #define CML_RT5682_CODEC_DAI "rt5682-aif1"
3117fe95d6SNaveen Manohar #define NAME_SIZE 32
3217fe95d6SNaveen Manohar 
33629ba12eSMac Chiang #define SOF_RT1011_SPEAKER_WL		BIT(0)
34629ba12eSMac Chiang #define SOF_RT1011_SPEAKER_WR		BIT(1)
35629ba12eSMac Chiang #define SOF_RT1011_SPEAKER_TL		BIT(2)
36629ba12eSMac Chiang #define SOF_RT1011_SPEAKER_TR		BIT(3)
37629ba12eSMac Chiang 
38629ba12eSMac Chiang /* Default: Woofer speakers  */
39629ba12eSMac Chiang static unsigned long sof_rt1011_quirk = SOF_RT1011_SPEAKER_WL |
40629ba12eSMac Chiang 					SOF_RT1011_SPEAKER_WR;
41629ba12eSMac Chiang 
sof_rt1011_quirk_cb(const struct dmi_system_id * id)42629ba12eSMac Chiang static int sof_rt1011_quirk_cb(const struct dmi_system_id *id)
43629ba12eSMac Chiang {
44629ba12eSMac Chiang 	sof_rt1011_quirk = (unsigned long)id->driver_data;
45629ba12eSMac Chiang 	return 1;
46629ba12eSMac Chiang }
47629ba12eSMac Chiang 
48629ba12eSMac Chiang static const struct dmi_system_id sof_rt1011_quirk_table[] = {
49629ba12eSMac Chiang 	{
50629ba12eSMac Chiang 		.callback = sof_rt1011_quirk_cb,
51629ba12eSMac Chiang 		.matches = {
52629ba12eSMac Chiang 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
53629ba12eSMac Chiang 			DMI_MATCH(DMI_PRODUCT_NAME, "Helios"),
54629ba12eSMac Chiang 	},
55629ba12eSMac Chiang 		.driver_data = (void *)(SOF_RT1011_SPEAKER_WL | SOF_RT1011_SPEAKER_WR |
56629ba12eSMac Chiang 					SOF_RT1011_SPEAKER_TL | SOF_RT1011_SPEAKER_TR),
57629ba12eSMac Chiang 	},
58629ba12eSMac Chiang 	{
59629ba12eSMac Chiang 	}
60629ba12eSMac Chiang };
61629ba12eSMac Chiang 
6217fe95d6SNaveen Manohar static struct snd_soc_jack hdmi_jack[3];
6317fe95d6SNaveen Manohar 
6417fe95d6SNaveen Manohar struct hdmi_pcm {
6517fe95d6SNaveen Manohar 	struct list_head head;
6617fe95d6SNaveen Manohar 	struct snd_soc_dai *codec_dai;
6717fe95d6SNaveen Manohar 	int device;
6817fe95d6SNaveen Manohar };
6917fe95d6SNaveen Manohar 
7017fe95d6SNaveen Manohar struct card_private {
7117fe95d6SNaveen Manohar 	char codec_name[SND_ACPI_I2C_ID_LEN];
7217fe95d6SNaveen Manohar 	struct snd_soc_jack headset;
7317fe95d6SNaveen Manohar 	struct list_head hdmi_pcm_list;
7417fe95d6SNaveen Manohar 	bool common_hdmi_codec_drv;
7517fe95d6SNaveen Manohar };
7617fe95d6SNaveen Manohar 
7717fe95d6SNaveen Manohar static const struct snd_kcontrol_new cml_controls[] = {
7817fe95d6SNaveen Manohar 	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
7917fe95d6SNaveen Manohar 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
8017fe95d6SNaveen Manohar 	SOC_DAPM_PIN_SWITCH("WL Ext Spk"),
8117fe95d6SNaveen Manohar 	SOC_DAPM_PIN_SWITCH("WR Ext Spk"),
8217fe95d6SNaveen Manohar };
8317fe95d6SNaveen Manohar 
84629ba12eSMac Chiang static const struct snd_kcontrol_new cml_rt1011_tt_controls[] = {
85629ba12eSMac Chiang 	SOC_DAPM_PIN_SWITCH("TL Ext Spk"),
86629ba12eSMac Chiang 	SOC_DAPM_PIN_SWITCH("TR Ext Spk"),
87629ba12eSMac Chiang };
88629ba12eSMac Chiang 
8917fe95d6SNaveen Manohar static const struct snd_soc_dapm_widget cml_rt1011_rt5682_widgets[] = {
9017fe95d6SNaveen Manohar 	SND_SOC_DAPM_SPK("WL Ext Spk", NULL),
9117fe95d6SNaveen Manohar 	SND_SOC_DAPM_SPK("WR Ext Spk", NULL),
9217fe95d6SNaveen Manohar 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
9317fe95d6SNaveen Manohar 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
9417fe95d6SNaveen Manohar 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
9517fe95d6SNaveen Manohar };
9617fe95d6SNaveen Manohar 
97629ba12eSMac Chiang static const struct snd_soc_dapm_widget cml_rt1011_tt_widgets[] = {
98629ba12eSMac Chiang 	SND_SOC_DAPM_SPK("TL Ext Spk", NULL),
99629ba12eSMac Chiang 	SND_SOC_DAPM_SPK("TR Ext Spk", NULL),
100629ba12eSMac Chiang };
101629ba12eSMac Chiang 
10217fe95d6SNaveen Manohar static const struct snd_soc_dapm_route cml_rt1011_rt5682_map[] = {
103629ba12eSMac Chiang 	/*WL/WR speaker*/
10417fe95d6SNaveen Manohar 	{"WL Ext Spk", NULL, "WL SPO"},
10517fe95d6SNaveen Manohar 	{"WR Ext Spk", NULL, "WR SPO"},
10617fe95d6SNaveen Manohar 
10717fe95d6SNaveen Manohar 	/* HP jack connectors - unknown if we have jack detection */
10817fe95d6SNaveen Manohar 	{ "Headphone Jack", NULL, "HPOL" },
10917fe95d6SNaveen Manohar 	{ "Headphone Jack", NULL, "HPOR" },
11017fe95d6SNaveen Manohar 
11117fe95d6SNaveen Manohar 	/* other jacks */
11217fe95d6SNaveen Manohar 	{ "IN1P", NULL, "Headset Mic" },
11317fe95d6SNaveen Manohar 
11417fe95d6SNaveen Manohar 	/* DMIC */
11517fe95d6SNaveen Manohar 	{"DMic", NULL, "SoC DMIC"},
11617fe95d6SNaveen Manohar };
11717fe95d6SNaveen Manohar 
118629ba12eSMac Chiang static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = {
119629ba12eSMac Chiang 	/*TL/TR speaker*/
120629ba12eSMac Chiang 	{"TL Ext Spk", NULL, "TL SPO" },
121629ba12eSMac Chiang 	{"TR Ext Spk", NULL, "TR SPO" },
122629ba12eSMac Chiang };
123629ba12eSMac Chiang 
124*77a036e8SPierre-Louis Bossart static struct snd_soc_jack_pin jack_pins[] = {
125*77a036e8SPierre-Louis Bossart 	{
126*77a036e8SPierre-Louis Bossart 		.pin    = "Headphone Jack",
127*77a036e8SPierre-Louis Bossart 		.mask   = SND_JACK_HEADPHONE,
128*77a036e8SPierre-Louis Bossart 	},
129*77a036e8SPierre-Louis Bossart 	{
130*77a036e8SPierre-Louis Bossart 		.pin    = "Headset Mic",
131*77a036e8SPierre-Louis Bossart 		.mask   = SND_JACK_MICROPHONE,
132*77a036e8SPierre-Louis Bossart 	},
133*77a036e8SPierre-Louis Bossart };
134*77a036e8SPierre-Louis Bossart 
cml_rt5682_codec_init(struct snd_soc_pcm_runtime * rtd)13517fe95d6SNaveen Manohar static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
13617fe95d6SNaveen Manohar {
13717fe95d6SNaveen Manohar 	struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
1380d1571c1SKuninori Morimoto 	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
13917fe95d6SNaveen Manohar 	struct snd_soc_jack *jack;
14017fe95d6SNaveen Manohar 	int ret;
14117fe95d6SNaveen Manohar 
14217fe95d6SNaveen Manohar 	/* need to enable ASRC function for 24MHz mclk rate */
14317fe95d6SNaveen Manohar 	rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
14417fe95d6SNaveen Manohar 					RT5682_AD_STEREO1_FILTER,
14517fe95d6SNaveen Manohar 					RT5682_CLK_SEL_I2S1_ASRC);
14617fe95d6SNaveen Manohar 
14717fe95d6SNaveen Manohar 	/*
14817fe95d6SNaveen Manohar 	 * Headset buttons map to the google Reference headset.
14917fe95d6SNaveen Manohar 	 * These can be configured by userspace.
15017fe95d6SNaveen Manohar 	 */
151*77a036e8SPierre-Louis Bossart 	ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
15217fe95d6SNaveen Manohar 					 SND_JACK_HEADSET | SND_JACK_BTN_0 |
15317fe95d6SNaveen Manohar 					 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
15417fe95d6SNaveen Manohar 					 SND_JACK_BTN_3,
155*77a036e8SPierre-Louis Bossart 					 &ctx->headset,
156*77a036e8SPierre-Louis Bossart 					 jack_pins,
157*77a036e8SPierre-Louis Bossart 					 ARRAY_SIZE(jack_pins));
15817fe95d6SNaveen Manohar 	if (ret) {
15917fe95d6SNaveen Manohar 		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
16017fe95d6SNaveen Manohar 		return ret;
16117fe95d6SNaveen Manohar 	}
16217fe95d6SNaveen Manohar 
16317fe95d6SNaveen Manohar 	jack = &ctx->headset;
16417fe95d6SNaveen Manohar 
16517fe95d6SNaveen Manohar 	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
16617fe95d6SNaveen Manohar 	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
16717fe95d6SNaveen Manohar 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
16817fe95d6SNaveen Manohar 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
16917fe95d6SNaveen Manohar 	ret = snd_soc_component_set_jack(component, jack, NULL);
17017fe95d6SNaveen Manohar 	if (ret)
17117fe95d6SNaveen Manohar 		dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
17217fe95d6SNaveen Manohar 
17317fe95d6SNaveen Manohar 	return ret;
17417fe95d6SNaveen Manohar };
17517fe95d6SNaveen Manohar 
cml_rt5682_codec_exit(struct snd_soc_pcm_runtime * rtd)1764fcc922cSFred Oh static void cml_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd)
1774fcc922cSFred Oh {
1784fcc922cSFred Oh 	struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
1794fcc922cSFred Oh 
1804fcc922cSFred Oh 	snd_soc_component_set_jack(component, NULL, NULL);
1814fcc922cSFred Oh }
1824fcc922cSFred Oh 
cml_rt1011_spk_init(struct snd_soc_pcm_runtime * rtd)183629ba12eSMac Chiang static int cml_rt1011_spk_init(struct snd_soc_pcm_runtime *rtd)
184629ba12eSMac Chiang {
185629ba12eSMac Chiang 	int ret = 0;
186629ba12eSMac Chiang 	struct snd_soc_card *card = rtd->card;
187629ba12eSMac Chiang 
188629ba12eSMac Chiang 	if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
189629ba12eSMac Chiang 				SOF_RT1011_SPEAKER_TR)) {
190629ba12eSMac Chiang 
191629ba12eSMac Chiang 		ret = snd_soc_add_card_controls(card, cml_rt1011_tt_controls,
192629ba12eSMac Chiang 					ARRAY_SIZE(cml_rt1011_tt_controls));
193629ba12eSMac Chiang 		if (ret)
194629ba12eSMac Chiang 			return ret;
195629ba12eSMac Chiang 
196629ba12eSMac Chiang 		ret = snd_soc_dapm_new_controls(&card->dapm,
197629ba12eSMac Chiang 					cml_rt1011_tt_widgets,
198629ba12eSMac Chiang 					ARRAY_SIZE(cml_rt1011_tt_widgets));
199629ba12eSMac Chiang 		if (ret)
200629ba12eSMac Chiang 			return ret;
201629ba12eSMac Chiang 
202629ba12eSMac Chiang 		ret = snd_soc_dapm_add_routes(&card->dapm, cml_rt1011_tt_map,
203629ba12eSMac Chiang 					ARRAY_SIZE(cml_rt1011_tt_map));
204629ba12eSMac Chiang 
205629ba12eSMac Chiang 		if (ret)
206629ba12eSMac Chiang 			return ret;
207629ba12eSMac Chiang 	}
208629ba12eSMac Chiang 
209629ba12eSMac Chiang 	return ret;
210629ba12eSMac Chiang }
211629ba12eSMac Chiang 
cml_rt5682_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)21217fe95d6SNaveen Manohar static int cml_rt5682_hw_params(struct snd_pcm_substream *substream,
21317fe95d6SNaveen Manohar 				struct snd_pcm_hw_params *params)
21417fe95d6SNaveen Manohar {
2152207b93bSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
2160d1571c1SKuninori Morimoto 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
21717fe95d6SNaveen Manohar 	int clk_id, clk_freq, pll_out, ret;
21817fe95d6SNaveen Manohar 
21917fe95d6SNaveen Manohar 	clk_id = RT5682_PLL1_S_MCLK;
22017fe95d6SNaveen Manohar 	clk_freq = CML_PLAT_CLK;
22117fe95d6SNaveen Manohar 
22217fe95d6SNaveen Manohar 	pll_out = params_rate(params) * 512;
22317fe95d6SNaveen Manohar 
22417fe95d6SNaveen Manohar 	ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
22517fe95d6SNaveen Manohar 	if (ret < 0)
22617fe95d6SNaveen Manohar 		dev_warn(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret);
22717fe95d6SNaveen Manohar 
22817fe95d6SNaveen Manohar 	/* Configure sysclk for codec */
22917fe95d6SNaveen Manohar 	ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
23017fe95d6SNaveen Manohar 				     pll_out, SND_SOC_CLOCK_IN);
23117fe95d6SNaveen Manohar 	if (ret < 0)
23217fe95d6SNaveen Manohar 		dev_warn(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
23317fe95d6SNaveen Manohar 
23417fe95d6SNaveen Manohar 	/*
23517fe95d6SNaveen Manohar 	 * slot_width should be equal or large than data length, set them
23617fe95d6SNaveen Manohar 	 * be the same
23717fe95d6SNaveen Manohar 	 */
23817fe95d6SNaveen Manohar 	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2,
23917fe95d6SNaveen Manohar 				       params_width(params));
24017fe95d6SNaveen Manohar 	if (ret < 0)
24117fe95d6SNaveen Manohar 		dev_warn(rtd->dev, "set TDM slot err:%d\n", ret);
24217fe95d6SNaveen Manohar 	return ret;
24317fe95d6SNaveen Manohar }
24417fe95d6SNaveen Manohar 
cml_rt1011_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)24517fe95d6SNaveen Manohar static int cml_rt1011_hw_params(struct snd_pcm_substream *substream,
24617fe95d6SNaveen Manohar 				struct snd_pcm_hw_params *params)
24717fe95d6SNaveen Manohar {
2482207b93bSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
24917fe95d6SNaveen Manohar 	struct snd_soc_dai *codec_dai;
25017fe95d6SNaveen Manohar 	struct snd_soc_card *card = rtd->card;
25117fe95d6SNaveen Manohar 	int srate, i, ret = 0;
25217fe95d6SNaveen Manohar 
25317fe95d6SNaveen Manohar 	srate = params_rate(params);
25417fe95d6SNaveen Manohar 
2555dd1677cSKuninori Morimoto 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
25617fe95d6SNaveen Manohar 
25717fe95d6SNaveen Manohar 		/* 100 Fs to drive 24 bit data */
25817fe95d6SNaveen Manohar 		ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK,
25917fe95d6SNaveen Manohar 					  100 * srate, 256 * srate);
26017fe95d6SNaveen Manohar 		if (ret < 0) {
26117fe95d6SNaveen Manohar 			dev_err(card->dev, "codec_dai clock not set\n");
26217fe95d6SNaveen Manohar 			return ret;
26317fe95d6SNaveen Manohar 		}
26417fe95d6SNaveen Manohar 
26517fe95d6SNaveen Manohar 		ret = snd_soc_dai_set_sysclk(codec_dai,
26617fe95d6SNaveen Manohar 					     RT1011_FS_SYS_PRE_S_PLL1,
26717fe95d6SNaveen Manohar 					     256 * srate, SND_SOC_CLOCK_IN);
26817fe95d6SNaveen Manohar 		if (ret < 0) {
26917fe95d6SNaveen Manohar 			dev_err(card->dev, "codec_dai clock not set\n");
27017fe95d6SNaveen Manohar 			return ret;
27117fe95d6SNaveen Manohar 		}
27217fe95d6SNaveen Manohar 
27317fe95d6SNaveen Manohar 		/*
27417fe95d6SNaveen Manohar 		 * Codec TDM is configured as 24 bit capture/ playback.
27517fe95d6SNaveen Manohar 		 * 2 CH PB is done over 4 codecs - 2 Woofers and 2 Tweeters.
27617fe95d6SNaveen Manohar 		 * The Left woofer and tweeter plays the Left playback data
27717fe95d6SNaveen Manohar 		 * and  similar by the Right.
27817fe95d6SNaveen Manohar 		 * Hence 2 codecs (1 T and 1 W pair) share same Rx slot.
27917fe95d6SNaveen Manohar 		 * The feedback is captured for each codec individually.
28017fe95d6SNaveen Manohar 		 * Hence all 4 codecs use 1 Tx slot each for feedback.
28117fe95d6SNaveen Manohar 		 */
282629ba12eSMac Chiang 		if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_WL |
283629ba12eSMac Chiang 					SOF_RT1011_SPEAKER_WR)) {
28417fe95d6SNaveen Manohar 			if (!strcmp(codec_dai->component->name, "i2c-10EC1011:00")) {
28517fe95d6SNaveen Manohar 				ret = snd_soc_dai_set_tdm_slot(codec_dai,
28617fe95d6SNaveen Manohar 							       0x4, 0x1, 4, 24);
28717fe95d6SNaveen Manohar 				if (ret < 0)
28817fe95d6SNaveen Manohar 					break;
28917fe95d6SNaveen Manohar 			}
290629ba12eSMac Chiang 
29117fe95d6SNaveen Manohar 			if (!strcmp(codec_dai->component->name, "i2c-10EC1011:01")) {
29217fe95d6SNaveen Manohar 				ret = snd_soc_dai_set_tdm_slot(codec_dai,
29317fe95d6SNaveen Manohar 							       0x8, 0x2, 4, 24);
29417fe95d6SNaveen Manohar 				if (ret < 0)
29517fe95d6SNaveen Manohar 					break;
29617fe95d6SNaveen Manohar 			}
297629ba12eSMac Chiang 		}
298629ba12eSMac Chiang 
299629ba12eSMac Chiang 		if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
300629ba12eSMac Chiang 					SOF_RT1011_SPEAKER_TR)) {
301629ba12eSMac Chiang 			if (!strcmp(codec_dai->component->name, "i2c-10EC1011:02")) {
302629ba12eSMac Chiang 				ret = snd_soc_dai_set_tdm_slot(codec_dai,
303629ba12eSMac Chiang 							       0x1, 0x1, 4, 24);
304629ba12eSMac Chiang 				if (ret < 0)
305629ba12eSMac Chiang 					break;
306629ba12eSMac Chiang 			}
307629ba12eSMac Chiang 
30817fe95d6SNaveen Manohar 			if (!strcmp(codec_dai->component->name, "i2c-10EC1011:03")) {
30917fe95d6SNaveen Manohar 				ret = snd_soc_dai_set_tdm_slot(codec_dai,
31017fe95d6SNaveen Manohar 							       0x2, 0x2, 4, 24);
31117fe95d6SNaveen Manohar 				if (ret < 0)
31217fe95d6SNaveen Manohar 					break;
31317fe95d6SNaveen Manohar 			}
31417fe95d6SNaveen Manohar 		}
315629ba12eSMac Chiang 	}
31617fe95d6SNaveen Manohar 	if (ret < 0)
31717fe95d6SNaveen Manohar 		dev_err(rtd->dev,
31817fe95d6SNaveen Manohar 			"set codec TDM slot for %s failed with error %d\n",
31917fe95d6SNaveen Manohar 			codec_dai->component->name, ret);
32017fe95d6SNaveen Manohar 	return ret;
32117fe95d6SNaveen Manohar }
32217fe95d6SNaveen Manohar 
32317fe95d6SNaveen Manohar static struct snd_soc_ops cml_rt5682_ops = {
32417fe95d6SNaveen Manohar 	.hw_params = cml_rt5682_hw_params,
32517fe95d6SNaveen Manohar };
32617fe95d6SNaveen Manohar 
32717fe95d6SNaveen Manohar static const struct snd_soc_ops cml_rt1011_ops = {
32817fe95d6SNaveen Manohar 	.hw_params = cml_rt1011_hw_params,
32917fe95d6SNaveen Manohar };
33017fe95d6SNaveen Manohar 
sof_card_late_probe(struct snd_soc_card * card)33117fe95d6SNaveen Manohar static int sof_card_late_probe(struct snd_soc_card *card)
33217fe95d6SNaveen Manohar {
33317fe95d6SNaveen Manohar 	struct card_private *ctx = snd_soc_card_get_drvdata(card);
33417fe95d6SNaveen Manohar 	struct snd_soc_component *component = NULL;
33517fe95d6SNaveen Manohar 	char jack_name[NAME_SIZE];
33617fe95d6SNaveen Manohar 	struct hdmi_pcm *pcm;
33717fe95d6SNaveen Manohar 	int ret, i = 0;
33817fe95d6SNaveen Manohar 
33998ff5c26SGuennadi Liakhovetski 	if (list_empty(&ctx->hdmi_pcm_list))
34098ff5c26SGuennadi Liakhovetski 		return -EINVAL;
34198ff5c26SGuennadi Liakhovetski 
34298ff5c26SGuennadi Liakhovetski 	if (ctx->common_hdmi_codec_drv) {
34317fe95d6SNaveen Manohar 		pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm,
34417fe95d6SNaveen Manohar 				       head);
34517fe95d6SNaveen Manohar 		component = pcm->codec_dai->component;
34617fe95d6SNaveen Manohar 		return hda_dsp_hdmi_build_controls(card, component);
34798ff5c26SGuennadi Liakhovetski 	}
34817fe95d6SNaveen Manohar 
34917fe95d6SNaveen Manohar 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
35017fe95d6SNaveen Manohar 		component = pcm->codec_dai->component;
35117fe95d6SNaveen Manohar 		snprintf(jack_name, sizeof(jack_name),
35217fe95d6SNaveen Manohar 			 "HDMI/DP, pcm=%d Jack", pcm->device);
35317fe95d6SNaveen Manohar 		ret = snd_soc_card_jack_new(card, jack_name,
35419aed2d6SAkihiko Odaki 					    SND_JACK_AVOUT, &hdmi_jack[i]);
35517fe95d6SNaveen Manohar 		if (ret)
35617fe95d6SNaveen Manohar 			return ret;
35717fe95d6SNaveen Manohar 
35817fe95d6SNaveen Manohar 		ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
35917fe95d6SNaveen Manohar 					  &hdmi_jack[i]);
36017fe95d6SNaveen Manohar 		if (ret < 0)
36117fe95d6SNaveen Manohar 			return ret;
36217fe95d6SNaveen Manohar 
36317fe95d6SNaveen Manohar 		i++;
36417fe95d6SNaveen Manohar 	}
36517fe95d6SNaveen Manohar 
36617fe95d6SNaveen Manohar 	return hdac_hdmi_jack_port_init(component, &card->dapm);
36717fe95d6SNaveen Manohar }
36817fe95d6SNaveen Manohar 
hdmi_init(struct snd_soc_pcm_runtime * rtd)36917fe95d6SNaveen Manohar static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
37017fe95d6SNaveen Manohar {
37117fe95d6SNaveen Manohar 	struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
3720d1571c1SKuninori Morimoto 	struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
37317fe95d6SNaveen Manohar 	struct hdmi_pcm *pcm;
37417fe95d6SNaveen Manohar 
37517fe95d6SNaveen Manohar 	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
37617fe95d6SNaveen Manohar 	if (!pcm)
37717fe95d6SNaveen Manohar 		return -ENOMEM;
37817fe95d6SNaveen Manohar 
37917fe95d6SNaveen Manohar 	pcm->device = dai->id;
38017fe95d6SNaveen Manohar 	pcm->codec_dai = dai;
38117fe95d6SNaveen Manohar 
38217fe95d6SNaveen Manohar 	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
38317fe95d6SNaveen Manohar 
38417fe95d6SNaveen Manohar 	return 0;
38517fe95d6SNaveen Manohar }
38617fe95d6SNaveen Manohar 
38717fe95d6SNaveen Manohar /* Cometlake digital audio interface glue - connects codec <--> CPU */
38817fe95d6SNaveen Manohar 
38917fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(ssp0_pin,
39017fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
39117fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(ssp0_codec,
39217fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00",
39317fe95d6SNaveen Manohar 				CML_RT5682_CODEC_DAI)));
39417fe95d6SNaveen Manohar 
39517fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(ssp1_pin,
39617fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
3978a473c39SFred Oh SND_SOC_DAILINK_DEF(ssp1_codec_2spk,
39817fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(
39917fe95d6SNaveen Manohar 	/* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI),
400629ba12eSMac Chiang 	/* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI)));
4018a473c39SFred Oh SND_SOC_DAILINK_DEF(ssp1_codec_4spk,
4028a473c39SFred Oh 	DAILINK_COMP_ARRAY(
4038a473c39SFred Oh 	/* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI),
4048a473c39SFred Oh 	/* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI),
4058a473c39SFred Oh 	/* TL */ COMP_CODEC("i2c-10EC1011:02", CML_RT1011_CODEC_DAI),
4068a473c39SFred Oh 	/* TR */ COMP_CODEC("i2c-10EC1011:03", CML_RT1011_CODEC_DAI)));
4078a473c39SFred Oh 
40817fe95d6SNaveen Manohar 
40917fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(dmic_pin,
41017fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
41117fe95d6SNaveen Manohar 
41217fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(dmic16k_pin,
41317fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin")));
41417fe95d6SNaveen Manohar 
41517fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(dmic_codec,
41617fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
41717fe95d6SNaveen Manohar 
41817fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(idisp1_pin,
41917fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
42017fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(idisp1_codec,
42117fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
42217fe95d6SNaveen Manohar 
42317fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(idisp2_pin,
42417fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
42517fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(idisp2_codec,
42617fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
42717fe95d6SNaveen Manohar 
42817fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(idisp3_pin,
42917fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
43017fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(idisp3_codec,
43117fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
43217fe95d6SNaveen Manohar 
43317fe95d6SNaveen Manohar SND_SOC_DAILINK_DEF(platform,
43417fe95d6SNaveen Manohar 	DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
43517fe95d6SNaveen Manohar 
43617fe95d6SNaveen Manohar static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = {
43717fe95d6SNaveen Manohar 	/* Back End DAI links */
43817fe95d6SNaveen Manohar 	{
43917fe95d6SNaveen Manohar 		/* SSP0 - Codec */
44017fe95d6SNaveen Manohar 		.name = "SSP0-Codec",
44117fe95d6SNaveen Manohar 		.id = 0,
44217fe95d6SNaveen Manohar 		.init = cml_rt5682_codec_init,
4434fcc922cSFred Oh 		.exit = cml_rt5682_codec_exit,
44417fe95d6SNaveen Manohar 		.ignore_pmdown_time = 1,
44517fe95d6SNaveen Manohar 		.ops = &cml_rt5682_ops,
44617fe95d6SNaveen Manohar 		.dpcm_playback = 1,
44717fe95d6SNaveen Manohar 		.dpcm_capture = 1,
44817fe95d6SNaveen Manohar 		.no_pcm = 1,
44917fe95d6SNaveen Manohar 		SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform),
45017fe95d6SNaveen Manohar 	},
45117fe95d6SNaveen Manohar 	{
45217fe95d6SNaveen Manohar 		.name = "dmic01",
45317fe95d6SNaveen Manohar 		.id = 1,
45417fe95d6SNaveen Manohar 		.ignore_suspend = 1,
45517fe95d6SNaveen Manohar 		.dpcm_capture = 1,
45617fe95d6SNaveen Manohar 		.no_pcm = 1,
45717fe95d6SNaveen Manohar 		SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
45817fe95d6SNaveen Manohar 	},
45917fe95d6SNaveen Manohar 	{
46017fe95d6SNaveen Manohar 		.name = "dmic16k",
46117fe95d6SNaveen Manohar 		.id = 2,
46217fe95d6SNaveen Manohar 		.ignore_suspend = 1,
46317fe95d6SNaveen Manohar 		.dpcm_capture = 1,
46417fe95d6SNaveen Manohar 		.no_pcm = 1,
46517fe95d6SNaveen Manohar 		SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform),
46617fe95d6SNaveen Manohar 	},
46717fe95d6SNaveen Manohar 	{
46817fe95d6SNaveen Manohar 		.name = "iDisp1",
46917fe95d6SNaveen Manohar 		.id = 3,
47017fe95d6SNaveen Manohar 		.init = hdmi_init,
47117fe95d6SNaveen Manohar 		.dpcm_playback = 1,
47217fe95d6SNaveen Manohar 		.no_pcm = 1,
47317fe95d6SNaveen Manohar 		SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform),
47417fe95d6SNaveen Manohar 	},
47517fe95d6SNaveen Manohar 	{
47617fe95d6SNaveen Manohar 		.name = "iDisp2",
47717fe95d6SNaveen Manohar 		.id = 4,
47817fe95d6SNaveen Manohar 		.init = hdmi_init,
47917fe95d6SNaveen Manohar 		.dpcm_playback = 1,
48017fe95d6SNaveen Manohar 		.no_pcm = 1,
48117fe95d6SNaveen Manohar 		SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform),
48217fe95d6SNaveen Manohar 	},
48317fe95d6SNaveen Manohar 	{
48417fe95d6SNaveen Manohar 		.name = "iDisp3",
48517fe95d6SNaveen Manohar 		.id = 5,
48617fe95d6SNaveen Manohar 		.init = hdmi_init,
48717fe95d6SNaveen Manohar 		.dpcm_playback = 1,
48817fe95d6SNaveen Manohar 		.no_pcm = 1,
48917fe95d6SNaveen Manohar 		SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform),
49017fe95d6SNaveen Manohar 	},
49117fe95d6SNaveen Manohar 	{
49217fe95d6SNaveen Manohar 		/*
49317fe95d6SNaveen Manohar 		 * SSP1 - Codec : added to end of list ensuring
49417fe95d6SNaveen Manohar 		 * reuse of common topologies for other end points
49517fe95d6SNaveen Manohar 		 * and changing only SSP1's codec
49617fe95d6SNaveen Manohar 		 */
49717fe95d6SNaveen Manohar 		.name = "SSP1-Codec",
49817fe95d6SNaveen Manohar 		.id = 6,
49917fe95d6SNaveen Manohar 		.dpcm_playback = 1,
50017fe95d6SNaveen Manohar 		.dpcm_capture = 1, /* Capture stream provides Feedback */
50117fe95d6SNaveen Manohar 		.no_pcm = 1,
502629ba12eSMac Chiang 		.init = cml_rt1011_spk_init,
50317fe95d6SNaveen Manohar 		.ops = &cml_rt1011_ops,
5048a473c39SFred Oh 		SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec_2spk, platform),
50517fe95d6SNaveen Manohar 	},
50617fe95d6SNaveen Manohar };
50717fe95d6SNaveen Manohar 
50817fe95d6SNaveen Manohar static struct snd_soc_codec_conf rt1011_conf[] = {
50917fe95d6SNaveen Manohar 	{
5105610b90eSPierre-Louis Bossart 		.dlc = COMP_CODEC_CONF("i2c-10EC1011:00"),
51117fe95d6SNaveen Manohar 		.name_prefix = "WL",
51217fe95d6SNaveen Manohar 	},
51317fe95d6SNaveen Manohar 	{
5145610b90eSPierre-Louis Bossart 		.dlc = COMP_CODEC_CONF("i2c-10EC1011:01"),
51517fe95d6SNaveen Manohar 		.name_prefix = "WR",
51617fe95d6SNaveen Manohar 	},
5178a473c39SFred Oh 	/* single configuration structure for 2 and 4 channels */
5188a473c39SFred Oh 	{
5198a473c39SFred Oh 		.dlc = COMP_CODEC_CONF("i2c-10EC1011:02"),
5208a473c39SFred Oh 		.name_prefix = "TL",
5218a473c39SFred Oh 	},
5228a473c39SFred Oh 	{
5238a473c39SFred Oh 		.dlc = COMP_CODEC_CONF("i2c-10EC1011:03"),
5248a473c39SFred Oh 		.name_prefix = "TR",
5258a473c39SFred Oh 	},
52617fe95d6SNaveen Manohar };
52717fe95d6SNaveen Manohar 
52817fe95d6SNaveen Manohar /* Cometlake audio machine driver for RT1011 and RT5682 */
52917fe95d6SNaveen Manohar static struct snd_soc_card snd_soc_card_cml = {
53017fe95d6SNaveen Manohar 	.name = "cml_rt1011_rt5682",
53129912092SPierre-Louis Bossart 	.owner = THIS_MODULE,
53217fe95d6SNaveen Manohar 	.dai_link = cml_rt1011_rt5682_dailink,
53317fe95d6SNaveen Manohar 	.num_links = ARRAY_SIZE(cml_rt1011_rt5682_dailink),
53417fe95d6SNaveen Manohar 	.codec_conf = rt1011_conf,
53517fe95d6SNaveen Manohar 	.num_configs = ARRAY_SIZE(rt1011_conf),
53617fe95d6SNaveen Manohar 	.dapm_widgets = cml_rt1011_rt5682_widgets,
53717fe95d6SNaveen Manohar 	.num_dapm_widgets = ARRAY_SIZE(cml_rt1011_rt5682_widgets),
53817fe95d6SNaveen Manohar 	.dapm_routes = cml_rt1011_rt5682_map,
53917fe95d6SNaveen Manohar 	.num_dapm_routes = ARRAY_SIZE(cml_rt1011_rt5682_map),
54017fe95d6SNaveen Manohar 	.controls = cml_controls,
54117fe95d6SNaveen Manohar 	.num_controls = ARRAY_SIZE(cml_controls),
54217fe95d6SNaveen Manohar 	.fully_routed = true,
54317fe95d6SNaveen Manohar 	.late_probe = sof_card_late_probe,
54417fe95d6SNaveen Manohar };
54517fe95d6SNaveen Manohar 
snd_cml_rt1011_probe(struct platform_device * pdev)54617fe95d6SNaveen Manohar static int snd_cml_rt1011_probe(struct platform_device *pdev)
54717fe95d6SNaveen Manohar {
5485ac7c1b2SBard Liao 	struct snd_soc_dai_link *dai_link;
54917fe95d6SNaveen Manohar 	struct card_private *ctx;
55017fe95d6SNaveen Manohar 	struct snd_soc_acpi_mach *mach;
55117fe95d6SNaveen Manohar 	const char *platform_name;
552629ba12eSMac Chiang 	int ret, i;
55317fe95d6SNaveen Manohar 
5542e6529a5SPierre-Louis Bossart 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
55517fe95d6SNaveen Manohar 	if (!ctx)
55617fe95d6SNaveen Manohar 		return -ENOMEM;
55717fe95d6SNaveen Manohar 
55817fe95d6SNaveen Manohar 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
55942432196SGuennadi Liakhovetski 	mach = pdev->dev.platform_data;
56017fe95d6SNaveen Manohar 	snd_soc_card_cml.dev = &pdev->dev;
56117fe95d6SNaveen Manohar 	platform_name = mach->mach_params.platform;
56217fe95d6SNaveen Manohar 
563629ba12eSMac Chiang 	dmi_check_system(sof_rt1011_quirk_table);
564629ba12eSMac Chiang 
565e1a31c09SFred Oh 	dev_dbg(&pdev->dev, "sof_rt1011_quirk = %lx\n", sof_rt1011_quirk);
566629ba12eSMac Chiang 
5678a473c39SFred Oh 	/* when 4 speaker is available, update codec config */
568629ba12eSMac Chiang 	if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL |
569629ba12eSMac Chiang 				SOF_RT1011_SPEAKER_TR)) {
5705ac7c1b2SBard Liao 		for_each_card_prelinks(&snd_soc_card_cml, i, dai_link) {
571ec0d0f63SFred Oh 			if (!strcmp(dai_link->codecs[0].dai_name,
572629ba12eSMac Chiang 				    CML_RT1011_CODEC_DAI)) {
5735ac7c1b2SBard Liao 				dai_link->codecs = ssp1_codec_4spk;
5745ac7c1b2SBard Liao 				dai_link->num_codecs = ARRAY_SIZE(ssp1_codec_4spk);
575629ba12eSMac Chiang 			}
576629ba12eSMac Chiang 		}
577629ba12eSMac Chiang 	}
578629ba12eSMac Chiang 
57917fe95d6SNaveen Manohar 	/* set platform name for each dailink */
58017fe95d6SNaveen Manohar 	ret = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cml,
58117fe95d6SNaveen Manohar 						    platform_name);
58217fe95d6SNaveen Manohar 	if (ret)
58317fe95d6SNaveen Manohar 		return ret;
58417fe95d6SNaveen Manohar 
58517fe95d6SNaveen Manohar 	ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
58617fe95d6SNaveen Manohar 
58717fe95d6SNaveen Manohar 	snd_soc_card_set_drvdata(&snd_soc_card_cml, ctx);
58817fe95d6SNaveen Manohar 
58917fe95d6SNaveen Manohar 	return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cml);
59017fe95d6SNaveen Manohar }
59117fe95d6SNaveen Manohar 
59217fe95d6SNaveen Manohar static struct platform_driver snd_cml_rt1011_rt5682_driver = {
59317fe95d6SNaveen Manohar 	.probe = snd_cml_rt1011_probe,
59417fe95d6SNaveen Manohar 	.driver = {
59517fe95d6SNaveen Manohar 		.name = "cml_rt1011_rt5682",
59617fe95d6SNaveen Manohar 		.pm = &snd_soc_pm_ops,
59717fe95d6SNaveen Manohar 	},
59817fe95d6SNaveen Manohar };
59917fe95d6SNaveen Manohar module_platform_driver(snd_cml_rt1011_rt5682_driver);
60017fe95d6SNaveen Manohar 
60117fe95d6SNaveen Manohar /* Module information */
60217fe95d6SNaveen Manohar MODULE_DESCRIPTION("Cometlake Audio Machine driver - RT1011 and RT5682 in I2S mode");
60317fe95d6SNaveen Manohar MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
60417fe95d6SNaveen Manohar MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
60517fe95d6SNaveen Manohar MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
606629ba12eSMac Chiang MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>");
60717fe95d6SNaveen Manohar MODULE_LICENSE("GPL v2");
60817fe95d6SNaveen Manohar MODULE_ALIAS("platform:cml_rt1011_rt5682");
609f6081af6SPierre-Louis Bossart MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
610