arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / sound / soc / intel / boards / sof_cs42l42.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright(c) 2021 Intel Corporation.
3
4 /*
5  * Intel SOF Machine Driver with Cirrus Logic CS42L42 Codec
6  * and speaker codec MAX98357A
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 "../common/soc-intel-quirks.h"
23 #include "sof_board_helpers.h"
24 #include "sof_maxim_common.h"
25 #include "sof_ssp_common.h"
26
27 #define SOF_CS42L42_SSP_CODEC(quirk)            ((quirk) & GENMASK(2, 0))
28 #define SOF_CS42L42_SSP_CODEC_MASK              (GENMASK(2, 0))
29 #define SOF_CS42L42_SSP_AMP_SHIFT               4
30 #define SOF_CS42L42_SSP_AMP_MASK                (GENMASK(6, 4))
31 #define SOF_CS42L42_SSP_AMP(quirk)      \
32         (((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK)
33 #define SOF_CS42L42_NUM_HDMIDEV_SHIFT           7
34 #define SOF_CS42L42_NUM_HDMIDEV_MASK            (GENMASK(9, 7))
35 #define SOF_CS42L42_NUM_HDMIDEV(quirk)  \
36         (((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK)
37 #define SOF_CS42L42_DAILINK_SHIFT               10
38 #define SOF_CS42L42_DAILINK_MASK                (GENMASK(24, 10))
39 #define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \
40         ((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK)
41 #define SOF_BT_OFFLOAD_PRESENT                  BIT(25)
42 #define SOF_CS42L42_SSP_BT_SHIFT                26
43 #define SOF_CS42L42_SSP_BT_MASK                 (GENMASK(28, 26))
44 #define SOF_CS42L42_SSP_BT(quirk)       \
45         (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK)
46
47 enum {
48         LINK_NONE = 0,
49         LINK_HP = 1,
50         LINK_SPK = 2,
51         LINK_DMIC = 3,
52         LINK_HDMI = 4,
53         LINK_BT = 5,
54 };
55
56 static struct snd_soc_jack_pin jack_pins[] = {
57         {
58                 .pin    = "Headphone Jack",
59                 .mask   = SND_JACK_HEADPHONE,
60         },
61         {
62                 .pin    = "Headset Mic",
63                 .mask   = SND_JACK_MICROPHONE,
64         },
65 };
66
67 /* Default: SSP2 */
68 static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2);
69
70 static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
71 {
72         struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
73         struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
74         struct snd_soc_jack *jack = &ctx->headset_jack;
75         int ret;
76
77         /*
78          * Headset buttons map to the google Reference headset.
79          * These can be configured by userspace.
80          */
81         ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
82                                          SND_JACK_HEADSET | SND_JACK_BTN_0 |
83                                          SND_JACK_BTN_1 | SND_JACK_BTN_2 |
84                                          SND_JACK_BTN_3,
85                                          jack,
86                                          jack_pins,
87                                          ARRAY_SIZE(jack_pins));
88         if (ret) {
89                 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
90                 return ret;
91         }
92
93         snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
94         snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
95         snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
96         snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
97
98         ret = snd_soc_component_set_jack(component, jack, NULL);
99         if (ret) {
100                 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
101                 return ret;
102         }
103
104         return ret;
105 };
106
107 static void sof_cs42l42_exit(struct snd_soc_pcm_runtime *rtd)
108 {
109         struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
110
111         snd_soc_component_set_jack(component, NULL, NULL);
112 }
113
114 static int sof_cs42l42_hw_params(struct snd_pcm_substream *substream,
115                                  struct snd_pcm_hw_params *params)
116 {
117         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
118         struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
119         int clk_freq, ret;
120
121         clk_freq = sof_dai_get_bclk(rtd); /* BCLK freq */
122
123         if (clk_freq <= 0) {
124                 dev_err(rtd->dev, "get bclk freq failed: %d\n", clk_freq);
125                 return -EINVAL;
126         }
127
128         /* Configure sysclk for codec */
129         ret = snd_soc_dai_set_sysclk(codec_dai, 0,
130                                      clk_freq, SND_SOC_CLOCK_IN);
131         if (ret < 0)
132                 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
133
134         return ret;
135 }
136
137 static const struct snd_soc_ops sof_cs42l42_ops = {
138         .hw_params = sof_cs42l42_hw_params,
139 };
140
141 static struct snd_soc_dai_link_component platform_component[] = {
142         {
143                 /* name might be overridden during probe */
144                 .name = "0000:00:1f.3"
145         }
146 };
147
148 static int sof_card_late_probe(struct snd_soc_card *card)
149 {
150         return sof_intel_board_card_late_probe(card);
151 }
152
153 static const struct snd_kcontrol_new sof_controls[] = {
154         SOC_DAPM_PIN_SWITCH("Headphone Jack"),
155         SOC_DAPM_PIN_SWITCH("Headset Mic"),
156 };
157
158 static const struct snd_soc_dapm_widget sof_widgets[] = {
159         SND_SOC_DAPM_HP("Headphone Jack", NULL),
160         SND_SOC_DAPM_MIC("Headset Mic", NULL),
161 };
162
163 static const struct snd_soc_dapm_route sof_map[] = {
164         /* HP jack connectors - unknown if we have jack detection */
165         {"Headphone Jack", NULL, "HP"},
166
167         /* other jacks */
168         {"HS", NULL, "Headset Mic"},
169 };
170
171 /* sof audio machine driver for cs42l42 codec */
172 static struct snd_soc_card sof_audio_card_cs42l42 = {
173         .name = "cs42l42", /* the sof- prefix is added by the core */
174         .owner = THIS_MODULE,
175         .controls = sof_controls,
176         .num_controls = ARRAY_SIZE(sof_controls),
177         .dapm_widgets = sof_widgets,
178         .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
179         .dapm_routes = sof_map,
180         .num_dapm_routes = ARRAY_SIZE(sof_map),
181         .fully_routed = true,
182         .late_probe = sof_card_late_probe,
183 };
184
185 static struct snd_soc_dai_link_component cs42l42_component[] = {
186         {
187                 .name = "i2c-10134242:00",
188                 .dai_name = "cs42l42",
189         }
190 };
191
192 static int create_spk_amp_dai_links(struct device *dev,
193                                     struct snd_soc_dai_link *links,
194                                     struct snd_soc_dai_link_component *cpus,
195                                     int *id, enum sof_ssp_codec amp_type,
196                                     int ssp_amp)
197 {
198         int ret = 0;
199
200         /* speaker amp */
201         if (amp_type == CODEC_NONE)
202                 return 0;
203
204         links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
205                                          ssp_amp);
206         if (!links[*id].name) {
207                 ret = -ENOMEM;
208                 goto devm_err;
209         }
210
211         links[*id].id = *id;
212
213         switch (amp_type) {
214         case CODEC_MAX98357A:
215                 max_98357a_dai_link(&links[*id]);
216                 break;
217         case CODEC_MAX98360A:
218                 max_98360a_dai_link(&links[*id]);
219                 break;
220         default:
221                 dev_err(dev, "invalid amp type %d\n", amp_type);
222                 return -EINVAL;
223         }
224
225         links[*id].platforms = platform_component;
226         links[*id].num_platforms = ARRAY_SIZE(platform_component);
227         links[*id].dpcm_playback = 1;
228         /* firmware-generated echo reference */
229         links[*id].dpcm_capture = 1;
230
231         links[*id].no_pcm = 1;
232         links[*id].cpus = &cpus[*id];
233         links[*id].num_cpus = 1;
234
235         links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
236                                                    "SSP%d Pin", ssp_amp);
237         if (!links[*id].cpus->dai_name) {
238                 ret = -ENOMEM;
239                 goto devm_err;
240         }
241
242         (*id)++;
243
244 devm_err:
245         return ret;
246 }
247
248 static int create_hp_codec_dai_links(struct device *dev,
249                                      struct snd_soc_dai_link *links,
250                                      struct snd_soc_dai_link_component *cpus,
251                                      int *id, int ssp_codec)
252 {
253         /* codec SSP */
254         links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec",
255                                          ssp_codec);
256         if (!links[*id].name)
257                 goto devm_err;
258
259         links[*id].id = *id;
260         links[*id].codecs = cs42l42_component;
261         links[*id].num_codecs = ARRAY_SIZE(cs42l42_component);
262         links[*id].platforms = platform_component;
263         links[*id].num_platforms = ARRAY_SIZE(platform_component);
264         links[*id].init = sof_cs42l42_init;
265         links[*id].exit = sof_cs42l42_exit;
266         links[*id].ops = &sof_cs42l42_ops;
267         links[*id].dpcm_playback = 1;
268         links[*id].dpcm_capture = 1;
269         links[*id].no_pcm = 1;
270         links[*id].cpus = &cpus[*id];
271         links[*id].num_cpus = 1;
272
273         links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
274                                                    "SSP%d Pin",
275                                                    ssp_codec);
276         if (!links[*id].cpus->dai_name)
277                 goto devm_err;
278
279         (*id)++;
280
281         return 0;
282
283 devm_err:
284         return -ENOMEM;
285 }
286
287 static int create_bt_offload_dai_links(struct device *dev,
288                                        struct snd_soc_dai_link *links,
289                                        struct snd_soc_dai_link_component *cpus,
290                                        int *id, int ssp_bt)
291 {
292         /* bt offload */
293         if (!(sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT))
294                 return 0;
295
296         links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT",
297                                          ssp_bt);
298         if (!links[*id].name)
299                 goto devm_err;
300
301         links[*id].id = *id;
302         links[*id].codecs = &snd_soc_dummy_dlc;
303         links[*id].num_codecs = 1;
304         links[*id].platforms = platform_component;
305         links[*id].num_platforms = ARRAY_SIZE(platform_component);
306
307         links[*id].dpcm_playback = 1;
308         links[*id].dpcm_capture = 1;
309         links[*id].no_pcm = 1;
310         links[*id].cpus = &cpus[*id];
311         links[*id].num_cpus = 1;
312
313         links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
314                                                    "SSP%d Pin",
315                                                    ssp_bt);
316         if (!links[*id].cpus->dai_name)
317                 goto devm_err;
318
319         (*id)++;
320
321         return 0;
322
323 devm_err:
324         return -ENOMEM;
325 }
326
327 static struct snd_soc_dai_link *
328 sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type,
329                           int ssp_codec, int ssp_amp, int ssp_bt,
330                           int dmic_be_num, int hdmi_num, bool idisp_codec)
331 {
332         struct snd_soc_dai_link_component *cpus;
333         struct snd_soc_dai_link *links;
334         int ret;
335         int id = 0;
336         int link_seq;
337         int i;
338
339         links = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links,
340                             sizeof(struct snd_soc_dai_link), GFP_KERNEL);
341         cpus = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links,
342                             sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
343         if (!links || !cpus)
344                 goto devm_err;
345
346         link_seq = (sof_cs42l42_quirk & SOF_CS42L42_DAILINK_MASK) >> SOF_CS42L42_DAILINK_SHIFT;
347
348         while (link_seq) {
349                 int link_type = link_seq & 0x07;
350
351                 switch (link_type) {
352                 case LINK_HP:
353                         ret = create_hp_codec_dai_links(dev, links, cpus, &id, ssp_codec);
354                         if (ret < 0) {
355                                 dev_err(dev, "fail to create hp codec dai links, ret %d\n",
356                                         ret);
357                                 goto devm_err;
358                         }
359                         break;
360                 case LINK_SPK:
361                         ret = create_spk_amp_dai_links(dev, links, cpus, &id,
362                                                        amp_type, ssp_amp);
363                         if (ret < 0) {
364                                 dev_err(dev, "fail to create spk amp dai links, ret %d\n",
365                                         ret);
366                                 goto devm_err;
367                         }
368                         break;
369                 case LINK_DMIC:
370                         if (dmic_be_num > 0) {
371                                 /* at least we have dmic01 */
372                                 ret = sof_intel_board_set_dmic_link(dev,
373                                                                     &links[id],
374                                                                     id,
375                                                                     SOF_DMIC_01);
376                                 if (ret) {
377                                         dev_err(dev, "fail to create dmic01 link, ret %d\n",
378                                                 ret);
379                                         goto devm_err;
380                                 }
381
382                                 id++;
383                         }
384
385                         if (dmic_be_num > 1) {
386                                 /* set up 2 BE links at most */
387                                 ret = sof_intel_board_set_dmic_link(dev,
388                                                                     &links[id],
389                                                                     id,
390                                                                     SOF_DMIC_16K);
391                                 if (ret) {
392                                         dev_err(dev, "fail to create dmic16k link, ret %d\n",
393                                                 ret);
394                                         goto devm_err;
395                                 }
396
397                                 id++;
398                         }
399                         break;
400                 case LINK_HDMI:
401                         for (i = 1; i <= hdmi_num; i++) {
402                                 ret = sof_intel_board_set_intel_hdmi_link(dev,
403                                                                           &links[id],
404                                                                           id, i,
405                                                                           idisp_codec);
406                                 if (ret) {
407                                         dev_err(dev, "fail to create hdmi link, ret %d\n",
408                                                 ret);
409                                         goto devm_err;
410                                 }
411
412                                 id++;
413                         }
414                         break;
415                 case LINK_BT:
416                         ret = create_bt_offload_dai_links(dev, links, cpus, &id, ssp_bt);
417                         if (ret < 0) {
418                                 dev_err(dev, "fail to create bt offload dai links, ret %d\n",
419                                         ret);
420                                 goto devm_err;
421                         }
422                         break;
423                 case LINK_NONE:
424                         /* caught here if it's not used as terminator in macro */
425                 default:
426                         dev_err(dev, "invalid link type %d\n", link_type);
427                         goto devm_err;
428                 }
429
430                 link_seq >>= 3;
431         }
432
433         return links;
434 devm_err:
435         return NULL;
436 }
437
438 static int sof_audio_probe(struct platform_device *pdev)
439 {
440         struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
441         struct snd_soc_dai_link *dai_links;
442         struct sof_card_private *ctx;
443         int ret, ssp_bt, ssp_amp, ssp_codec;
444
445         ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
446         if (!ctx)
447                 return -ENOMEM;
448
449         if (pdev->id_entry && pdev->id_entry->driver_data)
450                 sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data;
451
452         ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev);
453         ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev);
454
455         if (soc_intel_is_glk()) {
456                 ctx->dmic_be_num = 1;
457                 ctx->hdmi_num = 3;
458         } else {
459                 ctx->dmic_be_num = 2;
460                 ctx->hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >>
461                          SOF_CS42L42_NUM_HDMIDEV_SHIFT;
462                 /* default number of HDMI DAI's */
463                 if (!ctx->hdmi_num)
464                         ctx->hdmi_num = 3;
465         }
466
467         if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
468                 ctx->hdmi.idisp_codec = true;
469
470         dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
471
472         ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >>
473                         SOF_CS42L42_SSP_BT_SHIFT;
474
475         ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
476                         SOF_CS42L42_SSP_AMP_SHIFT;
477
478         ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK;
479
480         /* compute number of dai links */
481         sof_audio_card_cs42l42.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num;
482
483         if (ctx->amp_type != CODEC_NONE)
484                 sof_audio_card_cs42l42.num_links++;
485         if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)
486                 sof_audio_card_cs42l42.num_links++;
487
488         dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type,
489                                               ssp_codec, ssp_amp, ssp_bt,
490                                               ctx->dmic_be_num, ctx->hdmi_num,
491                                               ctx->hdmi.idisp_codec);
492         if (!dai_links)
493                 return -ENOMEM;
494
495         sof_audio_card_cs42l42.dai_link = dai_links;
496
497         sof_audio_card_cs42l42.dev = &pdev->dev;
498
499         /* set platform name for each dailink */
500         ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_cs42l42,
501                                                     mach->mach_params.platform);
502         if (ret)
503                 return ret;
504
505         snd_soc_card_set_drvdata(&sof_audio_card_cs42l42, ctx);
506
507         return devm_snd_soc_register_card(&pdev->dev,
508                                           &sof_audio_card_cs42l42);
509 }
510
511 static const struct platform_device_id board_ids[] = {
512         {
513                 .name = "glk_cs4242_mx98357a",
514                 .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) |
515                                         SOF_CS42L42_SSP_AMP(1)) |
516                                         SOF_CS42L42_DAILINK(LINK_SPK, LINK_HP, LINK_DMIC, LINK_HDMI, LINK_NONE),
517         },
518         {
519                 .name = "jsl_cs4242_mx98360a",
520                 .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
521                                         SOF_CS42L42_SSP_AMP(1)) |
522                                         SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_NONE),
523         },
524         {
525                 .name = "adl_mx98360a_cs4242",
526                 .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
527                                 SOF_CS42L42_SSP_AMP(1) |
528                                 SOF_CS42L42_NUM_HDMIDEV(4) |
529                                 SOF_BT_OFFLOAD_PRESENT |
530                                 SOF_CS42L42_SSP_BT(2) |
531                                 SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_BT)),
532         },
533         { }
534 };
535 MODULE_DEVICE_TABLE(platform, board_ids);
536
537 static struct platform_driver sof_audio = {
538         .probe = sof_audio_probe,
539         .driver = {
540                 .name = "sof_cs42l42",
541                 .pm = &snd_soc_pm_ops,
542         },
543         .id_table = board_ids,
544 };
545 module_platform_driver(sof_audio)
546
547 /* Module information */
548 MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42");
549 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
550 MODULE_LICENSE("GPL");
551 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS);
552 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
553 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON);