• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
sof_pcm512x_quirk_cb(const struct dmi_system_id * id)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 
sof_hdmi_init(struct snd_soc_pcm_runtime * rtd)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 = asoc_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 
sof_pcm512x_codec_init(struct snd_soc_pcm_runtime * rtd)90 static int sof_pcm512x_codec_init(struct snd_soc_pcm_runtime *rtd)
91 {
92 	struct snd_soc_component *codec = asoc_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 
aif1_startup(struct snd_pcm_substream * substream)102 static int aif1_startup(struct snd_pcm_substream *substream)
103 {
104 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
105 	struct snd_soc_component *codec = asoc_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 
aif1_shutdown(struct snd_pcm_substream * substream)113 static void aif1_shutdown(struct snd_pcm_substream *substream)
114 {
115 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
116 	struct snd_soc_component *codec = asoc_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 
sof_card_late_probe(struct snd_soc_card * card)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 
dmic_init(struct snd_soc_pcm_runtime * rtd)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 
sof_card_dai_links_create(struct device * dev,int ssp_codec,int dmic_be_num,int hdmi_num,bool idisp_codec)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].nonatomic = true;
250 	links[id].dpcm_playback = 1;
251 	/*
252 	 * capture only supported with specific versions of the Hifiberry DAC+
253 	 */
254 	if (sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE)
255 		links[id].dpcm_capture = 1;
256 	links[id].no_pcm = 1;
257 	links[id].cpus = &cpus[id];
258 	links[id].num_cpus = 1;
259 	if (is_legacy_cpu) {
260 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
261 							  "ssp%d-port",
262 							  ssp_codec);
263 		if (!links[id].cpus->dai_name)
264 			goto devm_err;
265 	} else {
266 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
267 							  "SSP%d Pin",
268 							  ssp_codec);
269 		if (!links[id].cpus->dai_name)
270 			goto devm_err;
271 	}
272 	id++;
273 
274 	/* dmic */
275 	if (dmic_be_num > 0) {
276 		/* at least we have dmic01 */
277 		links[id].name = "dmic01";
278 		links[id].cpus = &cpus[id];
279 		links[id].cpus->dai_name = "DMIC01 Pin";
280 		links[id].init = dmic_init;
281 		if (dmic_be_num > 1) {
282 			/* set up 2 BE links at most */
283 			links[id + 1].name = "dmic16k";
284 			links[id + 1].cpus = &cpus[id + 1];
285 			links[id + 1].cpus->dai_name = "DMIC16k Pin";
286 			dmic_be_num = 2;
287 		}
288 	}
289 
290 	for (i = 0; i < dmic_be_num; i++) {
291 		links[id].id = id;
292 		links[id].num_cpus = 1;
293 		links[id].codecs = dmic_component;
294 		links[id].num_codecs = ARRAY_SIZE(dmic_component);
295 		links[id].platforms = platform_component;
296 		links[id].num_platforms = ARRAY_SIZE(platform_component);
297 		links[id].ignore_suspend = 1;
298 		links[id].dpcm_capture = 1;
299 		links[id].no_pcm = 1;
300 		id++;
301 	}
302 
303 	/* HDMI */
304 	if (hdmi_num > 0) {
305 		idisp_components = devm_kcalloc(dev, hdmi_num,
306 				sizeof(struct snd_soc_dai_link_component),
307 				GFP_KERNEL);
308 		if (!idisp_components)
309 			goto devm_err;
310 	}
311 	for (i = 1; i <= hdmi_num; i++) {
312 		links[id].name = devm_kasprintf(dev, GFP_KERNEL,
313 						"iDisp%d", i);
314 		if (!links[id].name)
315 			goto devm_err;
316 
317 		links[id].id = id;
318 		links[id].cpus = &cpus[id];
319 		links[id].num_cpus = 1;
320 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
321 							  "iDisp%d Pin", i);
322 		if (!links[id].cpus->dai_name)
323 			goto devm_err;
324 
325 		/*
326 		 * topology cannot be loaded if codec is missing, so
327 		 * use the dummy codec if needed
328 		 */
329 		if (idisp_codec) {
330 			idisp_components[i - 1].name = "ehdaudio0D2";
331 			idisp_components[i - 1].dai_name =
332 				devm_kasprintf(dev, GFP_KERNEL,
333 					       "intel-hdmi-hifi%d", i);
334 		} else {
335 			idisp_components[i - 1].name = "snd-soc-dummy";
336 			idisp_components[i - 1].dai_name = "snd-soc-dummy-dai";
337 		}
338 		if (!idisp_components[i - 1].dai_name)
339 			goto devm_err;
340 
341 		links[id].codecs = &idisp_components[i - 1];
342 		links[id].num_codecs = 1;
343 		links[id].platforms = platform_component;
344 		links[id].num_platforms = ARRAY_SIZE(platform_component);
345 		links[id].init = sof_hdmi_init;
346 		links[id].dpcm_playback = 1;
347 		links[id].no_pcm = 1;
348 		id++;
349 	}
350 
351 	return links;
352 devm_err:
353 	return NULL;
354 }
355 
sof_audio_probe(struct platform_device * pdev)356 static int sof_audio_probe(struct platform_device *pdev)
357 {
358 	struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
359 	struct snd_soc_dai_link *dai_links;
360 	struct sof_card_private *ctx;
361 	int dmic_be_num, hdmi_num;
362 	int ret, ssp_codec;
363 
364 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
365 	if (!ctx)
366 		return -ENOMEM;
367 
368 	hdmi_num = 0;
369 	if (soc_intel_is_byt() || soc_intel_is_cht()) {
370 		is_legacy_cpu = true;
371 		dmic_be_num = 0;
372 		/* default quirk for legacy cpu */
373 		sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(2);
374 	} else {
375 		dmic_be_num = 2;
376 		if (mach->mach_params.common_hdmi_codec_drv &&
377 		    (mach->mach_params.codec_mask & IDISP_CODEC_MASK))
378 			ctx->idisp_codec = true;
379 
380 		/* links are always present in topology */
381 		hdmi_num = 3;
382 	}
383 
384 	dmi_check_system(sof_pcm512x_quirk_table);
385 
386 	dev_dbg(&pdev->dev, "sof_pcm512x_quirk = %lx\n", sof_pcm512x_quirk);
387 
388 	ssp_codec = sof_pcm512x_quirk & SOF_PCM512X_SSP_CODEC_MASK;
389 
390 	if (!(sof_pcm512x_quirk & SOF_PCM512X_ENABLE_DMIC))
391 		dmic_be_num = 0;
392 
393 	/* compute number of dai links */
394 	sof_audio_card_pcm512x.num_links = 1 + dmic_be_num + hdmi_num;
395 
396 	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec,
397 					      dmic_be_num, hdmi_num,
398 					      ctx->idisp_codec);
399 	if (!dai_links)
400 		return -ENOMEM;
401 
402 	sof_audio_card_pcm512x.dai_link = dai_links;
403 
404 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
405 
406 	sof_audio_card_pcm512x.dev = &pdev->dev;
407 
408 	/* set platform name for each dailink */
409 	ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_pcm512x,
410 						    mach->mach_params.platform);
411 	if (ret)
412 		return ret;
413 
414 	snd_soc_card_set_drvdata(&sof_audio_card_pcm512x, ctx);
415 
416 	return devm_snd_soc_register_card(&pdev->dev,
417 					  &sof_audio_card_pcm512x);
418 }
419 
sof_pcm512x_remove(struct platform_device * pdev)420 static int sof_pcm512x_remove(struct platform_device *pdev)
421 {
422 	struct snd_soc_card *card = platform_get_drvdata(pdev);
423 	struct snd_soc_component *component = NULL;
424 
425 	for_each_card_components(card, component) {
426 		if (!strcmp(component->name, pcm512x_component[0].name)) {
427 			snd_soc_component_set_jack(component, NULL, NULL);
428 			break;
429 		}
430 	}
431 
432 	return 0;
433 }
434 
435 static struct platform_driver sof_audio = {
436 	.probe = sof_audio_probe,
437 	.remove = sof_pcm512x_remove,
438 	.driver = {
439 		.name = "sof_pcm512x",
440 		.pm = &snd_soc_pm_ops,
441 	},
442 };
443 module_platform_driver(sof_audio)
444 
445 MODULE_DESCRIPTION("ASoC Intel(R) SOF + PCM512x Machine driver");
446 MODULE_AUTHOR("Pierre-Louis Bossart");
447 MODULE_LICENSE("GPL v2");
448 MODULE_ALIAS("platform:sof_pcm512x");
449