OSDN Git Service

MAINTAINERS: add entry for redpine wireless driver
[uclinux-h8/linux.git] / sound / soc / intel / boards / glk_rt5682_max98357a.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright(c) 2018 Intel Corporation.
3
4 /*
5  * Intel Geminilake I2S Machine Driver with MAX98357A & RT5682 Codecs
6  *
7  * Modified from:
8  *   Intel Apollolake I2S Machine driver
9  */
10
11 #include <linux/input.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.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 "../skylake/skl.h"
20 #include "../../codecs/rt5682.h"
21 #include "../../codecs/hdac_hdmi.h"
22
23 /* The platform clock outputs 19.2Mhz clock to codec as I2S MCLK */
24 #define GLK_PLAT_CLK_FREQ 19200000
25 #define RT5682_PLL_FREQ (48000 * 512)
26 #define GLK_REALTEK_CODEC_DAI "rt5682-aif1"
27 #define GLK_MAXIM_CODEC_DAI "HiFi"
28 #define MAXIM_DEV0_NAME "MX98357A:00"
29 #define DUAL_CHANNEL 2
30 #define QUAD_CHANNEL 4
31 #define NAME_SIZE 32
32
33 static struct snd_soc_jack geminilake_hdmi[3];
34
35 struct glk_hdmi_pcm {
36         struct list_head head;
37         struct snd_soc_dai *codec_dai;
38         int device;
39 };
40
41 struct glk_card_private {
42         struct snd_soc_jack geminilake_headset;
43         struct list_head hdmi_pcm_list;
44 };
45
46 enum {
47         GLK_DPCM_AUDIO_PB = 0,
48         GLK_DPCM_AUDIO_CP,
49         GLK_DPCM_AUDIO_HS_PB,
50         GLK_DPCM_AUDIO_ECHO_REF_CP,
51         GLK_DPCM_AUDIO_REF_CP,
52         GLK_DPCM_AUDIO_DMIC_CP,
53         GLK_DPCM_AUDIO_HDMI1_PB,
54         GLK_DPCM_AUDIO_HDMI2_PB,
55         GLK_DPCM_AUDIO_HDMI3_PB,
56 };
57
58 static int platform_clock_control(struct snd_soc_dapm_widget *w,
59                                         struct snd_kcontrol *k, int  event)
60 {
61         struct snd_soc_dapm_context *dapm = w->dapm;
62         struct snd_soc_card *card = dapm->card;
63         struct snd_soc_dai *codec_dai;
64         int ret = 0;
65
66         codec_dai = snd_soc_card_get_codec_dai(card, GLK_REALTEK_CODEC_DAI);
67         if (!codec_dai) {
68                 dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
69                 return -EIO;
70         }
71
72         if (SND_SOC_DAPM_EVENT_OFF(event)) {
73                 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
74                 if (ret)
75                         dev_err(card->dev, "failed to stop sysclk: %d\n", ret);
76         } else if (SND_SOC_DAPM_EVENT_ON(event)) {
77                 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK,
78                                         GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ);
79                 if (ret < 0) {
80                         dev_err(card->dev, "can't set codec pll: %d\n", ret);
81                         return ret;
82                 }
83         }
84
85         if (ret)
86                 dev_err(card->dev, "failed to start internal clk: %d\n", ret);
87
88         return ret;
89 }
90
91 static const struct snd_kcontrol_new geminilake_controls[] = {
92         SOC_DAPM_PIN_SWITCH("Headphone Jack"),
93         SOC_DAPM_PIN_SWITCH("Headset Mic"),
94         SOC_DAPM_PIN_SWITCH("Spk"),
95 };
96
97 static const struct snd_soc_dapm_widget geminilake_widgets[] = {
98         SND_SOC_DAPM_HP("Headphone Jack", NULL),
99         SND_SOC_DAPM_MIC("Headset Mic", NULL),
100         SND_SOC_DAPM_SPK("Spk", NULL),
101         SND_SOC_DAPM_MIC("SoC DMIC", NULL),
102         SND_SOC_DAPM_SPK("HDMI1", NULL),
103         SND_SOC_DAPM_SPK("HDMI2", NULL),
104         SND_SOC_DAPM_SPK("HDMI3", NULL),
105         SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
106                         platform_clock_control, SND_SOC_DAPM_PRE_PMU |
107                         SND_SOC_DAPM_POST_PMD),
108 };
109
110 static const struct snd_soc_dapm_route geminilake_map[] = {
111         /* HP jack connectors - unknown if we have jack detection */
112         { "Headphone Jack", NULL, "Platform Clock" },
113         { "Headphone Jack", NULL, "HPOL" },
114         { "Headphone Jack", NULL, "HPOR" },
115
116         /* speaker */
117         { "Spk", NULL, "Speaker" },
118
119         /* other jacks */
120         { "Headset Mic", NULL, "Platform Clock" },
121         { "IN1P", NULL, "Headset Mic" },
122
123         /* digital mics */
124         { "DMic", NULL, "SoC DMIC" },
125
126         /* CODEC BE connections */
127         { "HiFi Playback", NULL, "ssp1 Tx" },
128         { "ssp1 Tx", NULL, "codec0_out" },
129
130         { "AIF1 Playback", NULL, "ssp2 Tx" },
131         { "ssp2 Tx", NULL, "codec1_out" },
132
133         { "codec0_in", NULL, "ssp2 Rx" },
134         { "ssp2 Rx", NULL, "AIF1 Capture" },
135
136         { "HDMI1", NULL, "hif5-0 Output" },
137         { "HDMI2", NULL, "hif6-0 Output" },
138         { "HDMI2", NULL, "hif7-0 Output" },
139
140         { "hifi3", NULL, "iDisp3 Tx" },
141         { "iDisp3 Tx", NULL, "iDisp3_out" },
142         { "hifi2", NULL, "iDisp2 Tx" },
143         { "iDisp2 Tx", NULL, "iDisp2_out" },
144         { "hifi1", NULL, "iDisp1 Tx" },
145         { "iDisp1 Tx", NULL, "iDisp1_out" },
146
147         /* DMIC */
148         { "dmic01_hifi", NULL, "DMIC01 Rx" },
149         { "DMIC01 Rx", NULL, "DMIC AIF" },
150 };
151
152 static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
153                         struct snd_pcm_hw_params *params)
154 {
155         struct snd_interval *rate = hw_param_interval(params,
156                         SNDRV_PCM_HW_PARAM_RATE);
157         struct snd_interval *channels = hw_param_interval(params,
158                         SNDRV_PCM_HW_PARAM_CHANNELS);
159         struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
160
161         /* The ADSP will convert the FE rate to 48k, stereo */
162         rate->min = rate->max = 48000;
163         channels->min = channels->max = DUAL_CHANNEL;
164
165         /* set SSP to 24 bit */
166         snd_mask_none(fmt);
167         snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
168
169         return 0;
170 }
171
172 static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
173 {
174         struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
175         struct snd_soc_component *component = rtd->codec_dai->component;
176         struct snd_soc_dai *codec_dai = rtd->codec_dai;
177         struct snd_soc_jack *jack;
178         int ret;
179
180         /* Configure sysclk for codec */
181         ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
182                                         RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
183         if (ret < 0)
184                 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
185
186         /*
187          * Headset buttons map to the google Reference headset.
188          * These can be configured by userspace.
189          */
190         ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
191                         SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
192                         SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
193                         &ctx->geminilake_headset, NULL, 0);
194         if (ret) {
195                 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
196                 return ret;
197         }
198
199         jack = &ctx->geminilake_headset;
200
201         snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
202         snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
203         snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
204         snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
205         ret = snd_soc_component_set_jack(component, jack, NULL);
206
207         if (ret) {
208                 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
209                 return ret;
210         }
211
212         return ret;
213 };
214
215 static int geminilake_rt5682_hw_params(struct snd_pcm_substream *substream,
216         struct snd_pcm_hw_params *params)
217 {
218         struct snd_soc_pcm_runtime *rtd = substream->private_data;
219         struct snd_soc_dai *codec_dai = rtd->codec_dai;
220         int ret;
221
222         /* Set valid bitmask & configuration for I2S in 24 bit */
223         ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, 24);
224         if (ret < 0) {
225                 dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
226                 return ret;
227         }
228
229         return ret;
230 }
231
232 static struct snd_soc_ops geminilake_rt5682_ops = {
233         .hw_params = geminilake_rt5682_hw_params,
234 };
235
236 static int geminilake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
237 {
238         struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
239         struct snd_soc_dai *dai = rtd->codec_dai;
240         struct glk_hdmi_pcm *pcm;
241
242         pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
243         if (!pcm)
244                 return -ENOMEM;
245
246         pcm->device = GLK_DPCM_AUDIO_HDMI1_PB + dai->id;
247         pcm->codec_dai = dai;
248
249         list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
250
251         return 0;
252 }
253
254 static int geminilake_rt5682_fe_init(struct snd_soc_pcm_runtime *rtd)
255 {
256         struct snd_soc_component *component = rtd->cpu_dai->component;
257         struct snd_soc_dapm_context *dapm;
258         int ret;
259
260         dapm = snd_soc_component_get_dapm(component);
261         ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
262         if (ret) {
263                 dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret);
264                 return ret;
265         }
266
267         return ret;
268 }
269
270 static const unsigned int rates[] = {
271         48000,
272 };
273
274 static const struct snd_pcm_hw_constraint_list constraints_rates = {
275         .count = ARRAY_SIZE(rates),
276         .list  = rates,
277         .mask = 0,
278 };
279
280 static const unsigned int channels[] = {
281         DUAL_CHANNEL,
282 };
283
284 static const struct snd_pcm_hw_constraint_list constraints_channels = {
285         .count = ARRAY_SIZE(channels),
286         .list = channels,
287         .mask = 0,
288 };
289
290 static unsigned int channels_quad[] = {
291         QUAD_CHANNEL,
292 };
293
294 static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
295         .count = ARRAY_SIZE(channels_quad),
296         .list = channels_quad,
297         .mask = 0,
298 };
299
300 static int geminilake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
301                 struct snd_pcm_hw_params *params)
302 {
303         struct snd_interval *channels = hw_param_interval(params,
304                                 SNDRV_PCM_HW_PARAM_CHANNELS);
305
306         /*
307          * set BE channel constraint as user FE channels
308          */
309         channels->min = channels->max = 4;
310
311         return 0;
312 }
313
314 static int geminilake_dmic_startup(struct snd_pcm_substream *substream)
315 {
316         struct snd_pcm_runtime *runtime = substream->runtime;
317
318         runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
319         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
320                         &constraints_channels_quad);
321
322         return snd_pcm_hw_constraint_list(substream->runtime, 0,
323                         SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
324 }
325
326 static const struct snd_soc_ops geminilake_dmic_ops = {
327         .startup = geminilake_dmic_startup,
328 };
329
330 static const unsigned int rates_16000[] = {
331         16000,
332 };
333
334 static const struct snd_pcm_hw_constraint_list constraints_16000 = {
335         .count = ARRAY_SIZE(rates_16000),
336         .list  = rates_16000,
337 };
338
339 static int geminilake_refcap_startup(struct snd_pcm_substream *substream)
340 {
341         return snd_pcm_hw_constraint_list(substream->runtime, 0,
342                                 SNDRV_PCM_HW_PARAM_RATE,
343                                 &constraints_16000);
344 };
345
346 static const struct snd_soc_ops geminilake_refcap_ops = {
347         .startup = geminilake_refcap_startup,
348 };
349
350 /* geminilake digital audio interface glue - connects codec <--> CPU */
351 static struct snd_soc_dai_link geminilake_dais[] = {
352         /* Front End DAI links */
353         [GLK_DPCM_AUDIO_PB] = {
354                 .name = "Glk Audio Port",
355                 .stream_name = "Audio",
356                 .cpu_dai_name = "System Pin",
357                 .platform_name = "0000:00:0e.0",
358                 .dynamic = 1,
359                 .codec_name = "snd-soc-dummy",
360                 .codec_dai_name = "snd-soc-dummy-dai",
361                 .nonatomic = 1,
362                 .init = geminilake_rt5682_fe_init,
363                 .trigger = {
364                         SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
365                 .dpcm_playback = 1,
366         },
367         [GLK_DPCM_AUDIO_CP] = {
368                 .name = "Glk Audio Capture Port",
369                 .stream_name = "Audio Record",
370                 .cpu_dai_name = "System Pin",
371                 .platform_name = "0000:00:0e.0",
372                 .dynamic = 1,
373                 .codec_name = "snd-soc-dummy",
374                 .codec_dai_name = "snd-soc-dummy-dai",
375                 .nonatomic = 1,
376                 .trigger = {
377                         SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
378                 .dpcm_capture = 1,
379         },
380         [GLK_DPCM_AUDIO_HS_PB] = {
381                 .name = "Glk Audio Headset Playback",
382                 .stream_name = "Headset Audio",
383                 .cpu_dai_name = "System Pin2",
384                 .platform_name = "0000:00:0e.0",
385                 .codec_name = "snd-soc-dummy",
386                 .codec_dai_name = "snd-soc-dummy-dai",
387                 .dpcm_playback = 1,
388                 .nonatomic = 1,
389                 .dynamic = 1,
390         },
391         [GLK_DPCM_AUDIO_ECHO_REF_CP] = {
392                 .name = "Glk Audio Echo Reference cap",
393                 .stream_name = "Echoreference Capture",
394                 .cpu_dai_name = "Echoref Pin",
395                 .platform_name = "0000:00:0e.0",
396                 .codec_name = "snd-soc-dummy",
397                 .codec_dai_name = "snd-soc-dummy-dai",
398                 .init = NULL,
399                 .capture_only = 1,
400                 .nonatomic = 1,
401         },
402         [GLK_DPCM_AUDIO_REF_CP] = {
403                 .name = "Glk Audio Reference cap",
404                 .stream_name = "Refcap",
405                 .cpu_dai_name = "Reference Pin",
406                 .codec_name = "snd-soc-dummy",
407                 .codec_dai_name = "snd-soc-dummy-dai",
408                 .platform_name = "0000:00:0e.0",
409                 .init = NULL,
410                 .dpcm_capture = 1,
411                 .nonatomic = 1,
412                 .dynamic = 1,
413                 .ops = &geminilake_refcap_ops,
414         },
415         [GLK_DPCM_AUDIO_DMIC_CP] = {
416                 .name = "Glk Audio DMIC cap",
417                 .stream_name = "dmiccap",
418                 .cpu_dai_name = "DMIC Pin",
419                 .codec_name = "snd-soc-dummy",
420                 .codec_dai_name = "snd-soc-dummy-dai",
421                 .platform_name = "0000:00:0e.0",
422                 .init = NULL,
423                 .dpcm_capture = 1,
424                 .nonatomic = 1,
425                 .dynamic = 1,
426                 .ops = &geminilake_dmic_ops,
427         },
428         [GLK_DPCM_AUDIO_HDMI1_PB] = {
429                 .name = "Glk HDMI Port1",
430                 .stream_name = "Hdmi1",
431                 .cpu_dai_name = "HDMI1 Pin",
432                 .codec_name = "snd-soc-dummy",
433                 .codec_dai_name = "snd-soc-dummy-dai",
434                 .platform_name = "0000:00:0e.0",
435                 .dpcm_playback = 1,
436                 .init = NULL,
437                 .trigger = {
438                         SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
439                 .nonatomic = 1,
440                 .dynamic = 1,
441         },
442         [GLK_DPCM_AUDIO_HDMI2_PB] =     {
443                 .name = "Glk HDMI Port2",
444                 .stream_name = "Hdmi2",
445                 .cpu_dai_name = "HDMI2 Pin",
446                 .codec_name = "snd-soc-dummy",
447                 .codec_dai_name = "snd-soc-dummy-dai",
448                 .platform_name = "0000:00:0e.0",
449                 .dpcm_playback = 1,
450                 .init = NULL,
451                 .trigger = {
452                         SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
453                 .nonatomic = 1,
454                 .dynamic = 1,
455         },
456         [GLK_DPCM_AUDIO_HDMI3_PB] =     {
457                 .name = "Glk HDMI Port3",
458                 .stream_name = "Hdmi3",
459                 .cpu_dai_name = "HDMI3 Pin",
460                 .codec_name = "snd-soc-dummy",
461                 .codec_dai_name = "snd-soc-dummy-dai",
462                 .platform_name = "0000:00:0e.0",
463                 .trigger = {
464                         SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
465                 .dpcm_playback = 1,
466                 .init = NULL,
467                 .nonatomic = 1,
468                 .dynamic = 1,
469         },
470         /* Back End DAI links */
471         {
472                 /* SSP1 - Codec */
473                 .name = "SSP1-Codec",
474                 .id = 0,
475                 .cpu_dai_name = "SSP1 Pin",
476                 .platform_name = "0000:00:0e.0",
477                 .no_pcm = 1,
478                 .codec_name = MAXIM_DEV0_NAME,
479                 .codec_dai_name = GLK_MAXIM_CODEC_DAI,
480                 .dai_fmt = SND_SOC_DAIFMT_I2S |
481                         SND_SOC_DAIFMT_NB_NF |
482                         SND_SOC_DAIFMT_CBS_CFS,
483                 .ignore_pmdown_time = 1,
484                 .be_hw_params_fixup = geminilake_ssp_fixup,
485                 .dpcm_playback = 1,
486         },
487         {
488                 /* SSP2 - Codec */
489                 .name = "SSP2-Codec",
490                 .id = 1,
491                 .cpu_dai_name = "SSP2 Pin",
492                 .platform_name = "0000:00:0e.0",
493                 .no_pcm = 1,
494                 .codec_name = "i2c-10EC5682:00",
495                 .codec_dai_name = GLK_REALTEK_CODEC_DAI,
496                 .init = geminilake_rt5682_codec_init,
497                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
498                         SND_SOC_DAIFMT_CBS_CFS,
499                 .ignore_pmdown_time = 1,
500                 .be_hw_params_fixup = geminilake_ssp_fixup,
501                 .ops = &geminilake_rt5682_ops,
502                 .dpcm_playback = 1,
503                 .dpcm_capture = 1,
504         },
505         {
506                 .name = "dmic01",
507                 .id = 2,
508                 .cpu_dai_name = "DMIC01 Pin",
509                 .codec_name = "dmic-codec",
510                 .codec_dai_name = "dmic-hifi",
511                 .platform_name = "0000:00:0e.0",
512                 .ignore_suspend = 1,
513                 .be_hw_params_fixup = geminilake_dmic_fixup,
514                 .dpcm_capture = 1,
515                 .no_pcm = 1,
516         },
517         {
518                 .name = "iDisp1",
519                 .id = 3,
520                 .cpu_dai_name = "iDisp1 Pin",
521                 .codec_name = "ehdaudio0D2",
522                 .codec_dai_name = "intel-hdmi-hifi1",
523                 .platform_name = "0000:00:0e.0",
524                 .init = geminilake_hdmi_init,
525                 .dpcm_playback = 1,
526                 .no_pcm = 1,
527         },
528         {
529                 .name = "iDisp2",
530                 .id = 4,
531                 .cpu_dai_name = "iDisp2 Pin",
532                 .codec_name = "ehdaudio0D2",
533                 .codec_dai_name = "intel-hdmi-hifi2",
534                 .platform_name = "0000:00:0e.0",
535                 .init = geminilake_hdmi_init,
536                 .dpcm_playback = 1,
537                 .no_pcm = 1,
538         },
539         {
540                 .name = "iDisp3",
541                 .id = 5,
542                 .cpu_dai_name = "iDisp3 Pin",
543                 .codec_name = "ehdaudio0D2",
544                 .codec_dai_name = "intel-hdmi-hifi3",
545                 .platform_name = "0000:00:0e.0",
546                 .init = geminilake_hdmi_init,
547                 .dpcm_playback = 1,
548                 .no_pcm = 1,
549         },
550 };
551
552 static int glk_card_late_probe(struct snd_soc_card *card)
553 {
554         struct glk_card_private *ctx = snd_soc_card_get_drvdata(card);
555         struct snd_soc_component *component = NULL;
556         char jack_name[NAME_SIZE];
557         struct glk_hdmi_pcm *pcm;
558         int err = 0;
559         int i = 0;
560
561         list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
562                 component = pcm->codec_dai->component;
563                 snprintf(jack_name, sizeof(jack_name),
564                         "HDMI/DP, pcm=%d Jack", pcm->device);
565                 err = snd_soc_card_jack_new(card, jack_name,
566                                         SND_JACK_AVOUT, &geminilake_hdmi[i],
567                                         NULL, 0);
568
569                 if (err)
570                         return err;
571
572                 err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
573                                                 &geminilake_hdmi[i]);
574                 if (err < 0)
575                         return err;
576
577                 i++;
578         }
579
580         if (!component)
581                 return -EINVAL;
582
583         return hdac_hdmi_jack_port_init(component, &card->dapm);
584 }
585
586 /* geminilake audio machine driver for SPT + RT5682 */
587 static struct snd_soc_card glk_audio_card_rt5682_m98357a = {
588         .name = "glkrt5682max",
589         .owner = THIS_MODULE,
590         .dai_link = geminilake_dais,
591         .num_links = ARRAY_SIZE(geminilake_dais),
592         .controls = geminilake_controls,
593         .num_controls = ARRAY_SIZE(geminilake_controls),
594         .dapm_widgets = geminilake_widgets,
595         .num_dapm_widgets = ARRAY_SIZE(geminilake_widgets),
596         .dapm_routes = geminilake_map,
597         .num_dapm_routes = ARRAY_SIZE(geminilake_map),
598         .fully_routed = true,
599         .late_probe = glk_card_late_probe,
600 };
601
602 static int geminilake_audio_probe(struct platform_device *pdev)
603 {
604         struct glk_card_private *ctx;
605
606         ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
607         if (!ctx)
608                 return -ENOMEM;
609
610         INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
611
612         glk_audio_card_rt5682_m98357a.dev = &pdev->dev;
613         snd_soc_card_set_drvdata(&glk_audio_card_rt5682_m98357a, ctx);
614
615         return devm_snd_soc_register_card(&pdev->dev,
616                                         &glk_audio_card_rt5682_m98357a);
617 }
618
619 static const struct platform_device_id glk_board_ids[] = {
620         {
621                 .name = "glk_rt5682_max98357a",
622                 .driver_data =
623                         (kernel_ulong_t)&glk_audio_card_rt5682_m98357a,
624         },
625         { }
626 };
627
628 static struct platform_driver geminilake_audio = {
629         .probe = geminilake_audio_probe,
630         .driver = {
631                 .name = "glk_rt5682_max98357a",
632                 .pm = &snd_soc_pm_ops,
633         },
634         .id_table = glk_board_ids,
635 };
636 module_platform_driver(geminilake_audio)
637
638 /* Module information */
639 MODULE_DESCRIPTION("Geminilake Audio Machine driver-RT5682 & MAX98357A in I2S mode");
640 MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
641 MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
642 MODULE_LICENSE("GPL v2");
643 MODULE_ALIAS("platform:glk_rt5682_max98357a");