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