]>
Commit | Line | Data |
---|---|---|
a164137c PLB |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright(c) 2021 Intel Corporation. | |
3 | ||
4 | /* | |
5 | * Intel SOF Machine Driver with es8336 Codec | |
6 | */ | |
7 | ||
8 | #include <linux/device.h> | |
9 | #include <linux/dmi.h> | |
10 | #include <linux/gpio/consumer.h> | |
11 | #include <linux/gpio/machine.h> | |
12 | #include <linux/i2c.h> | |
13 | #include <linux/input.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/platform_device.h> | |
16 | #include <linux/slab.h> | |
17 | #include <sound/jack.h> | |
18 | #include <sound/pcm.h> | |
19 | #include <sound/pcm_params.h> | |
20 | #include <sound/soc.h> | |
21 | #include <sound/soc-acpi.h> | |
22 | #include "hda_dsp_common.h" | |
23 | ||
8e5db491 PLB |
24 | /* jd-inv + terminating entry */ |
25 | #define MAX_NO_PROPS 2 | |
26 | ||
a164137c PLB |
27 | #define SOF_ES8336_SSP_CODEC(quirk) ((quirk) & GENMASK(3, 0)) |
28 | #define SOF_ES8336_SSP_CODEC_MASK (GENMASK(3, 0)) | |
29 | ||
890a4087 | 30 | #define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK BIT(4) |
a164137c | 31 | #define SOF_ES8336_ENABLE_DMIC BIT(5) |
8e5db491 | 32 | #define SOF_ES8336_JD_INVERTED BIT(6) |
6e1ff145 | 33 | #define SOF_ES8336_HEADPHONE_GPIO BIT(7) |
7c7bb2a0 | 34 | #define SOC_ES8336_HEADSET_MIC1 BIT(8) |
a164137c PLB |
35 | |
36 | static unsigned long quirk; | |
37 | ||
38 | static int quirk_override = -1; | |
39 | module_param_named(quirk, quirk_override, int, 0444); | |
40 | MODULE_PARM_DESC(quirk, "Board-specific quirk override"); | |
41 | ||
42 | struct sof_es8336_private { | |
43 | struct device *codec_dev; | |
6e1ff145 | 44 | struct gpio_desc *gpio_speakers, *gpio_headphone; |
a164137c PLB |
45 | struct snd_soc_jack jack; |
46 | struct list_head hdmi_pcm_list; | |
47 | bool speaker_en; | |
48 | }; | |
49 | ||
50 | struct sof_hdmi_pcm { | |
51 | struct list_head head; | |
52 | struct snd_soc_dai *codec_dai; | |
53 | int device; | |
54 | }; | |
55 | ||
6e1ff145 MCC |
56 | static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true }; |
57 | static const struct acpi_gpio_params enable_gpio1 = { 1, 0, true }; | |
58 | ||
890a4087 | 59 | static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = { |
6e1ff145 | 60 | { "speakers-enable-gpios", &enable_gpio0, 1 }, |
a164137c PLB |
61 | { } |
62 | }; | |
63 | ||
890a4087 | 64 | static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = { |
6e1ff145 MCC |
65 | { "speakers-enable-gpios", &enable_gpio1, 1 }, |
66 | }; | |
67 | ||
68 | static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = { | |
69 | { "speakers-enable-gpios", &enable_gpio0, 1 }, | |
70 | { "headphone-enable-gpios", &enable_gpio1, 1 }, | |
71 | { } | |
72 | }; | |
73 | ||
74 | static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = { | |
75 | { "speakers-enable-gpios", &enable_gpio1, 1 }, | |
76 | { "headphone-enable-gpios", &enable_gpio0, 1 }, | |
a164137c PLB |
77 | { } |
78 | }; | |
79 | ||
890a4087 | 80 | static const struct acpi_gpio_mapping *gpio_mapping = acpi_speakers_enable_gpio0; |
a164137c PLB |
81 | |
82 | static void log_quirks(struct device *dev) | |
83 | { | |
9c818d84 PLB |
84 | dev_info(dev, "quirk mask %#lx\n", quirk); |
85 | dev_info(dev, "quirk SSP%ld\n", SOF_ES8336_SSP_CODEC(quirk)); | |
86 | if (quirk & SOF_ES8336_ENABLE_DMIC) | |
87 | dev_info(dev, "quirk DMIC enabled\n"); | |
890a4087 PLB |
88 | if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) |
89 | dev_info(dev, "Speakers GPIO1 quirk enabled\n"); | |
6e1ff145 MCC |
90 | if (quirk & SOF_ES8336_HEADPHONE_GPIO) |
91 | dev_info(dev, "quirk headphone GPIO enabled\n"); | |
8e5db491 PLB |
92 | if (quirk & SOF_ES8336_JD_INVERTED) |
93 | dev_info(dev, "quirk JD inverted enabled\n"); | |
7c7bb2a0 MCC |
94 | if (quirk & SOC_ES8336_HEADSET_MIC1) |
95 | dev_info(dev, "quirk headset at mic1 port enabled\n"); | |
a164137c PLB |
96 | } |
97 | ||
98 | static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, | |
99 | struct snd_kcontrol *kcontrol, int event) | |
100 | { | |
101 | struct snd_soc_card *card = w->dapm->card; | |
102 | struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); | |
103 | ||
6e1ff145 MCC |
104 | if (priv->speaker_en == !SND_SOC_DAPM_EVENT_ON(event)) |
105 | return 0; | |
106 | ||
107 | priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event); | |
108 | ||
a164137c | 109 | if (SND_SOC_DAPM_EVENT_ON(event)) |
6e1ff145 | 110 | msleep(70); |
a164137c | 111 | |
890a4087 | 112 | gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en); |
a164137c | 113 | |
6e1ff145 MCC |
114 | if (!(quirk & SOF_ES8336_HEADPHONE_GPIO)) |
115 | return 0; | |
116 | ||
117 | if (SND_SOC_DAPM_EVENT_ON(event)) | |
118 | msleep(70); | |
119 | ||
120 | gpiod_set_value_cansleep(priv->gpio_headphone, priv->speaker_en); | |
121 | ||
a164137c PLB |
122 | return 0; |
123 | } | |
124 | ||
125 | static const struct snd_soc_dapm_widget sof_es8316_widgets[] = { | |
126 | SND_SOC_DAPM_SPK("Speaker", NULL), | |
127 | SND_SOC_DAPM_HP("Headphone", NULL), | |
128 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | |
129 | SND_SOC_DAPM_MIC("Internal Mic", NULL), | |
130 | ||
131 | SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, | |
132 | sof_es8316_speaker_power_event, | |
133 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | |
134 | }; | |
135 | ||
136 | static const struct snd_soc_dapm_widget dmic_widgets[] = { | |
137 | SND_SOC_DAPM_MIC("SoC DMIC", NULL), | |
138 | }; | |
139 | ||
140 | static const struct snd_soc_dapm_route sof_es8316_audio_map[] = { | |
141 | {"Headphone", NULL, "HPOL"}, | |
142 | {"Headphone", NULL, "HPOR"}, | |
143 | ||
144 | /* | |
145 | * There is no separate speaker output instead the speakers are muxed to | |
6e1ff145 | 146 | * the HP outputs. The mux is controlled Speaker and/or headphone switch. |
a164137c PLB |
147 | */ |
148 | {"Speaker", NULL, "HPOL"}, | |
149 | {"Speaker", NULL, "HPOR"}, | |
150 | {"Speaker", NULL, "Speaker Power"}, | |
151 | }; | |
152 | ||
7c7bb2a0 | 153 | static const struct snd_soc_dapm_route sof_es8316_headset_mic2_map[] = { |
a164137c PLB |
154 | {"MIC1", NULL, "Internal Mic"}, |
155 | {"MIC2", NULL, "Headset Mic"}, | |
156 | }; | |
157 | ||
7c7bb2a0 MCC |
158 | static const struct snd_soc_dapm_route sof_es8316_headset_mic1_map[] = { |
159 | {"MIC2", NULL, "Internal Mic"}, | |
160 | {"MIC1", NULL, "Headset Mic"}, | |
161 | }; | |
162 | ||
a164137c PLB |
163 | static const struct snd_soc_dapm_route dmic_map[] = { |
164 | /* digital mics */ | |
165 | {"DMic", NULL, "SoC DMIC"}, | |
166 | }; | |
167 | ||
168 | static const struct snd_kcontrol_new sof_es8316_controls[] = { | |
169 | SOC_DAPM_PIN_SWITCH("Speaker"), | |
170 | SOC_DAPM_PIN_SWITCH("Headphone"), | |
171 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | |
172 | SOC_DAPM_PIN_SWITCH("Internal Mic"), | |
173 | }; | |
174 | ||
175 | static struct snd_soc_jack_pin sof_es8316_jack_pins[] = { | |
176 | { | |
177 | .pin = "Headphone", | |
178 | .mask = SND_JACK_HEADPHONE, | |
179 | }, | |
180 | { | |
181 | .pin = "Headset Mic", | |
182 | .mask = SND_JACK_MICROPHONE, | |
183 | }, | |
184 | }; | |
185 | ||
186 | static int dmic_init(struct snd_soc_pcm_runtime *runtime) | |
187 | { | |
188 | struct snd_soc_card *card = runtime->card; | |
189 | int ret; | |
190 | ||
191 | ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, | |
192 | ARRAY_SIZE(dmic_widgets)); | |
193 | if (ret) { | |
194 | dev_err(card->dev, "DMic widget addition failed: %d\n", ret); | |
195 | return ret; | |
196 | } | |
197 | ||
198 | ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, | |
199 | ARRAY_SIZE(dmic_map)); | |
200 | if (ret) | |
201 | dev_err(card->dev, "DMic map addition failed: %d\n", ret); | |
202 | ||
203 | return ret; | |
204 | } | |
205 | ||
206 | static int sof_hdmi_init(struct snd_soc_pcm_runtime *runtime) | |
207 | { | |
208 | struct sof_es8336_private *priv = snd_soc_card_get_drvdata(runtime->card); | |
209 | struct snd_soc_dai *dai = asoc_rtd_to_codec(runtime, 0); | |
210 | struct sof_hdmi_pcm *pcm; | |
211 | ||
212 | pcm = devm_kzalloc(runtime->card->dev, sizeof(*pcm), GFP_KERNEL); | |
213 | if (!pcm) | |
214 | return -ENOMEM; | |
215 | ||
216 | /* dai_link id is 1:1 mapped to the PCM device */ | |
217 | pcm->device = runtime->dai_link->id; | |
218 | pcm->codec_dai = dai; | |
219 | ||
220 | list_add_tail(&pcm->head, &priv->hdmi_pcm_list); | |
221 | ||
222 | return 0; | |
223 | } | |
224 | ||
225 | static int sof_es8316_init(struct snd_soc_pcm_runtime *runtime) | |
226 | { | |
227 | struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component; | |
228 | struct snd_soc_card *card = runtime->card; | |
229 | struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); | |
230 | const struct snd_soc_dapm_route *custom_map; | |
231 | int num_routes; | |
232 | int ret; | |
233 | ||
234 | card->dapm.idle_bias_off = true; | |
235 | ||
7c7bb2a0 MCC |
236 | if (quirk & SOC_ES8336_HEADSET_MIC1) { |
237 | custom_map = sof_es8316_headset_mic1_map; | |
238 | num_routes = ARRAY_SIZE(sof_es8316_headset_mic1_map); | |
239 | } else { | |
240 | custom_map = sof_es8316_headset_mic2_map; | |
241 | num_routes = ARRAY_SIZE(sof_es8316_headset_mic2_map); | |
242 | } | |
a164137c PLB |
243 | |
244 | ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); | |
245 | if (ret) | |
246 | return ret; | |
247 | ||
248 | ret = snd_soc_card_jack_new(card, "Headset", | |
249 | SND_JACK_HEADSET | SND_JACK_BTN_0, | |
250 | &priv->jack, sof_es8316_jack_pins, | |
251 | ARRAY_SIZE(sof_es8316_jack_pins)); | |
252 | if (ret) { | |
253 | dev_err(card->dev, "jack creation failed %d\n", ret); | |
254 | return ret; | |
255 | } | |
256 | ||
257 | snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); | |
258 | ||
259 | snd_soc_component_set_jack(codec, &priv->jack, NULL); | |
260 | ||
261 | return 0; | |
262 | } | |
263 | ||
264 | static void sof_es8316_exit(struct snd_soc_pcm_runtime *rtd) | |
265 | { | |
266 | struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; | |
267 | ||
268 | snd_soc_component_set_jack(component, NULL, NULL); | |
269 | } | |
270 | ||
271 | static int sof_es8336_quirk_cb(const struct dmi_system_id *id) | |
272 | { | |
273 | quirk = (unsigned long)id->driver_data; | |
274 | ||
6e1ff145 MCC |
275 | if (quirk & SOF_ES8336_HEADPHONE_GPIO) { |
276 | if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) | |
277 | gpio_mapping = acpi_enable_both_gpios; | |
278 | else | |
279 | gpio_mapping = acpi_enable_both_gpios_rev_order; | |
280 | } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) { | |
890a4087 | 281 | gpio_mapping = acpi_speakers_enable_gpio1; |
6e1ff145 | 282 | } |
a164137c PLB |
283 | |
284 | return 1; | |
285 | } | |
286 | ||
651c304d PLB |
287 | /* |
288 | * this table should only be used to add GPIO or jack-detection quirks | |
289 | * that cannot be detected from ACPI tables. The SSP and DMIC | |
290 | * information are providing by the platform driver and are aligned | |
291 | * with the topology used. | |
292 | * | |
293 | * If the GPIO support is missing, the quirk parameter can be used to | |
294 | * enable speakers. In that case it's recommended to keep the SSP and DMIC | |
295 | * information consistent, overriding the SSP and DMIC can only be done | |
296 | * if the topology file is modified as well. | |
297 | */ | |
a164137c | 298 | static const struct dmi_system_id sof_es8336_quirk_table[] = { |
a164137c PLB |
299 | { |
300 | .callback = sof_es8336_quirk_cb, | |
301 | .matches = { | |
302 | DMI_MATCH(DMI_SYS_VENDOR, "IP3 tech"), | |
303 | DMI_MATCH(DMI_BOARD_NAME, "WN1"), | |
304 | }, | |
890a4087 | 305 | .driver_data = (void *)(SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) |
a164137c | 306 | }, |
c7cb4717 MCC |
307 | { |
308 | .callback = sof_es8336_quirk_cb, | |
309 | .matches = { | |
310 | DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), | |
311 | DMI_MATCH(DMI_BOARD_NAME, "BOHB-WAX9-PCB-B2"), | |
312 | }, | |
313 | .driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO | | |
314 | SOC_ES8336_HEADSET_MIC1) | |
315 | }, | |
a164137c PLB |
316 | {} |
317 | }; | |
318 | ||
319 | static int sof_es8336_hw_params(struct snd_pcm_substream *substream, | |
320 | struct snd_pcm_hw_params *params) | |
321 | { | |
322 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); | |
323 | struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); | |
324 | const int sysclk = 19200000; | |
325 | int ret; | |
326 | ||
327 | ret = snd_soc_dai_set_sysclk(codec_dai, 1, sysclk, SND_SOC_CLOCK_OUT); | |
328 | if (ret < 0) { | |
329 | dev_err(rtd->dev, "%s, Failed to set ES8336 SYSCLK: %d\n", | |
330 | __func__, ret); | |
331 | return ret; | |
332 | } | |
333 | ||
334 | return 0; | |
335 | } | |
336 | ||
337 | /* machine stream operations */ | |
338 | static struct snd_soc_ops sof_es8336_ops = { | |
339 | .hw_params = sof_es8336_hw_params, | |
340 | }; | |
341 | ||
342 | static struct snd_soc_dai_link_component platform_component[] = { | |
343 | { | |
344 | /* name might be overridden during probe */ | |
345 | .name = "0000:00:1f.3" | |
346 | } | |
347 | }; | |
348 | ||
70b519e5 | 349 | SND_SOC_DAILINK_DEF(es8336_codec, |
a164137c PLB |
350 | DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi"))); |
351 | ||
352 | static struct snd_soc_dai_link_component dmic_component[] = { | |
353 | { | |
354 | .name = "dmic-codec", | |
355 | .dai_name = "dmic-hifi", | |
356 | } | |
357 | }; | |
358 | ||
359 | static int sof_es8336_late_probe(struct snd_soc_card *card) | |
360 | { | |
361 | struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); | |
362 | struct sof_hdmi_pcm *pcm; | |
363 | ||
364 | if (list_empty(&priv->hdmi_pcm_list)) | |
365 | return -ENOENT; | |
366 | ||
367 | pcm = list_first_entry(&priv->hdmi_pcm_list, struct sof_hdmi_pcm, head); | |
368 | ||
369 | return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component); | |
370 | } | |
371 | ||
372 | /* SoC card */ | |
373 | static struct snd_soc_card sof_es8336_card = { | |
374 | .name = "essx8336", /* sof- prefix added automatically */ | |
375 | .owner = THIS_MODULE, | |
376 | .dapm_widgets = sof_es8316_widgets, | |
377 | .num_dapm_widgets = ARRAY_SIZE(sof_es8316_widgets), | |
378 | .dapm_routes = sof_es8316_audio_map, | |
379 | .num_dapm_routes = ARRAY_SIZE(sof_es8316_audio_map), | |
380 | .controls = sof_es8316_controls, | |
381 | .num_controls = ARRAY_SIZE(sof_es8316_controls), | |
382 | .fully_routed = true, | |
383 | .late_probe = sof_es8336_late_probe, | |
384 | .num_links = 1, | |
385 | }; | |
386 | ||
387 | static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, | |
388 | int ssp_codec, | |
389 | int dmic_be_num, | |
390 | int hdmi_num) | |
391 | { | |
392 | struct snd_soc_dai_link_component *cpus; | |
393 | struct snd_soc_dai_link *links; | |
394 | struct snd_soc_dai_link_component *idisp_components; | |
395 | int hdmi_id_offset = 0; | |
396 | int id = 0; | |
397 | int i; | |
398 | ||
399 | links = devm_kcalloc(dev, sof_es8336_card.num_links, | |
400 | sizeof(struct snd_soc_dai_link), GFP_KERNEL); | |
401 | cpus = devm_kcalloc(dev, sof_es8336_card.num_links, | |
402 | sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); | |
403 | if (!links || !cpus) | |
404 | goto devm_err; | |
405 | ||
406 | /* codec SSP */ | |
407 | links[id].name = devm_kasprintf(dev, GFP_KERNEL, | |
408 | "SSP%d-Codec", ssp_codec); | |
409 | if (!links[id].name) | |
410 | goto devm_err; | |
411 | ||
412 | links[id].id = id; | |
70b519e5 PLB |
413 | links[id].codecs = es8336_codec; |
414 | links[id].num_codecs = ARRAY_SIZE(es8336_codec); | |
a164137c PLB |
415 | links[id].platforms = platform_component; |
416 | links[id].num_platforms = ARRAY_SIZE(platform_component); | |
417 | links[id].init = sof_es8316_init; | |
418 | links[id].exit = sof_es8316_exit; | |
419 | links[id].ops = &sof_es8336_ops; | |
420 | links[id].nonatomic = true; | |
421 | links[id].dpcm_playback = 1; | |
422 | links[id].dpcm_capture = 1; | |
423 | links[id].no_pcm = 1; | |
424 | links[id].cpus = &cpus[id]; | |
425 | links[id].num_cpus = 1; | |
426 | ||
427 | links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, | |
428 | "SSP%d Pin", | |
429 | ssp_codec); | |
430 | if (!links[id].cpus->dai_name) | |
431 | goto devm_err; | |
432 | ||
433 | id++; | |
434 | ||
435 | /* dmic */ | |
436 | if (dmic_be_num > 0) { | |
437 | /* at least we have dmic01 */ | |
438 | links[id].name = "dmic01"; | |
439 | links[id].cpus = &cpus[id]; | |
440 | links[id].cpus->dai_name = "DMIC01 Pin"; | |
441 | links[id].init = dmic_init; | |
442 | if (dmic_be_num > 1) { | |
443 | /* set up 2 BE links at most */ | |
444 | links[id + 1].name = "dmic16k"; | |
445 | links[id + 1].cpus = &cpus[id + 1]; | |
446 | links[id + 1].cpus->dai_name = "DMIC16k Pin"; | |
447 | dmic_be_num = 2; | |
448 | } | |
449 | } else { | |
450 | /* HDMI dai link starts at 3 according to current topology settings */ | |
451 | hdmi_id_offset = 2; | |
452 | } | |
453 | ||
454 | for (i = 0; i < dmic_be_num; i++) { | |
455 | links[id].id = id; | |
456 | links[id].num_cpus = 1; | |
457 | links[id].codecs = dmic_component; | |
458 | links[id].num_codecs = ARRAY_SIZE(dmic_component); | |
459 | links[id].platforms = platform_component; | |
460 | links[id].num_platforms = ARRAY_SIZE(platform_component); | |
461 | links[id].ignore_suspend = 1; | |
462 | links[id].dpcm_capture = 1; | |
463 | links[id].no_pcm = 1; | |
464 | ||
465 | id++; | |
466 | } | |
467 | ||
468 | /* HDMI */ | |
469 | if (hdmi_num > 0) { | |
470 | idisp_components = devm_kzalloc(dev, | |
471 | sizeof(struct snd_soc_dai_link_component) * | |
472 | hdmi_num, GFP_KERNEL); | |
473 | if (!idisp_components) | |
474 | goto devm_err; | |
475 | } | |
476 | ||
477 | for (i = 1; i <= hdmi_num; i++) { | |
478 | links[id].name = devm_kasprintf(dev, GFP_KERNEL, | |
479 | "iDisp%d", i); | |
480 | if (!links[id].name) | |
481 | goto devm_err; | |
482 | ||
483 | links[id].id = id + hdmi_id_offset; | |
484 | links[id].cpus = &cpus[id]; | |
485 | links[id].num_cpus = 1; | |
486 | links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, | |
487 | "iDisp%d Pin", i); | |
488 | if (!links[id].cpus->dai_name) | |
489 | goto devm_err; | |
490 | ||
491 | idisp_components[i - 1].name = "ehdaudio0D2"; | |
492 | idisp_components[i - 1].dai_name = devm_kasprintf(dev, | |
493 | GFP_KERNEL, | |
494 | "intel-hdmi-hifi%d", | |
495 | i); | |
496 | if (!idisp_components[i - 1].dai_name) | |
497 | goto devm_err; | |
498 | ||
499 | links[id].codecs = &idisp_components[i - 1]; | |
500 | links[id].num_codecs = 1; | |
501 | links[id].platforms = platform_component; | |
502 | links[id].num_platforms = ARRAY_SIZE(platform_component); | |
503 | links[id].init = sof_hdmi_init; | |
504 | links[id].dpcm_playback = 1; | |
505 | links[id].no_pcm = 1; | |
506 | ||
507 | id++; | |
508 | } | |
509 | ||
510 | return links; | |
511 | ||
512 | devm_err: | |
513 | return NULL; | |
514 | } | |
515 | ||
6e13567d PLB |
516 | static char soc_components[30]; |
517 | ||
a164137c PLB |
518 | /* i2c-<HID>:00 with HID being 8 chars */ |
519 | static char codec_name[SND_ACPI_I2C_ID_LEN]; | |
520 | ||
521 | static int sof_es8336_probe(struct platform_device *pdev) | |
522 | { | |
523 | struct device *dev = &pdev->dev; | |
524 | struct snd_soc_card *card; | |
525 | struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; | |
8e5db491 | 526 | struct property_entry props[MAX_NO_PROPS] = {}; |
a164137c | 527 | struct sof_es8336_private *priv; |
8e5db491 | 528 | struct fwnode_handle *fwnode; |
a164137c PLB |
529 | struct acpi_device *adev; |
530 | struct snd_soc_dai_link *dai_links; | |
531 | struct device *codec_dev; | |
8e5db491 | 532 | unsigned int cnt = 0; |
a164137c PLB |
533 | int dmic_be_num = 0; |
534 | int hdmi_num = 3; | |
535 | int ret; | |
536 | ||
537 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
538 | if (!priv) | |
539 | return -ENOMEM; | |
540 | ||
541 | card = &sof_es8336_card; | |
542 | card->dev = dev; | |
543 | ||
651c304d PLB |
544 | /* check GPIO DMI quirks */ |
545 | dmi_check_system(sof_es8336_quirk_table); | |
a164137c | 546 | |
651c304d PLB |
547 | if (!mach->mach_params.i2s_link_mask) { |
548 | dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n"); | |
549 | } else { | |
550 | /* | |
551 | * Set configuration based on platform NHLT. | |
552 | * In this machine driver, we can only support one SSP for the | |
553 | * ES8336 link, the else-if below are intentional. | |
554 | * In some cases multiple SSPs can be reported by NHLT, starting MSB-first | |
555 | * seems to pick the right connection. | |
556 | */ | |
557 | unsigned long ssp = 0; | |
558 | ||
559 | if (mach->mach_params.i2s_link_mask & BIT(2)) | |
560 | ssp = SOF_ES8336_SSP_CODEC(2); | |
561 | else if (mach->mach_params.i2s_link_mask & BIT(1)) | |
562 | ssp = SOF_ES8336_SSP_CODEC(1); | |
563 | else if (mach->mach_params.i2s_link_mask & BIT(0)) | |
564 | ssp = SOF_ES8336_SSP_CODEC(0); | |
565 | ||
566 | quirk |= ssp; | |
567 | } | |
568 | ||
569 | if (mach->mach_params.dmic_num) | |
570 | quirk |= SOF_ES8336_ENABLE_DMIC; | |
a164137c PLB |
571 | |
572 | if (quirk_override != -1) { | |
573 | dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n", | |
574 | quirk, quirk_override); | |
575 | quirk = quirk_override; | |
576 | } | |
577 | log_quirks(dev); | |
578 | ||
651c304d PLB |
579 | if (quirk & SOF_ES8336_ENABLE_DMIC) |
580 | dmic_be_num = 2; | |
581 | ||
a164137c PLB |
582 | sof_es8336_card.num_links += dmic_be_num + hdmi_num; |
583 | dai_links = sof_card_dai_links_create(dev, | |
584 | SOF_ES8336_SSP_CODEC(quirk), | |
585 | dmic_be_num, hdmi_num); | |
586 | if (!dai_links) | |
587 | return -ENOMEM; | |
588 | ||
589 | sof_es8336_card.dai_link = dai_links; | |
590 | ||
591 | /* fixup codec name based on HID */ | |
592 | adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); | |
593 | if (adev) { | |
594 | snprintf(codec_name, sizeof(codec_name), | |
595 | "i2c-%s", acpi_dev_name(adev)); | |
596 | put_device(&adev->dev); | |
597 | dai_links[0].codecs->name = codec_name; | |
70b519e5 PLB |
598 | |
599 | /* also fixup codec dai name if relevant */ | |
600 | if (!strncmp(mach->id, "ESSX8326", SND_ACPI_I2C_ID_LEN)) | |
601 | dai_links[0].codecs->dai_name = "ES8326 HiFi"; | |
8e5db491 PLB |
602 | } else { |
603 | dev_err(dev, "Error cannot find '%s' dev\n", mach->id); | |
604 | return -ENXIO; | |
a164137c PLB |
605 | } |
606 | ||
607 | ret = snd_soc_fixup_dai_links_platform_name(&sof_es8336_card, | |
608 | mach->mach_params.platform); | |
609 | if (ret) | |
610 | return ret; | |
611 | ||
42302b20 | 612 | codec_dev = acpi_get_first_physical_node(adev); |
a164137c PLB |
613 | if (!codec_dev) |
614 | return -EPROBE_DEFER; | |
42302b20 | 615 | priv->codec_dev = get_device(codec_dev); |
a164137c | 616 | |
8e5db491 PLB |
617 | if (quirk & SOF_ES8336_JD_INVERTED) |
618 | props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted"); | |
619 | ||
620 | if (cnt) { | |
621 | fwnode = fwnode_create_software_node(props, NULL); | |
622 | if (IS_ERR(fwnode)) { | |
623 | put_device(codec_dev); | |
624 | return PTR_ERR(fwnode); | |
625 | } | |
626 | ||
627 | ret = device_add_software_node(codec_dev, to_software_node(fwnode)); | |
628 | ||
629 | fwnode_handle_put(fwnode); | |
630 | ||
631 | if (ret) { | |
632 | put_device(codec_dev); | |
633 | return ret; | |
634 | } | |
635 | } | |
636 | ||
d94c11a9 | 637 | /* get speaker enable GPIO */ |
a164137c PLB |
638 | ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping); |
639 | if (ret) | |
640 | dev_warn(codec_dev, "unable to add GPIO mapping table\n"); | |
641 | ||
890a4087 PLB |
642 | priv->gpio_speakers = gpiod_get_optional(codec_dev, "speakers-enable", GPIOD_OUT_LOW); |
643 | if (IS_ERR(priv->gpio_speakers)) { | |
644 | ret = dev_err_probe(dev, PTR_ERR(priv->gpio_speakers), | |
645 | "could not get speakers-enable GPIO\n"); | |
8e5db491 | 646 | goto err_put_codec; |
a164137c PLB |
647 | } |
648 | ||
6e1ff145 MCC |
649 | priv->gpio_headphone = gpiod_get_optional(codec_dev, "headphone-enable", GPIOD_OUT_LOW); |
650 | if (IS_ERR(priv->gpio_headphone)) { | |
651 | ret = dev_err_probe(dev, PTR_ERR(priv->gpio_headphone), | |
652 | "could not get headphone-enable GPIO\n"); | |
653 | goto err_put_codec; | |
654 | } | |
655 | ||
a164137c PLB |
656 | INIT_LIST_HEAD(&priv->hdmi_pcm_list); |
657 | ||
658 | snd_soc_card_set_drvdata(card, priv); | |
659 | ||
6e13567d PLB |
660 | if (mach->mach_params.dmic_num > 0) { |
661 | snprintf(soc_components, sizeof(soc_components), | |
662 | "cfg-dmics:%d", mach->mach_params.dmic_num); | |
663 | card->components = soc_components; | |
664 | } | |
665 | ||
a164137c PLB |
666 | ret = devm_snd_soc_register_card(dev, card); |
667 | if (ret) { | |
890a4087 | 668 | gpiod_put(priv->gpio_speakers); |
a164137c | 669 | dev_err(dev, "snd_soc_register_card failed: %d\n", ret); |
8e5db491 | 670 | goto err_put_codec; |
a164137c PLB |
671 | } |
672 | platform_set_drvdata(pdev, &sof_es8336_card); | |
673 | return 0; | |
674 | ||
8e5db491 PLB |
675 | err_put_codec: |
676 | device_remove_software_node(priv->codec_dev); | |
a164137c PLB |
677 | put_device(codec_dev); |
678 | return ret; | |
679 | } | |
680 | ||
681 | static int sof_es8336_remove(struct platform_device *pdev) | |
682 | { | |
683 | struct snd_soc_card *card = platform_get_drvdata(pdev); | |
684 | struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card); | |
685 | ||
890a4087 | 686 | gpiod_put(priv->gpio_speakers); |
8e5db491 | 687 | device_remove_software_node(priv->codec_dev); |
a164137c PLB |
688 | put_device(priv->codec_dev); |
689 | ||
690 | return 0; | |
691 | } | |
692 | ||
693 | static struct platform_driver sof_es8336_driver = { | |
694 | .driver = { | |
695 | .name = "sof-essx8336", | |
696 | .pm = &snd_soc_pm_ops, | |
697 | }, | |
698 | .probe = sof_es8336_probe, | |
699 | .remove = sof_es8336_remove, | |
700 | }; | |
701 | module_platform_driver(sof_es8336_driver); | |
702 | ||
703 | MODULE_DESCRIPTION("ASoC Intel(R) SOF + ES8336 Machine driver"); | |
704 | MODULE_LICENSE("GPL"); | |
705 | MODULE_ALIAS("platform:sof-essx8336"); | |
706 | MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); |