xref: /linux/sound/soc/intel/boards/sof_pcm512x.c (revision f40ed2e8db8d51c0b8155bee3a293528d9f7a956)
1*f40ed2e8SPierre-Louis Bossart // SPDX-License-Identifier: GPL-2.0
2*f40ed2e8SPierre-Louis Bossart // Copyright(c) 2018-2020 Intel Corporation.
3*f40ed2e8SPierre-Louis Bossart 
4*f40ed2e8SPierre-Louis Bossart /*
5*f40ed2e8SPierre-Louis Bossart  * Intel SOF Machine Driver for Intel platforms with TI PCM512x codec,
6*f40ed2e8SPierre-Louis Bossart  * e.g. Up or Up2 with Hifiberry DAC+ HAT
7*f40ed2e8SPierre-Louis Bossart  */
8*f40ed2e8SPierre-Louis Bossart #include <linux/clk.h>
9*f40ed2e8SPierre-Louis Bossart #include <linux/dmi.h>
10*f40ed2e8SPierre-Louis Bossart #include <linux/i2c.h>
11*f40ed2e8SPierre-Louis Bossart #include <linux/input.h>
12*f40ed2e8SPierre-Louis Bossart #include <linux/module.h>
13*f40ed2e8SPierre-Louis Bossart #include <linux/platform_device.h>
14*f40ed2e8SPierre-Louis Bossart #include <linux/types.h>
15*f40ed2e8SPierre-Louis Bossart #include <sound/core.h>
16*f40ed2e8SPierre-Louis Bossart #include <sound/jack.h>
17*f40ed2e8SPierre-Louis Bossart #include <sound/pcm.h>
18*f40ed2e8SPierre-Louis Bossart #include <sound/pcm_params.h>
19*f40ed2e8SPierre-Louis Bossart #include <sound/soc.h>
20*f40ed2e8SPierre-Louis Bossart #include <sound/soc-acpi.h>
21*f40ed2e8SPierre-Louis Bossart #include "../../codecs/pcm512x.h"
22*f40ed2e8SPierre-Louis Bossart #include "../common/soc-intel-quirks.h"
23*f40ed2e8SPierre-Louis Bossart #include "hda_dsp_common.h"
24*f40ed2e8SPierre-Louis Bossart 
25*f40ed2e8SPierre-Louis Bossart #define NAME_SIZE 32
26*f40ed2e8SPierre-Louis Bossart 
27*f40ed2e8SPierre-Louis Bossart #define SOF_PCM512X_SSP_CODEC(quirk)		((quirk) & GENMASK(3, 0))
28*f40ed2e8SPierre-Louis Bossart #define SOF_PCM512X_SSP_CODEC_MASK			(GENMASK(3, 0))
29*f40ed2e8SPierre-Louis Bossart 
30*f40ed2e8SPierre-Louis Bossart /* Default: SSP5 */
31*f40ed2e8SPierre-Louis Bossart static unsigned long sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(5);
32*f40ed2e8SPierre-Louis Bossart 
33*f40ed2e8SPierre-Louis Bossart static bool is_legacy_cpu;
34*f40ed2e8SPierre-Louis Bossart 
35*f40ed2e8SPierre-Louis Bossart struct sof_hdmi_pcm {
36*f40ed2e8SPierre-Louis Bossart 	struct list_head head;
37*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_dai *codec_dai;
38*f40ed2e8SPierre-Louis Bossart 	int device;
39*f40ed2e8SPierre-Louis Bossart };
40*f40ed2e8SPierre-Louis Bossart 
41*f40ed2e8SPierre-Louis Bossart struct sof_card_private {
42*f40ed2e8SPierre-Louis Bossart 	struct list_head hdmi_pcm_list;
43*f40ed2e8SPierre-Louis Bossart };
44*f40ed2e8SPierre-Louis Bossart 
45*f40ed2e8SPierre-Louis Bossart static int sof_pcm512x_quirk_cb(const struct dmi_system_id *id)
46*f40ed2e8SPierre-Louis Bossart {
47*f40ed2e8SPierre-Louis Bossart 	sof_pcm512x_quirk = (unsigned long)id->driver_data;
48*f40ed2e8SPierre-Louis Bossart 	return 1;
49*f40ed2e8SPierre-Louis Bossart }
50*f40ed2e8SPierre-Louis Bossart 
51*f40ed2e8SPierre-Louis Bossart static const struct dmi_system_id sof_pcm512x_quirk_table[] = {
52*f40ed2e8SPierre-Louis Bossart 	{
53*f40ed2e8SPierre-Louis Bossart 		.callback = sof_pcm512x_quirk_cb,
54*f40ed2e8SPierre-Louis Bossart 		.matches = {
55*f40ed2e8SPierre-Louis Bossart 			DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
56*f40ed2e8SPierre-Louis Bossart 			DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"),
57*f40ed2e8SPierre-Louis Bossart 		},
58*f40ed2e8SPierre-Louis Bossart 		.driver_data = (void *)(SOF_PCM512X_SSP_CODEC(2)),
59*f40ed2e8SPierre-Louis Bossart 	},
60*f40ed2e8SPierre-Louis Bossart 	{}
61*f40ed2e8SPierre-Louis Bossart };
62*f40ed2e8SPierre-Louis Bossart 
63*f40ed2e8SPierre-Louis Bossart static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
64*f40ed2e8SPierre-Louis Bossart {
65*f40ed2e8SPierre-Louis Bossart 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
66*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_dai *dai = rtd->codec_dai;
67*f40ed2e8SPierre-Louis Bossart 	struct sof_hdmi_pcm *pcm;
68*f40ed2e8SPierre-Louis Bossart 
69*f40ed2e8SPierre-Louis Bossart 	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
70*f40ed2e8SPierre-Louis Bossart 	if (!pcm)
71*f40ed2e8SPierre-Louis Bossart 		return -ENOMEM;
72*f40ed2e8SPierre-Louis Bossart 
73*f40ed2e8SPierre-Louis Bossart 	/* dai_link id is 1:1 mapped to the PCM device */
74*f40ed2e8SPierre-Louis Bossart 	pcm->device = rtd->dai_link->id;
75*f40ed2e8SPierre-Louis Bossart 	pcm->codec_dai = dai;
76*f40ed2e8SPierre-Louis Bossart 
77*f40ed2e8SPierre-Louis Bossart 	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
78*f40ed2e8SPierre-Louis Bossart 
79*f40ed2e8SPierre-Louis Bossart 	return 0;
80*f40ed2e8SPierre-Louis Bossart }
81*f40ed2e8SPierre-Louis Bossart 
82*f40ed2e8SPierre-Louis Bossart static int sof_pcm512x_codec_init(struct snd_soc_pcm_runtime *rtd)
83*f40ed2e8SPierre-Louis Bossart {
84*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_component *codec = rtd->codec_dai->component;
85*f40ed2e8SPierre-Louis Bossart 
86*f40ed2e8SPierre-Louis Bossart 	snd_soc_component_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
87*f40ed2e8SPierre-Louis Bossart 	snd_soc_component_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
88*f40ed2e8SPierre-Louis Bossart 	snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1,
89*f40ed2e8SPierre-Louis Bossart 				      0x08, 0x08);
90*f40ed2e8SPierre-Louis Bossart 
91*f40ed2e8SPierre-Louis Bossart 	return 0;
92*f40ed2e8SPierre-Louis Bossart }
93*f40ed2e8SPierre-Louis Bossart 
94*f40ed2e8SPierre-Louis Bossart static int aif1_startup(struct snd_pcm_substream *substream)
95*f40ed2e8SPierre-Louis Bossart {
96*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
97*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_component *codec = rtd->codec_dai->component;
98*f40ed2e8SPierre-Louis Bossart 
99*f40ed2e8SPierre-Louis Bossart 	snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1,
100*f40ed2e8SPierre-Louis Bossart 				      0x08, 0x08);
101*f40ed2e8SPierre-Louis Bossart 
102*f40ed2e8SPierre-Louis Bossart 	return 0;
103*f40ed2e8SPierre-Louis Bossart }
104*f40ed2e8SPierre-Louis Bossart 
105*f40ed2e8SPierre-Louis Bossart static void aif1_shutdown(struct snd_pcm_substream *substream)
106*f40ed2e8SPierre-Louis Bossart {
107*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
108*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_component *codec = rtd->codec_dai->component;
109*f40ed2e8SPierre-Louis Bossart 
110*f40ed2e8SPierre-Louis Bossart 	snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1,
111*f40ed2e8SPierre-Louis Bossart 				      0x08, 0x00);
112*f40ed2e8SPierre-Louis Bossart }
113*f40ed2e8SPierre-Louis Bossart 
114*f40ed2e8SPierre-Louis Bossart static const struct snd_soc_ops sof_pcm512x_ops = {
115*f40ed2e8SPierre-Louis Bossart 	.startup = aif1_startup,
116*f40ed2e8SPierre-Louis Bossart 	.shutdown = aif1_shutdown,
117*f40ed2e8SPierre-Louis Bossart };
118*f40ed2e8SPierre-Louis Bossart 
119*f40ed2e8SPierre-Louis Bossart static struct snd_soc_dai_link_component platform_component[] = {
120*f40ed2e8SPierre-Louis Bossart 	{
121*f40ed2e8SPierre-Louis Bossart 		/* name might be overridden during probe */
122*f40ed2e8SPierre-Louis Bossart 		.name = "0000:00:1f.3"
123*f40ed2e8SPierre-Louis Bossart 	}
124*f40ed2e8SPierre-Louis Bossart };
125*f40ed2e8SPierre-Louis Bossart 
126*f40ed2e8SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
127*f40ed2e8SPierre-Louis Bossart static int sof_card_late_probe(struct snd_soc_card *card)
128*f40ed2e8SPierre-Louis Bossart {
129*f40ed2e8SPierre-Louis Bossart 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
130*f40ed2e8SPierre-Louis Bossart 	struct sof_hdmi_pcm *pcm;
131*f40ed2e8SPierre-Louis Bossart 
132*f40ed2e8SPierre-Louis Bossart 	/* HDMI is not supported by SOF on Baytrail/CherryTrail */
133*f40ed2e8SPierre-Louis Bossart 	if (is_legacy_cpu)
134*f40ed2e8SPierre-Louis Bossart 		return 0;
135*f40ed2e8SPierre-Louis Bossart 
136*f40ed2e8SPierre-Louis Bossart 	if (list_empty(&ctx->hdmi_pcm_list))
137*f40ed2e8SPierre-Louis Bossart 		return -EINVAL;
138*f40ed2e8SPierre-Louis Bossart 
139*f40ed2e8SPierre-Louis Bossart 	pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
140*f40ed2e8SPierre-Louis Bossart 
141*f40ed2e8SPierre-Louis Bossart 	return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
142*f40ed2e8SPierre-Louis Bossart }
143*f40ed2e8SPierre-Louis Bossart #else
144*f40ed2e8SPierre-Louis Bossart static int sof_card_late_probe(struct snd_soc_card *card)
145*f40ed2e8SPierre-Louis Bossart {
146*f40ed2e8SPierre-Louis Bossart 	return 0;
147*f40ed2e8SPierre-Louis Bossart }
148*f40ed2e8SPierre-Louis Bossart #endif
149*f40ed2e8SPierre-Louis Bossart 
150*f40ed2e8SPierre-Louis Bossart static const struct snd_kcontrol_new sof_controls[] = {
151*f40ed2e8SPierre-Louis Bossart 	SOC_DAPM_PIN_SWITCH("Ext Spk"),
152*f40ed2e8SPierre-Louis Bossart };
153*f40ed2e8SPierre-Louis Bossart 
154*f40ed2e8SPierre-Louis Bossart static const struct snd_soc_dapm_widget sof_widgets[] = {
155*f40ed2e8SPierre-Louis Bossart 	SND_SOC_DAPM_SPK("Ext Spk", NULL),
156*f40ed2e8SPierre-Louis Bossart };
157*f40ed2e8SPierre-Louis Bossart 
158*f40ed2e8SPierre-Louis Bossart static const struct snd_soc_dapm_widget dmic_widgets[] = {
159*f40ed2e8SPierre-Louis Bossart 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
160*f40ed2e8SPierre-Louis Bossart };
161*f40ed2e8SPierre-Louis Bossart 
162*f40ed2e8SPierre-Louis Bossart static const struct snd_soc_dapm_route sof_map[] = {
163*f40ed2e8SPierre-Louis Bossart 	/* Speaker */
164*f40ed2e8SPierre-Louis Bossart 	{"Ext Spk", NULL, "OUTR"},
165*f40ed2e8SPierre-Louis Bossart 	{"Ext Spk", NULL, "OUTL"},
166*f40ed2e8SPierre-Louis Bossart };
167*f40ed2e8SPierre-Louis Bossart 
168*f40ed2e8SPierre-Louis Bossart static const struct snd_soc_dapm_route dmic_map[] = {
169*f40ed2e8SPierre-Louis Bossart 	/* digital mics */
170*f40ed2e8SPierre-Louis Bossart 	{"DMic", NULL, "SoC DMIC"},
171*f40ed2e8SPierre-Louis Bossart };
172*f40ed2e8SPierre-Louis Bossart 
173*f40ed2e8SPierre-Louis Bossart static int dmic_init(struct snd_soc_pcm_runtime *rtd)
174*f40ed2e8SPierre-Louis Bossart {
175*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_card *card = rtd->card;
176*f40ed2e8SPierre-Louis Bossart 	int ret;
177*f40ed2e8SPierre-Louis Bossart 
178*f40ed2e8SPierre-Louis Bossart 	ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
179*f40ed2e8SPierre-Louis Bossart 					ARRAY_SIZE(dmic_widgets));
180*f40ed2e8SPierre-Louis Bossart 	if (ret) {
181*f40ed2e8SPierre-Louis Bossart 		dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
182*f40ed2e8SPierre-Louis Bossart 		/* Don't need to add routes if widget addition failed */
183*f40ed2e8SPierre-Louis Bossart 		return ret;
184*f40ed2e8SPierre-Louis Bossart 	}
185*f40ed2e8SPierre-Louis Bossart 
186*f40ed2e8SPierre-Louis Bossart 	ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
187*f40ed2e8SPierre-Louis Bossart 				      ARRAY_SIZE(dmic_map));
188*f40ed2e8SPierre-Louis Bossart 
189*f40ed2e8SPierre-Louis Bossart 	if (ret)
190*f40ed2e8SPierre-Louis Bossart 		dev_err(card->dev, "DMic map addition failed: %d\n", ret);
191*f40ed2e8SPierre-Louis Bossart 
192*f40ed2e8SPierre-Louis Bossart 	return ret;
193*f40ed2e8SPierre-Louis Bossart }
194*f40ed2e8SPierre-Louis Bossart 
195*f40ed2e8SPierre-Louis Bossart /* sof audio machine driver for pcm512x codec */
196*f40ed2e8SPierre-Louis Bossart static struct snd_soc_card sof_audio_card_pcm512x = {
197*f40ed2e8SPierre-Louis Bossart 	.name = "pcm512x",
198*f40ed2e8SPierre-Louis Bossart 	.owner = THIS_MODULE,
199*f40ed2e8SPierre-Louis Bossart 	.controls = sof_controls,
200*f40ed2e8SPierre-Louis Bossart 	.num_controls = ARRAY_SIZE(sof_controls),
201*f40ed2e8SPierre-Louis Bossart 	.dapm_widgets = sof_widgets,
202*f40ed2e8SPierre-Louis Bossart 	.num_dapm_widgets = ARRAY_SIZE(sof_widgets),
203*f40ed2e8SPierre-Louis Bossart 	.dapm_routes = sof_map,
204*f40ed2e8SPierre-Louis Bossart 	.num_dapm_routes = ARRAY_SIZE(sof_map),
205*f40ed2e8SPierre-Louis Bossart 	.fully_routed = true,
206*f40ed2e8SPierre-Louis Bossart 	.late_probe = sof_card_late_probe,
207*f40ed2e8SPierre-Louis Bossart };
208*f40ed2e8SPierre-Louis Bossart 
209*f40ed2e8SPierre-Louis Bossart SND_SOC_DAILINK_DEF(pcm512x_component,
210*f40ed2e8SPierre-Louis Bossart 	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-104C5122:00", "pcm512x-hifi")));
211*f40ed2e8SPierre-Louis Bossart SND_SOC_DAILINK_DEF(dmic_component,
212*f40ed2e8SPierre-Louis Bossart 	DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
213*f40ed2e8SPierre-Louis Bossart 
214*f40ed2e8SPierre-Louis Bossart static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
215*f40ed2e8SPierre-Louis Bossart 							  int ssp_codec,
216*f40ed2e8SPierre-Louis Bossart 							  int dmic_be_num,
217*f40ed2e8SPierre-Louis Bossart 							  int hdmi_num)
218*f40ed2e8SPierre-Louis Bossart {
219*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_dai_link_component *idisp_components;
220*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_dai_link_component *cpus;
221*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_dai_link *links;
222*f40ed2e8SPierre-Louis Bossart 	int i, id = 0;
223*f40ed2e8SPierre-Louis Bossart 
224*f40ed2e8SPierre-Louis Bossart 	links = devm_kcalloc(dev, sof_audio_card_pcm512x.num_links,
225*f40ed2e8SPierre-Louis Bossart 			sizeof(struct snd_soc_dai_link), GFP_KERNEL);
226*f40ed2e8SPierre-Louis Bossart 	cpus = devm_kcalloc(dev, sof_audio_card_pcm512x.num_links,
227*f40ed2e8SPierre-Louis Bossart 			sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
228*f40ed2e8SPierre-Louis Bossart 	if (!links || !cpus)
229*f40ed2e8SPierre-Louis Bossart 		goto devm_err;
230*f40ed2e8SPierre-Louis Bossart 
231*f40ed2e8SPierre-Louis Bossart 	/* codec SSP */
232*f40ed2e8SPierre-Louis Bossart 	links[id].name = devm_kasprintf(dev, GFP_KERNEL,
233*f40ed2e8SPierre-Louis Bossart 					"SSP%d-Codec", ssp_codec);
234*f40ed2e8SPierre-Louis Bossart 	if (!links[id].name)
235*f40ed2e8SPierre-Louis Bossart 		goto devm_err;
236*f40ed2e8SPierre-Louis Bossart 
237*f40ed2e8SPierre-Louis Bossart 	links[id].id = id;
238*f40ed2e8SPierre-Louis Bossart 	links[id].codecs = pcm512x_component;
239*f40ed2e8SPierre-Louis Bossart 	links[id].num_codecs = ARRAY_SIZE(pcm512x_component);
240*f40ed2e8SPierre-Louis Bossart 	links[id].platforms = platform_component;
241*f40ed2e8SPierre-Louis Bossart 	links[id].num_platforms = ARRAY_SIZE(platform_component);
242*f40ed2e8SPierre-Louis Bossart 	links[id].init = sof_pcm512x_codec_init;
243*f40ed2e8SPierre-Louis Bossart 	links[id].ops = &sof_pcm512x_ops;
244*f40ed2e8SPierre-Louis Bossart 	links[id].nonatomic = true;
245*f40ed2e8SPierre-Louis Bossart 	links[id].dpcm_playback = 1;
246*f40ed2e8SPierre-Louis Bossart 	/*
247*f40ed2e8SPierre-Louis Bossart 	 * capture only supported with specific versions of the Hifiberry DAC+
248*f40ed2e8SPierre-Louis Bossart 	 * links[id].dpcm_capture = 1;
249*f40ed2e8SPierre-Louis Bossart 	 */
250*f40ed2e8SPierre-Louis Bossart 	links[id].no_pcm = 1;
251*f40ed2e8SPierre-Louis Bossart 	links[id].cpus = &cpus[id];
252*f40ed2e8SPierre-Louis Bossart 	links[id].num_cpus = 1;
253*f40ed2e8SPierre-Louis Bossart 	if (is_legacy_cpu) {
254*f40ed2e8SPierre-Louis Bossart 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
255*f40ed2e8SPierre-Louis Bossart 							  "ssp%d-port",
256*f40ed2e8SPierre-Louis Bossart 							  ssp_codec);
257*f40ed2e8SPierre-Louis Bossart 		if (!links[id].cpus->dai_name)
258*f40ed2e8SPierre-Louis Bossart 			goto devm_err;
259*f40ed2e8SPierre-Louis Bossart 	} else {
260*f40ed2e8SPierre-Louis Bossart 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
261*f40ed2e8SPierre-Louis Bossart 							  "SSP%d Pin",
262*f40ed2e8SPierre-Louis Bossart 							  ssp_codec);
263*f40ed2e8SPierre-Louis Bossart 		if (!links[id].cpus->dai_name)
264*f40ed2e8SPierre-Louis Bossart 			goto devm_err;
265*f40ed2e8SPierre-Louis Bossart 	}
266*f40ed2e8SPierre-Louis Bossart 	id++;
267*f40ed2e8SPierre-Louis Bossart 
268*f40ed2e8SPierre-Louis Bossart 	/* dmic */
269*f40ed2e8SPierre-Louis Bossart 	if (dmic_be_num > 0) {
270*f40ed2e8SPierre-Louis Bossart 		/* at least we have dmic01 */
271*f40ed2e8SPierre-Louis Bossart 		links[id].name = "dmic01";
272*f40ed2e8SPierre-Louis Bossart 		links[id].cpus = &cpus[id];
273*f40ed2e8SPierre-Louis Bossart 		links[id].cpus->dai_name = "DMIC01 Pin";
274*f40ed2e8SPierre-Louis Bossart 		links[id].init = dmic_init;
275*f40ed2e8SPierre-Louis Bossart 		if (dmic_be_num > 1) {
276*f40ed2e8SPierre-Louis Bossart 			/* set up 2 BE links at most */
277*f40ed2e8SPierre-Louis Bossart 			links[id + 1].name = "dmic16k";
278*f40ed2e8SPierre-Louis Bossart 			links[id + 1].cpus = &cpus[id + 1];
279*f40ed2e8SPierre-Louis Bossart 			links[id + 1].cpus->dai_name = "DMIC16k Pin";
280*f40ed2e8SPierre-Louis Bossart 			dmic_be_num = 2;
281*f40ed2e8SPierre-Louis Bossart 		}
282*f40ed2e8SPierre-Louis Bossart 	}
283*f40ed2e8SPierre-Louis Bossart 
284*f40ed2e8SPierre-Louis Bossart 	for (i = 0; i < dmic_be_num; i++) {
285*f40ed2e8SPierre-Louis Bossart 		links[id].id = id;
286*f40ed2e8SPierre-Louis Bossart 		links[id].num_cpus = 1;
287*f40ed2e8SPierre-Louis Bossart 		links[id].codecs = dmic_component;
288*f40ed2e8SPierre-Louis Bossart 		links[id].num_codecs = ARRAY_SIZE(dmic_component);
289*f40ed2e8SPierre-Louis Bossart 		links[id].platforms = platform_component;
290*f40ed2e8SPierre-Louis Bossart 		links[id].num_platforms = ARRAY_SIZE(platform_component);
291*f40ed2e8SPierre-Louis Bossart 		links[id].ignore_suspend = 1;
292*f40ed2e8SPierre-Louis Bossart 		links[id].dpcm_capture = 1;
293*f40ed2e8SPierre-Louis Bossart 		links[id].no_pcm = 1;
294*f40ed2e8SPierre-Louis Bossart 		id++;
295*f40ed2e8SPierre-Louis Bossart 	}
296*f40ed2e8SPierre-Louis Bossart 
297*f40ed2e8SPierre-Louis Bossart 	/* HDMI */
298*f40ed2e8SPierre-Louis Bossart 	if (hdmi_num > 0) {
299*f40ed2e8SPierre-Louis Bossart 		idisp_components = devm_kcalloc(dev, hdmi_num,
300*f40ed2e8SPierre-Louis Bossart 				sizeof(struct snd_soc_dai_link_component),
301*f40ed2e8SPierre-Louis Bossart 				GFP_KERNEL);
302*f40ed2e8SPierre-Louis Bossart 		if (!idisp_components)
303*f40ed2e8SPierre-Louis Bossart 			goto devm_err;
304*f40ed2e8SPierre-Louis Bossart 	}
305*f40ed2e8SPierre-Louis Bossart 	for (i = 1; i <= hdmi_num; i++) {
306*f40ed2e8SPierre-Louis Bossart 		links[id].name = devm_kasprintf(dev, GFP_KERNEL,
307*f40ed2e8SPierre-Louis Bossart 						"iDisp%d", i);
308*f40ed2e8SPierre-Louis Bossart 		if (!links[id].name)
309*f40ed2e8SPierre-Louis Bossart 			goto devm_err;
310*f40ed2e8SPierre-Louis Bossart 
311*f40ed2e8SPierre-Louis Bossart 		links[id].id = id;
312*f40ed2e8SPierre-Louis Bossart 		links[id].cpus = &cpus[id];
313*f40ed2e8SPierre-Louis Bossart 		links[id].num_cpus = 1;
314*f40ed2e8SPierre-Louis Bossart 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
315*f40ed2e8SPierre-Louis Bossart 							  "iDisp%d Pin", i);
316*f40ed2e8SPierre-Louis Bossart 		if (!links[id].cpus->dai_name)
317*f40ed2e8SPierre-Louis Bossart 			goto devm_err;
318*f40ed2e8SPierre-Louis Bossart 
319*f40ed2e8SPierre-Louis Bossart 		idisp_components[i - 1].name = "ehdaudio0D2";
320*f40ed2e8SPierre-Louis Bossart 		idisp_components[i - 1].dai_name = devm_kasprintf(dev,
321*f40ed2e8SPierre-Louis Bossart 								  GFP_KERNEL,
322*f40ed2e8SPierre-Louis Bossart 								  "intel-hdmi-hifi%d",
323*f40ed2e8SPierre-Louis Bossart 								  i);
324*f40ed2e8SPierre-Louis Bossart 		if (!idisp_components[i - 1].dai_name)
325*f40ed2e8SPierre-Louis Bossart 			goto devm_err;
326*f40ed2e8SPierre-Louis Bossart 
327*f40ed2e8SPierre-Louis Bossart 		links[id].codecs = &idisp_components[i - 1];
328*f40ed2e8SPierre-Louis Bossart 		links[id].num_codecs = 1;
329*f40ed2e8SPierre-Louis Bossart 		links[id].platforms = platform_component;
330*f40ed2e8SPierre-Louis Bossart 		links[id].num_platforms = ARRAY_SIZE(platform_component);
331*f40ed2e8SPierre-Louis Bossart 		links[id].init = sof_hdmi_init;
332*f40ed2e8SPierre-Louis Bossart 		links[id].dpcm_playback = 1;
333*f40ed2e8SPierre-Louis Bossart 		links[id].no_pcm = 1;
334*f40ed2e8SPierre-Louis Bossart 		id++;
335*f40ed2e8SPierre-Louis Bossart 	}
336*f40ed2e8SPierre-Louis Bossart 
337*f40ed2e8SPierre-Louis Bossart 	return links;
338*f40ed2e8SPierre-Louis Bossart devm_err:
339*f40ed2e8SPierre-Louis Bossart 	return NULL;
340*f40ed2e8SPierre-Louis Bossart }
341*f40ed2e8SPierre-Louis Bossart 
342*f40ed2e8SPierre-Louis Bossart static int sof_audio_probe(struct platform_device *pdev)
343*f40ed2e8SPierre-Louis Bossart {
344*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_dai_link *dai_links;
345*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_acpi_mach *mach;
346*f40ed2e8SPierre-Louis Bossart 	struct sof_card_private *ctx;
347*f40ed2e8SPierre-Louis Bossart 	int dmic_be_num, hdmi_num;
348*f40ed2e8SPierre-Louis Bossart 	int ret, ssp_codec;
349*f40ed2e8SPierre-Louis Bossart 
350*f40ed2e8SPierre-Louis Bossart 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
351*f40ed2e8SPierre-Louis Bossart 	if (!ctx)
352*f40ed2e8SPierre-Louis Bossart 		return -ENOMEM;
353*f40ed2e8SPierre-Louis Bossart 
354*f40ed2e8SPierre-Louis Bossart 	hdmi_num = 0;
355*f40ed2e8SPierre-Louis Bossart 	if (soc_intel_is_byt() || soc_intel_is_cht()) {
356*f40ed2e8SPierre-Louis Bossart 		is_legacy_cpu = true;
357*f40ed2e8SPierre-Louis Bossart 		dmic_be_num = 0;
358*f40ed2e8SPierre-Louis Bossart 		/* default quirk for legacy cpu */
359*f40ed2e8SPierre-Louis Bossart 		sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(2);
360*f40ed2e8SPierre-Louis Bossart 	} else {
361*f40ed2e8SPierre-Louis Bossart 		dmic_be_num = 2;
362*f40ed2e8SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
363*f40ed2e8SPierre-Louis Bossart 		hdmi_num = 3;
364*f40ed2e8SPierre-Louis Bossart #endif
365*f40ed2e8SPierre-Louis Bossart 	}
366*f40ed2e8SPierre-Louis Bossart 
367*f40ed2e8SPierre-Louis Bossart 	dmi_check_system(sof_pcm512x_quirk_table);
368*f40ed2e8SPierre-Louis Bossart 
369*f40ed2e8SPierre-Louis Bossart 	dev_dbg(&pdev->dev, "sof_pcm512x_quirk = %lx\n", sof_pcm512x_quirk);
370*f40ed2e8SPierre-Louis Bossart 
371*f40ed2e8SPierre-Louis Bossart 	ssp_codec = sof_pcm512x_quirk & SOF_PCM512X_SSP_CODEC_MASK;
372*f40ed2e8SPierre-Louis Bossart 
373*f40ed2e8SPierre-Louis Bossart 	/* compute number of dai links */
374*f40ed2e8SPierre-Louis Bossart 	sof_audio_card_pcm512x.num_links = 1 + dmic_be_num + hdmi_num;
375*f40ed2e8SPierre-Louis Bossart 
376*f40ed2e8SPierre-Louis Bossart 	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec,
377*f40ed2e8SPierre-Louis Bossart 					      dmic_be_num, hdmi_num);
378*f40ed2e8SPierre-Louis Bossart 	if (!dai_links)
379*f40ed2e8SPierre-Louis Bossart 		return -ENOMEM;
380*f40ed2e8SPierre-Louis Bossart 
381*f40ed2e8SPierre-Louis Bossart 	sof_audio_card_pcm512x.dai_link = dai_links;
382*f40ed2e8SPierre-Louis Bossart 
383*f40ed2e8SPierre-Louis Bossart 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
384*f40ed2e8SPierre-Louis Bossart 
385*f40ed2e8SPierre-Louis Bossart 	sof_audio_card_pcm512x.dev = &pdev->dev;
386*f40ed2e8SPierre-Louis Bossart 	mach = (&pdev->dev)->platform_data;
387*f40ed2e8SPierre-Louis Bossart 
388*f40ed2e8SPierre-Louis Bossart 	/* set platform name for each dailink */
389*f40ed2e8SPierre-Louis Bossart 	ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_pcm512x,
390*f40ed2e8SPierre-Louis Bossart 						    mach->mach_params.platform);
391*f40ed2e8SPierre-Louis Bossart 	if (ret)
392*f40ed2e8SPierre-Louis Bossart 		return ret;
393*f40ed2e8SPierre-Louis Bossart 
394*f40ed2e8SPierre-Louis Bossart 	snd_soc_card_set_drvdata(&sof_audio_card_pcm512x, ctx);
395*f40ed2e8SPierre-Louis Bossart 
396*f40ed2e8SPierre-Louis Bossart 	return devm_snd_soc_register_card(&pdev->dev,
397*f40ed2e8SPierre-Louis Bossart 					  &sof_audio_card_pcm512x);
398*f40ed2e8SPierre-Louis Bossart }
399*f40ed2e8SPierre-Louis Bossart 
400*f40ed2e8SPierre-Louis Bossart static int sof_pcm512x_remove(struct platform_device *pdev)
401*f40ed2e8SPierre-Louis Bossart {
402*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_card *card = platform_get_drvdata(pdev);
403*f40ed2e8SPierre-Louis Bossart 	struct snd_soc_component *component = NULL;
404*f40ed2e8SPierre-Louis Bossart 
405*f40ed2e8SPierre-Louis Bossart 	for_each_card_components(card, component) {
406*f40ed2e8SPierre-Louis Bossart 		if (!strcmp(component->name, pcm512x_component[0].name)) {
407*f40ed2e8SPierre-Louis Bossart 			snd_soc_component_set_jack(component, NULL, NULL);
408*f40ed2e8SPierre-Louis Bossart 			break;
409*f40ed2e8SPierre-Louis Bossart 		}
410*f40ed2e8SPierre-Louis Bossart 	}
411*f40ed2e8SPierre-Louis Bossart 
412*f40ed2e8SPierre-Louis Bossart 	return 0;
413*f40ed2e8SPierre-Louis Bossart }
414*f40ed2e8SPierre-Louis Bossart 
415*f40ed2e8SPierre-Louis Bossart static struct platform_driver sof_audio = {
416*f40ed2e8SPierre-Louis Bossart 	.probe = sof_audio_probe,
417*f40ed2e8SPierre-Louis Bossart 	.remove = sof_pcm512x_remove,
418*f40ed2e8SPierre-Louis Bossart 	.driver = {
419*f40ed2e8SPierre-Louis Bossart 		.name = "sof_pcm512x",
420*f40ed2e8SPierre-Louis Bossart 		.pm = &snd_soc_pm_ops,
421*f40ed2e8SPierre-Louis Bossart 	},
422*f40ed2e8SPierre-Louis Bossart };
423*f40ed2e8SPierre-Louis Bossart module_platform_driver(sof_audio)
424*f40ed2e8SPierre-Louis Bossart 
425*f40ed2e8SPierre-Louis Bossart MODULE_DESCRIPTION("ASoC Intel(R) SOF + PCM512x Machine driver");
426*f40ed2e8SPierre-Louis Bossart MODULE_AUTHOR("Pierre-Louis Bossart");
427*f40ed2e8SPierre-Louis Bossart MODULE_LICENSE("GPL v2");
428*f40ed2e8SPierre-Louis Bossart MODULE_ALIAS("platform:sof_pcm512x");
429