1
2
3
4
5
6
7
8#include <linux/i2c.h>
9#include <linux/input.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/regulator/consumer.h>
13#include <linux/dmi.h>
14#include <sound/core.h>
15#include <sound/jack.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19#include <sound/sof.h>
20#include <sound/soc-acpi.h>
21#include <dt-bindings/sound/cs42l42.h>
22#include "../../codecs/hdac_hdmi.h"
23#include "../common/soc-intel-quirks.h"
24#include "hda_dsp_common.h"
25#include "sof_maxim_common.h"
26
27#define NAME_SIZE 32
28
29#define SOF_CS42L42_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
30#define SOF_CS42L42_SSP_CODEC_MASK (GENMASK(2, 0))
31#define SOF_SPEAKER_AMP_PRESENT BIT(3)
32#define SOF_CS42L42_SSP_AMP_SHIFT 4
33#define SOF_CS42L42_SSP_AMP_MASK (GENMASK(6, 4))
34#define SOF_CS42L42_SSP_AMP(quirk) \
35 (((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK)
36#define SOF_CS42L42_NUM_HDMIDEV_SHIFT 7
37#define SOF_CS42L42_NUM_HDMIDEV_MASK (GENMASK(9, 7))
38#define SOF_CS42L42_NUM_HDMIDEV(quirk) \
39 (((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK)
40#define SOF_CS42L42_DAILINK_SHIFT 10
41#define SOF_CS42L42_DAILINK_MASK (GENMASK(24, 10))
42#define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \
43 ((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK)
44#define SOF_MAX98357A_SPEAKER_AMP_PRESENT BIT(25)
45#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(26)
46
47enum {
48 LINK_NONE = 0,
49 LINK_HP = 1,
50 LINK_SPK = 2,
51 LINK_DMIC = 3,
52 LINK_HDMI = 4,
53};
54
55
56static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2);
57
58struct sof_hdmi_pcm {
59 struct list_head head;
60 struct snd_soc_dai *codec_dai;
61 struct snd_soc_jack hdmi_jack;
62 int device;
63};
64
65struct sof_card_private {
66 struct snd_soc_jack headset_jack;
67 struct list_head hdmi_pcm_list;
68 bool common_hdmi_codec_drv;
69};
70
71static 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
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
90static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
91{
92 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
93 struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
94 struct snd_soc_jack *jack = &ctx->headset_jack;
95 int ret;
96
97
98
99
100
101 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
102 SND_JACK_HEADSET | SND_JACK_BTN_0 |
103 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
104 SND_JACK_BTN_3,
105 jack, NULL, 0);
106 if (ret) {
107 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
108 return ret;
109 }
110
111 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
112 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
113 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
114 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
115
116 ret = snd_soc_component_set_jack(component, jack, NULL);
117 if (ret) {
118 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
119 return ret;
120 }
121
122 return ret;
123};
124
125static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd)
126{
127 struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
128
129 snd_soc_component_set_jack(component, NULL, NULL);
130}
131
132static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream,
133 struct snd_pcm_hw_params *params)
134{
135 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
136 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
137 int clk_freq, ret;
138
139 clk_freq = sof_dai_get_bclk(rtd);
140
141 if (clk_freq <= 0) {
142 dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq);
143 return -EINVAL;
144 }
145
146
147 ret = snd_soc_dai_set_sysclk(codec_dai, 0,
148 clk_freq, SND_SOC_CLOCK_IN);
149 if (ret < 0)
150 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
151
152 return ret;
153}
154
155static const struct snd_soc_ops sof_cs42l42_ops = {
156 .hw_params = sof_cs42l42_hw_params,
157};
158
159static struct snd_soc_dai_link_component platform_component[] = {
160 {
161
162 .name = "0000:00:1f.3"
163 }
164};
165
166static int sof_card_late_probe(struct snd_soc_card *card)
167{
168 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
169 struct snd_soc_component *component = NULL;
170 char jack_name[NAME_SIZE];
171 struct sof_hdmi_pcm *pcm;
172 int err;
173
174 if (list_empty(&ctx->hdmi_pcm_list))
175 return -EINVAL;
176
177 if (ctx->common_hdmi_codec_drv) {
178 pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
179 head);
180 component = pcm->codec_dai->component;
181 return hda_dsp_hdmi_build_controls(card, component);
182 }
183
184 list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
185 component = pcm->codec_dai->component;
186 snprintf(jack_name, sizeof(jack_name),
187 "HDMI/DP, pcm=%d Jack", pcm->device);
188 err = snd_soc_card_jack_new(card, jack_name,
189 SND_JACK_AVOUT, &pcm->hdmi_jack,
190 NULL, 0);
191
192 if (err)
193 return err;
194
195 err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
196 &pcm->hdmi_jack);
197 if (err < 0)
198 return err;
199 }
200
201 return hdac_hdmi_jack_port_init(component, &card->dapm);
202}
203
204static const struct snd_kcontrol_new sof_controls[] = {
205 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
206 SOC_DAPM_PIN_SWITCH("Headset Mic"),
207};
208
209static const struct snd_soc_dapm_widget sof_widgets[] = {
210 SND_SOC_DAPM_HP("Headphone Jack", NULL),
211 SND_SOC_DAPM_MIC("Headset Mic", NULL),
212};
213
214static const struct snd_soc_dapm_widget dmic_widgets[] = {
215 SND_SOC_DAPM_MIC("SoC DMIC", NULL),
216};
217
218static const struct snd_soc_dapm_route sof_map[] = {
219
220 {"Headphone Jack", NULL, "HP"},
221
222
223 {"HS", NULL, "Headset Mic"},
224};
225
226static const struct snd_soc_dapm_route dmic_map[] = {
227
228 {"DMic", NULL, "SoC DMIC"},
229};
230
231static int dmic_init(struct snd_soc_pcm_runtime *rtd)
232{
233 struct snd_soc_card *card = rtd->card;
234 int ret;
235
236 ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
237 ARRAY_SIZE(dmic_widgets));
238 if (ret) {
239 dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
240
241 return ret;
242 }
243
244 ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
245 ARRAY_SIZE(dmic_map));
246
247 if (ret)
248 dev_err(card->dev, "DMic map addition failed: %d\n", ret);
249
250 return ret;
251}
252
253
254static struct snd_soc_card sof_audio_card_cs42l42 = {
255 .name = "cs42l42",
256 .owner = THIS_MODULE,
257 .controls = sof_controls,
258 .num_controls = ARRAY_SIZE(sof_controls),
259 .dapm_widgets = sof_widgets,
260 .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
261 .dapm_routes = sof_map,
262 .num_dapm_routes = ARRAY_SIZE(sof_map),
263 .fully_routed = true,
264 .late_probe = sof_card_late_probe,
265};
266
267static struct snd_soc_dai_link_component cs42l42_component[] = {
268 {
269 .name = "i2c-10134242:00",
270 .dai_name = "cs42l42",
271 }
272};
273
274static struct snd_soc_dai_link_component dmic_component[] = {
275 {
276 .name = "dmic-codec",
277 .dai_name = "dmic-hifi",
278 }
279};
280
281static int create_spk_amp_dai_links(struct device *dev,
282 struct snd_soc_dai_link *links,
283 struct snd_soc_dai_link_component *cpus,
284 int *id, int ssp_amp)
285{
286 int ret = 0;
287
288
289 if (!(sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT))
290 return 0;
291
292 links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
293 ssp_amp);
294 if (!links[*id].name) {
295 ret = -ENOMEM;
296 goto devm_err;
297 }
298
299 links[*id].id = *id;
300
301 if (sof_cs42l42_quirk & SOF_MAX98357A_SPEAKER_AMP_PRESENT) {
302 max_98357a_dai_link(&links[*id]);
303 } else if (sof_cs42l42_quirk & SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
304 max_98360a_dai_link(&links[*id]);
305 } else {
306 dev_err(dev, "no amp defined\n");
307 ret = -EINVAL;
308 goto devm_err;
309 }
310
311 links[*id].platforms = platform_component;
312 links[*id].num_platforms = ARRAY_SIZE(platform_component);
313 links[*id].dpcm_playback = 1;
314 links[*id].no_pcm = 1;
315 links[*id].cpus = &cpus[*id];
316 links[*id].num_cpus = 1;
317
318 links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
319 "SSP%d Pin", ssp_amp);
320 if (!links[*id].cpus->dai_name) {
321 ret = -ENOMEM;
322 goto devm_err;
323 }
324
325 (*id)++;
326
327devm_err:
328 return ret;
329}
330
331static int create_hp_codec_dai_links(struct device *dev,
332 struct snd_soc_dai_link *links,
333 struct snd_soc_dai_link_component *cpus,
334 int *id, int ssp_codec)
335{
336
337 links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
338 ssp_codec);
339 if (!links[*id].name)
340 goto devm_err;
341
342 links[*id].id = *id;
343 links[*id].codecs = cs42l42_component;
344 links[*id].num_codecs = ARRAY_SIZE(cs42l42_component);
345 links[*id].platforms = platform_component;
346 links[*id].num_platforms = ARRAY_SIZE(platform_component);
347 links[*id].init = sof_cs42l42_init;
348 links[*id].exit = sof_cs42l42_exit;
349 links[*id].ops = &sof_cs42l42_ops;
350 links[*id].dpcm_playback = 1;
351 links[*id].dpcm_capture = 1;
352 links[*id].no_pcm = 1;
353 links[*id].cpus = &cpus[*id];
354 links[*id].num_cpus = 1;
355
356 links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
357 "SSP%d Pin",
358 ssp_codec);
359 if (!links[*id].cpus->dai_name)
360 goto devm_err;
361
362 (*id)++;
363
364 return 0;
365
366devm_err:
367 return -ENOMEM;
368}
369
370static int create_dmic_dai_links(struct device *dev,
371 struct snd_soc_dai_link *links,
372 struct snd_soc_dai_link_component *cpus,
373 int *id, int dmic_be_num)
374{
375 int i;
376
377
378 if (dmic_be_num <= 0)
379 return 0;
380
381
382 links[*id].name = "dmic01";
383 links[*id].cpus = &cpus[*id];
384 links[*id].cpus->dai_name = "DMIC01 Pin";
385 links[*id].init = dmic_init;
386 if (dmic_be_num > 1) {
387
388 links[*id + 1].name = "dmic16k";
389 links[*id + 1].cpus = &cpus[*id + 1];
390 links[*id + 1].cpus->dai_name = "DMIC16k Pin";
391 dmic_be_num = 2;
392 }
393
394 for (i = 0; i < dmic_be_num; i++) {
395 links[*id].id = *id;
396 links[*id].num_cpus = 1;
397 links[*id].codecs = dmic_component;
398 links[*id].num_codecs = ARRAY_SIZE(dmic_component);
399 links[*id].platforms = platform_component;
400 links[*id].num_platforms = ARRAY_SIZE(platform_component);
401 links[*id].ignore_suspend = 1;
402 links[*id].dpcm_capture = 1;
403 links[*id].no_pcm = 1;
404
405 (*id)++;
406 }
407
408 return 0;
409}
410
411static int create_hdmi_dai_links(struct device *dev,
412 struct snd_soc_dai_link *links,
413 struct snd_soc_dai_link_component *cpus,
414 int *id, int hdmi_num)
415{
416 struct snd_soc_dai_link_component *idisp_components;
417 int i;
418
419
420 if (hdmi_num <= 0)
421 return 0;
422
423 idisp_components = devm_kzalloc(dev,
424 sizeof(struct snd_soc_dai_link_component) *
425 hdmi_num, GFP_KERNEL);
426 if (!idisp_components)
427 goto devm_err;
428
429 for (i = 1; i <= hdmi_num; i++) {
430 links[*id].name = devm_kasprintf(dev, GFP_KERNEL,
431 "iDisp%d", i);
432 if (!links[*id].name)
433 goto devm_err;
434
435 links[*id].id = *id;
436 links[*id].cpus = &cpus[*id];
437 links[*id].num_cpus = 1;
438 links[*id].cpus->dai_name = devm_kasprintf(dev,
439 GFP_KERNEL,
440 "iDisp%d Pin",
441 i);
442 if (!links[*id].cpus->dai_name)
443 goto devm_err;
444
445 idisp_components[i - 1].name = "ehdaudio0D2";
446 idisp_components[i - 1].dai_name = devm_kasprintf(dev,
447 GFP_KERNEL,
448 "intel-hdmi-hifi%d",
449 i);
450 if (!idisp_components[i - 1].dai_name)
451 goto devm_err;
452
453 links[*id].codecs = &idisp_components[i - 1];
454 links[*id].num_codecs = 1;
455 links[*id].platforms = platform_component;
456 links[*id].num_platforms = ARRAY_SIZE(platform_component);
457 links[*id].init = sof_hdmi_init;
458 links[*id].dpcm_playback = 1;
459 links[*id].no_pcm = 1;
460
461 (*id)++;
462 }
463
464 return 0;
465
466devm_err:
467 return -ENOMEM;
468}
469
470static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
471 int ssp_codec,
472 int ssp_amp,
473 int dmic_be_num,
474 int hdmi_num)
475{
476 struct snd_soc_dai_link_component *cpus;
477 struct snd_soc_dai_link *links;
478 int ret, id = 0, link_seq;
479
480 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
481 sof_audio_card_cs42l42.num_links, GFP_KERNEL);
482 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
483 sof_audio_card_cs42l42.num_links, GFP_KERNEL);
484 if (!links || !cpus)
485 goto devm_err;
486
487 link_seq = (sof_cs42l42_quirk & SOF_CS42L42_DAILINK_MASK) >> SOF_CS42L42_DAILINK_SHIFT;
488
489 while (link_seq) {
490 int link_type = link_seq & 0x07;
491
492 switch (link_type) {
493 case LINK_HP:
494 ret = create_hp_codec_dai_links(dev, links, cpus, &id, ssp_codec);
495 if (ret < 0) {
496 dev_err(dev, "fail to create hp codec dai links, ret %d\n",
497 ret);
498 goto devm_err;
499 }
500 break;
501 case LINK_SPK:
502 ret = create_spk_amp_dai_links(dev, links, cpus, &id, ssp_amp);
503 if (ret < 0) {
504 dev_err(dev, "fail to create spk amp dai links, ret %d\n",
505 ret);
506 goto devm_err;
507 }
508 break;
509 case LINK_DMIC:
510 ret = create_dmic_dai_links(dev, links, cpus, &id, dmic_be_num);
511 if (ret < 0) {
512 dev_err(dev, "fail to create dmic dai links, ret %d\n",
513 ret);
514 goto devm_err;
515 }
516 break;
517 case LINK_HDMI:
518 ret = create_hdmi_dai_links(dev, links, cpus, &id, hdmi_num);
519 if (ret < 0) {
520 dev_err(dev, "fail to create hdmi dai links, ret %d\n",
521 ret);
522 goto devm_err;
523 }
524 break;
525 case LINK_NONE:
526
527 default:
528 dev_err(dev, "invalid link type %d\n", link_type);
529 goto devm_err;
530 }
531
532 link_seq >>= 3;
533 }
534
535 return links;
536devm_err:
537 return NULL;
538}
539
540static int sof_audio_probe(struct platform_device *pdev)
541{
542 struct snd_soc_dai_link *dai_links;
543 struct snd_soc_acpi_mach *mach;
544 struct sof_card_private *ctx;
545 int dmic_be_num, hdmi_num;
546 int ret, ssp_amp, ssp_codec;
547
548 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
549 if (!ctx)
550 return -ENOMEM;
551
552 if (pdev->id_entry && pdev->id_entry->driver_data)
553 sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data;
554
555 mach = pdev->dev.platform_data;
556
557 if (soc_intel_is_glk()) {
558 dmic_be_num = 1;
559 hdmi_num = 3;
560 } else {
561 dmic_be_num = 2;
562 hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >>
563 SOF_CS42L42_NUM_HDMIDEV_SHIFT;
564
565 if (!hdmi_num)
566 hdmi_num = 3;
567 }
568
569 dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
570
571 ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
572 SOF_CS42L42_SSP_AMP_SHIFT;
573
574 ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK;
575
576
577 sof_audio_card_cs42l42.num_links = 1 + dmic_be_num + hdmi_num;
578
579 if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT)
580 sof_audio_card_cs42l42.num_links++;
581
582 dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
583 dmic_be_num, hdmi_num);
584 if (!dai_links)
585 return -ENOMEM;
586
587 sof_audio_card_cs42l42.dai_link = dai_links;
588
589 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
590
591 sof_audio_card_cs42l42.dev = &pdev->dev;
592
593
594 ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42,
595 mach->mach_params.platform);
596 if (ret)
597 return ret;
598
599 ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
600
601 snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx);
602
603 return devm_snd_soc_register_card(&pdev->dev,
604 &sof_audio_card_cs42l42);
605}
606
607static const struct platform_device_id board_ids[] = {
608 {
609 .name = "glk_cs4242_mx98357a",
610 .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) |
611 SOF_SPEAKER_AMP_PRESENT |
612 SOF_MAX98357A_SPEAKER_AMP_PRESENT |
613 SOF_CS42L42_SSP_AMP(1)) |
614 SOF_CS42L42_DAILINK(LINK_SPK, LINK_HP, LINK_DMIC, LINK_HDMI, LINK_NONE),
615 },
616 {
617 .name = "jsl_cs4242_mx98360a",
618 .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
619 SOF_SPEAKER_AMP_PRESENT |
620 SOF_MAX98360A_SPEAKER_AMP_PRESENT |
621 SOF_CS42L42_SSP_AMP(1)) |
622 SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_NONE),
623 },
624 { }
625};
626MODULE_DEVICE_TABLE(platform, board_ids);
627
628static struct platform_driver sof_audio = {
629 .probe = sof_audio_probe,
630 .driver = {
631 .name = "sof_cs42l42",
632 .pm = &snd_soc_pm_ops,
633 },
634 .id_table = board_ids,
635};
636module_platform_driver(sof_audio)
637
638
639MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42");
640MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
641MODULE_LICENSE("GPL");
642MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
643MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
644