1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright(c) 2019 Intel Corporation.
3
4 /*
5 * Intel SOF Machine driver for Dialog headphone codec
6 */
7
8 #include <linux/input.h>
9 #include <linux/module.h>
10 #include <sound/jack.h>
11 #include <sound/pcm.h>
12 #include <sound/pcm_params.h>
13 #include <linux/platform_device.h>
14 #include <sound/soc.h>
15 #include <sound/soc-acpi.h>
16 #include <sound/sof.h>
17 #include "../../codecs/da7219.h"
18 #include "sof_board_helpers.h"
19 #include "sof_maxim_common.h"
20
21 /* Driver-specific board quirks: from bit 0 to 7 */
22 #define SOF_DA7219_GLK_BOARD BIT(0)
23 #define SOF_DA7219_CML_BOARD BIT(1)
24 #define SOF_DA7219_JSL_BOARD BIT(2)
25 #define SOF_DA7219_MCLK_EN BIT(3)
26
27 #define DIALOG_CODEC_DAI "da7219-hifi"
28
platform_clock_control(struct snd_soc_dapm_widget * w,struct snd_kcontrol * k,int event)29 static int platform_clock_control(struct snd_soc_dapm_widget *w,
30 struct snd_kcontrol *k, int event)
31 {
32 struct snd_soc_dapm_context *dapm = w->dapm;
33 struct snd_soc_card *card = dapm->card;
34 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
35 struct snd_soc_dai *codec_dai;
36 int ret = 0;
37
38 if (ctx->da7219.pll_bypass)
39 return ret;
40
41 /* PLL SRM mode */
42 codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI);
43 if (!codec_dai) {
44 dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
45 return -EIO;
46 }
47
48 if (SND_SOC_DAPM_EVENT_OFF(event)) {
49 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK,
50 0, 0);
51 if (ret)
52 dev_err(card->dev, "failed to stop PLL: %d\n", ret);
53 } else if (SND_SOC_DAPM_EVENT_ON(event)) {
54 dev_dbg(card->dev, "pll srm mode\n");
55
56 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
57 0, DA7219_PLL_FREQ_OUT_98304);
58 if (ret)
59 dev_err(card->dev, "failed to start PLL: %d\n", ret);
60 }
61
62 return ret;
63 }
64
65 static const struct snd_kcontrol_new controls[] = {
66 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
67 SOC_DAPM_PIN_SWITCH("Headset Mic"),
68 SOC_DAPM_PIN_SWITCH("Line Out"),
69 };
70
71 static const struct snd_soc_dapm_widget widgets[] = {
72 SND_SOC_DAPM_HP("Headphone Jack", NULL),
73 SND_SOC_DAPM_MIC("Headset Mic", NULL),
74 SND_SOC_DAPM_LINE("Line Out", NULL),
75
76 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
77 platform_clock_control, SND_SOC_DAPM_POST_PMD |
78 SND_SOC_DAPM_PRE_PMU),
79 };
80
81 static const struct snd_soc_dapm_route audio_map[] = {
82 { "Headphone Jack", NULL, "HPL" },
83 { "Headphone Jack", NULL, "HPR" },
84
85 { "MIC", NULL, "Headset Mic" },
86
87 { "Headphone Jack", NULL, "Platform Clock" },
88 { "Headset Mic", NULL, "Platform Clock" },
89 { "Line Out", NULL, "Platform Clock" },
90 };
91
92 static struct snd_soc_jack_pin jack_pins[] = {
93 {
94 .pin = "Headphone Jack",
95 .mask = SND_JACK_HEADPHONE,
96 },
97 {
98 .pin = "Headset Mic",
99 .mask = SND_JACK_MICROPHONE,
100 },
101 {
102 .pin = "Line Out",
103 .mask = SND_JACK_LINEOUT,
104 },
105 };
106
da7219_codec_init(struct snd_soc_pcm_runtime * rtd)107 static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
108 {
109 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
110 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
111 struct snd_soc_component *component = codec_dai->component;
112 struct snd_soc_jack *jack = &ctx->headset_jack;
113 int mclk_rate, ret;
114
115 mclk_rate = sof_dai_get_mclk(rtd);
116 if (mclk_rate <= 0) {
117 dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_rate);
118 return -EINVAL;
119 }
120
121 ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, mclk_rate,
122 SND_SOC_CLOCK_IN);
123 if (ret) {
124 dev_err(rtd->dev, "fail to set sysclk, ret %d\n", ret);
125 return ret;
126 }
127
128 /*
129 * Use PLL bypass mode if MCLK is available, be sure to set the
130 * frequency of MCLK to 12.288 or 24.576MHz on topology side.
131 */
132 if (ctx->da7219.mclk_en &&
133 (mclk_rate == 12288000 || mclk_rate == 24576000)) {
134 /* PLL bypass mode */
135 dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate);
136
137 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
138 if (ret) {
139 dev_err(rtd->dev, "fail to set pll, ret %d\n", ret);
140 return ret;
141 }
142
143 ctx->da7219.pll_bypass = true;
144 }
145
146 /*
147 * Headset buttons map to the google Reference headset.
148 * These can be configured by userspace.
149 */
150 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
151 SND_JACK_HEADSET | SND_JACK_BTN_0 |
152 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
153 SND_JACK_BTN_3 | SND_JACK_LINEOUT,
154 jack, jack_pins, ARRAY_SIZE(jack_pins));
155 if (ret) {
156 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
157 return ret;
158 }
159
160 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
161 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
162 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
163 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
164
165 ret = snd_soc_component_set_jack(component, jack, NULL);
166 if (ret) {
167 dev_err(rtd->dev, "fail to set component jack, ret %d\n", ret);
168 return ret;
169 }
170
171 return ret;
172 }
173
da7219_codec_exit(struct snd_soc_pcm_runtime * rtd)174 static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd)
175 {
176 struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
177
178 snd_soc_component_set_jack(component, NULL, NULL);
179 }
180
card_late_probe(struct snd_soc_card * card)181 static int card_late_probe(struct snd_soc_card *card)
182 {
183 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
184 struct snd_soc_dapm_context *dapm = &card->dapm;
185 int err;
186
187 if (ctx->amp_type == CODEC_MAX98373) {
188 /* Disable Left and Right Spk pin after boot */
189 snd_soc_dapm_disable_pin(dapm, "Left Spk");
190 snd_soc_dapm_disable_pin(dapm, "Right Spk");
191 err = snd_soc_dapm_sync(dapm);
192 if (err < 0)
193 return err;
194 }
195
196 return sof_intel_board_card_late_probe(card);
197 }
198
199 static struct snd_soc_card card_da7219 = {
200 .name = "da7219", /* the sof- prefix is added by the core */
201 .owner = THIS_MODULE,
202 .controls = controls,
203 .num_controls = ARRAY_SIZE(controls),
204 .dapm_widgets = widgets,
205 .num_dapm_widgets = ARRAY_SIZE(widgets),
206 .dapm_routes = audio_map,
207 .num_dapm_routes = ARRAY_SIZE(audio_map),
208 .fully_routed = true,
209 .late_probe = card_late_probe,
210 };
211
212 static struct snd_soc_dai_link_component da7219_component[] = {
213 {
214 .name = "i2c-DLGS7219:00",
215 .dai_name = DIALOG_CODEC_DAI,
216 }
217 };
218
219 static int
sof_card_dai_links_create(struct device * dev,struct snd_soc_card * card,struct sof_card_private * ctx)220 sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
221 struct sof_card_private *ctx)
222 {
223 int ret;
224
225 ret = sof_intel_board_set_dai_link(dev, card, ctx);
226 if (ret)
227 return ret;
228
229 if (!ctx->codec_link) {
230 dev_err(dev, "codec link not available");
231 return -EINVAL;
232 }
233
234 /* codec-specific fields for headphone codec */
235 ctx->codec_link->codecs = da7219_component;
236 ctx->codec_link->num_codecs = ARRAY_SIZE(da7219_component);
237 ctx->codec_link->init = da7219_codec_init;
238 ctx->codec_link->exit = da7219_codec_exit;
239
240 if (ctx->amp_type == CODEC_NONE)
241 return 0;
242
243 if (!ctx->amp_link) {
244 dev_err(dev, "amp link not available");
245 return -EINVAL;
246 }
247
248 /* codec-specific fields for speaker amplifier */
249 switch (ctx->amp_type) {
250 case CODEC_MAX98357A:
251 max_98357a_dai_link(ctx->amp_link);
252 break;
253 case CODEC_MAX98360A:
254 max_98360a_dai_link(ctx->amp_link);
255 break;
256 case CODEC_MAX98373:
257 max_98373_dai_link(dev, ctx->amp_link);
258 break;
259 case CODEC_MAX98390:
260 max_98390_dai_link(dev, ctx->amp_link);
261 break;
262 default:
263 dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
264 return -EINVAL;
265 }
266
267 return 0;
268 }
269
270 #define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
271 SOF_LINK_CODEC, \
272 SOF_LINK_DMIC01, \
273 SOF_LINK_IDISP_HDMI, \
274 SOF_LINK_NONE, \
275 SOF_LINK_NONE, \
276 SOF_LINK_NONE)
277
278 #define CML_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
279 SOF_LINK_CODEC, \
280 SOF_LINK_DMIC01, \
281 SOF_LINK_IDISP_HDMI, \
282 SOF_LINK_DMIC16K, \
283 SOF_LINK_NONE, \
284 SOF_LINK_NONE)
285
286 #define JSL_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
287 SOF_LINK_CODEC, \
288 SOF_LINK_DMIC01, \
289 SOF_LINK_IDISP_HDMI, \
290 SOF_LINK_DMIC16K, \
291 SOF_LINK_NONE, \
292 SOF_LINK_NONE)
293
audio_probe(struct platform_device * pdev)294 static int audio_probe(struct platform_device *pdev)
295 {
296 struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
297 struct sof_card_private *ctx;
298 char *card_name;
299 unsigned long board_quirk = 0;
300 int ret;
301
302 if (pdev->id_entry && pdev->id_entry->driver_data)
303 board_quirk = (unsigned long)pdev->id_entry->driver_data;
304
305 dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk);
306
307 /* initialize ctx with board quirk */
308 ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk);
309 if (!ctx)
310 return -ENOMEM;
311
312 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
313 ctx->hdmi.idisp_codec = true;
314
315 if (board_quirk & SOF_DA7219_GLK_BOARD) {
316 /* dmic16k not support */
317 ctx->dmic_be_num = 1;
318
319 /* overwrite the DAI link order for GLK boards */
320 ctx->link_order_overwrite = GLK_LINK_ORDER;
321
322 /* backward-compatible with existing devices */
323 switch (ctx->amp_type) {
324 case CODEC_MAX98357A:
325 card_name = devm_kstrdup(&pdev->dev, "glkda7219max",
326 GFP_KERNEL);
327 if (!card_name)
328 return -ENOMEM;
329
330 card_da7219.name = card_name;
331 break;
332 default:
333 break;
334 }
335 } else if (board_quirk & SOF_DA7219_CML_BOARD) {
336 /* overwrite the DAI link order for CML boards */
337 ctx->link_order_overwrite = CML_LINK_ORDER;
338
339 /* backward-compatible with existing devices */
340 switch (ctx->amp_type) {
341 case CODEC_MAX98357A:
342 card_name = devm_kstrdup(&pdev->dev, "cmlda7219max",
343 GFP_KERNEL);
344 if (!card_name)
345 return -ENOMEM;
346
347 card_da7219.name = card_name;
348 break;
349 case CODEC_MAX98390:
350 card_name = devm_kstrdup(&pdev->dev,
351 "cml_max98390_da7219",
352 GFP_KERNEL);
353 if (!card_name)
354 return -ENOMEM;
355
356 card_da7219.name = card_name;
357 break;
358 default:
359 break;
360 }
361 } else if (board_quirk & SOF_DA7219_JSL_BOARD) {
362 /* overwrite the DAI link order for JSL boards */
363 ctx->link_order_overwrite = JSL_LINK_ORDER;
364
365 /* backward-compatible with existing devices */
366 switch (ctx->amp_type) {
367 case CODEC_MAX98360A:
368 card_name = devm_kstrdup(&pdev->dev, "da7219max98360a",
369 GFP_KERNEL);
370 if (!card_name)
371 return -ENOMEM;
372
373 card_da7219.name = card_name;
374 break;
375 case CODEC_MAX98373:
376 card_name = devm_kstrdup(&pdev->dev, "da7219max",
377 GFP_KERNEL);
378 if (!card_name)
379 return -ENOMEM;
380
381 card_da7219.name = card_name;
382 break;
383 default:
384 break;
385 }
386 }
387
388 if (board_quirk & SOF_DA7219_MCLK_EN)
389 ctx->da7219.mclk_en = true;
390
391 /* update dai_link */
392 ret = sof_card_dai_links_create(&pdev->dev, &card_da7219, ctx);
393 if (ret)
394 return ret;
395
396 /* update codec_conf */
397 switch (ctx->amp_type) {
398 case CODEC_MAX98373:
399 max_98373_set_codec_conf(&card_da7219);
400 break;
401 case CODEC_MAX98390:
402 max_98390_set_codec_conf(&pdev->dev, &card_da7219);
403 break;
404 case CODEC_MAX98357A:
405 case CODEC_MAX98360A:
406 case CODEC_NONE:
407 /* no codec conf required */
408 break;
409 default:
410 dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
411 return -EINVAL;
412 }
413
414 card_da7219.dev = &pdev->dev;
415
416 ret = snd_soc_fixup_dai_links_platform_name(&card_da7219,
417 mach->mach_params.platform);
418 if (ret)
419 return ret;
420
421 snd_soc_card_set_drvdata(&card_da7219, ctx);
422
423 return devm_snd_soc_register_card(&pdev->dev, &card_da7219);
424 }
425
426 static const struct platform_device_id board_ids[] = {
427 {
428 .name = "glk_da7219_def",
429 .driver_data = (kernel_ulong_t)(SOF_DA7219_GLK_BOARD |
430 SOF_SSP_PORT_CODEC(2) |
431 SOF_SSP_PORT_AMP(1)),
432 },
433 {
434 .name = "cml_da7219_def",
435 .driver_data = (kernel_ulong_t)(SOF_DA7219_CML_BOARD |
436 SOF_SSP_PORT_CODEC(0) |
437 SOF_SSP_PORT_AMP(1)),
438 },
439 {
440 .name = "jsl_da7219_def",
441 .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD |
442 SOF_SSP_PORT_CODEC(0) |
443 SOF_SSP_PORT_AMP(1)),
444 },
445 {
446 .name = "adl_da7219_def",
447 .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
448 SOF_SSP_PORT_CODEC(0) |
449 SOF_SSP_PORT_AMP(1) |
450 SOF_NUM_IDISP_HDMI(4) |
451 SOF_SSP_PORT_BT_OFFLOAD(2) |
452 SOF_BT_OFFLOAD_PRESENT),
453 },
454 {
455 .name = "rpl_da7219_def",
456 .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
457 SOF_SSP_PORT_CODEC(0) |
458 SOF_SSP_PORT_AMP(1) |
459 SOF_NUM_IDISP_HDMI(4) |
460 SOF_SSP_PORT_BT_OFFLOAD(2) |
461 SOF_BT_OFFLOAD_PRESENT),
462 },
463 {
464 .name = "mtl_da7219_def",
465 .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN |
466 SOF_SSP_PORT_CODEC(2) |
467 SOF_SSP_PORT_AMP(0) |
468 SOF_SSP_PORT_BT_OFFLOAD(1) |
469 SOF_BT_OFFLOAD_PRESENT),
470 },
471 { }
472 };
473 MODULE_DEVICE_TABLE(platform, board_ids);
474
475 static struct platform_driver audio = {
476 .probe = audio_probe,
477 .driver = {
478 .name = "sof_da7219",
479 .pm = &snd_soc_pm_ops,
480 },
481 .id_table = board_ids,
482 };
483 module_platform_driver(audio)
484
485 /* Module information */
486 MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec");
487 MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
488 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
489 MODULE_LICENSE("GPL v2");
490 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
491 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
492