Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[linux-2.6-microblaze.git] / sound / soc / qcom / sdm845.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4  */
5
6 #include <linux/module.h>
7 #include <linux/platform_device.h>
8 #include <linux/of_device.h>
9 #include <sound/core.h>
10 #include <sound/pcm.h>
11 #include <sound/pcm_params.h>
12 #include <sound/jack.h>
13 #include <sound/soc.h>
14 #include <linux/soundwire/sdw.h>
15 #include <uapi/linux/input-event-codes.h>
16 #include "common.h"
17 #include "qdsp6/q6afe.h"
18 #include "../codecs/rt5663.h"
19
20 #define DRIVER_NAME     "sdm845"
21 #define DEFAULT_SAMPLE_RATE_48K         48000
22 #define DEFAULT_MCLK_RATE               24576000
23 #define TDM_BCLK_RATE           6144000
24 #define MI2S_BCLK_RATE          1536000
25 #define LEFT_SPK_TDM_TX_MASK    0x30
26 #define RIGHT_SPK_TDM_TX_MASK   0xC0
27 #define SPK_TDM_RX_MASK         0x03
28 #define NUM_TDM_SLOTS           8
29 #define SLIM_MAX_TX_PORTS 16
30 #define SLIM_MAX_RX_PORTS 13
31 #define WCD934X_DEFAULT_MCLK_RATE       9600000
32
33 struct sdm845_snd_data {
34         struct snd_soc_jack jack;
35         bool jack_setup;
36         bool stream_prepared[AFE_PORT_MAX];
37         struct snd_soc_card *card;
38         uint32_t pri_mi2s_clk_count;
39         uint32_t sec_mi2s_clk_count;
40         uint32_t quat_tdm_clk_count;
41         struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
42 };
43
44 static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
45
46 static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
47                                      struct snd_pcm_hw_params *params)
48 {
49         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
50         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
51         struct snd_soc_dai *codec_dai;
52         struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
53         u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
54         struct sdw_stream_runtime *sruntime;
55         u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
56         int ret = 0, i;
57
58         for_each_rtd_codec_dais(rtd, i, codec_dai) {
59                 sruntime = snd_soc_dai_get_sdw_stream(codec_dai,
60                                                       substream->stream);
61                 if (sruntime != ERR_PTR(-ENOTSUPP))
62                         pdata->sruntime[cpu_dai->id] = sruntime;
63
64                 ret = snd_soc_dai_get_channel_map(codec_dai,
65                                 &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
66
67                 if (ret != 0 && ret != -ENOTSUPP) {
68                         pr_err("failed to get codec chan map, err:%d\n", ret);
69                         return ret;
70                 } else if (ret == -ENOTSUPP) {
71                         /* Ignore unsupported */
72                         continue;
73                 }
74
75                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
76                         ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
77                                                           rx_ch_cnt, rx_ch);
78                 else
79                         ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt,
80                                                           tx_ch, 0, NULL);
81         }
82
83         return 0;
84 }
85
86 static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
87                                         struct snd_pcm_hw_params *params)
88 {
89         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
90         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
91         struct snd_soc_dai *codec_dai;
92         int ret = 0, j;
93         int channels, slot_width;
94
95         switch (params_format(params)) {
96         case SNDRV_PCM_FORMAT_S16_LE:
97                 slot_width = 16;
98                 break;
99         default:
100                 dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
101                                 __func__, params_format(params));
102                 return -EINVAL;
103         }
104
105         channels = params_channels(params);
106         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
107                 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x3,
108                                 8, slot_width);
109                 if (ret < 0) {
110                         dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
111                                         __func__, ret);
112                         goto end;
113                 }
114
115                 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
116                                 channels, tdm_slot_offset);
117                 if (ret < 0) {
118                         dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
119                                         __func__, ret);
120                         goto end;
121                 }
122         } else {
123                 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0,
124                                 8, slot_width);
125                 if (ret < 0) {
126                         dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
127                                         __func__, ret);
128                         goto end;
129                 }
130
131                 ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
132                                 tdm_slot_offset, 0, NULL);
133                 if (ret < 0) {
134                         dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
135                                         __func__, ret);
136                         goto end;
137                 }
138         }
139
140         for_each_rtd_codec_dais(rtd, j, codec_dai) {
141
142                 if (!strcmp(codec_dai->component->name_prefix, "Left")) {
143                         ret = snd_soc_dai_set_tdm_slot(
144                                         codec_dai, LEFT_SPK_TDM_TX_MASK,
145                                         SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
146                                         slot_width);
147                         if (ret < 0) {
148                                 dev_err(rtd->dev,
149                                         "DEV0 TDM slot err:%d\n", ret);
150                                 return ret;
151                         }
152                 }
153
154                 if (!strcmp(codec_dai->component->name_prefix, "Right")) {
155                         ret = snd_soc_dai_set_tdm_slot(
156                                         codec_dai, RIGHT_SPK_TDM_TX_MASK,
157                                         SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
158                                         slot_width);
159                         if (ret < 0) {
160                                 dev_err(rtd->dev,
161                                         "DEV1 TDM slot err:%d\n", ret);
162                                 return ret;
163                         }
164                 }
165         }
166
167 end:
168         return ret;
169 }
170
171 static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
172                                         struct snd_pcm_hw_params *params)
173 {
174         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
175         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
176         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
177         int ret = 0;
178
179         switch (cpu_dai->id) {
180         case PRIMARY_MI2S_RX:
181         case PRIMARY_MI2S_TX:
182                 /*
183                  * Use ASRC for internal clocks, as PLL rate isn't multiple
184                  * of BCLK.
185                  */
186                 rt5663_sel_asrc_clk_src(
187                         codec_dai->component,
188                         RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
189                         RT5663_CLK_SEL_I2S1_ASRC);
190                 ret = snd_soc_dai_set_sysclk(
191                         codec_dai, RT5663_SCLK_S_MCLK, DEFAULT_MCLK_RATE,
192                         SND_SOC_CLOCK_IN);
193                 if (ret < 0)
194                         dev_err(rtd->dev,
195                                 "snd_soc_dai_set_sysclk err = %d\n", ret);
196                 break;
197         case QUATERNARY_TDM_RX_0:
198         case QUATERNARY_TDM_TX_0:
199                 ret = sdm845_tdm_snd_hw_params(substream, params);
200                 break;
201         case SLIMBUS_0_RX...SLIMBUS_6_TX:
202                 ret = sdm845_slim_snd_hw_params(substream, params);
203                 break;
204         case QUATERNARY_MI2S_RX:
205                 break;
206         default:
207                 pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
208                 break;
209         }
210         return ret;
211 }
212
213 static void sdm845_jack_free(struct snd_jack *jack)
214 {
215         struct snd_soc_component *component = jack->private_data;
216
217         snd_soc_component_set_jack(component, NULL, NULL);
218 }
219
220 static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
221 {
222         struct snd_soc_component *component;
223         struct snd_soc_card *card = rtd->card;
224         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
225         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
226         struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
227         struct snd_jack *jack;
228         /*
229          * Codec SLIMBUS configuration
230          * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
231          * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
232          * TX14, TX15, TX16
233          */
234         unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149,
235                                         150, 151, 152, 153, 154, 155, 156};
236         unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
237                                             134, 135, 136, 137, 138, 139,
238                                             140, 141, 142, 143};
239         int rval, i;
240
241
242         if (!pdata->jack_setup) {
243                 rval = snd_soc_card_jack_new(card, "Headset Jack",
244                                 SND_JACK_HEADSET |
245                                 SND_JACK_HEADPHONE |
246                                 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
247                                 SND_JACK_BTN_2 | SND_JACK_BTN_3,
248                                 &pdata->jack, NULL, 0);
249
250                 if (rval < 0) {
251                         dev_err(card->dev, "Unable to add Headphone Jack\n");
252                         return rval;
253                 }
254
255                 jack = pdata->jack.jack;
256
257                 snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
258                 snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
259                 snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
260                 snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
261                 pdata->jack_setup = true;
262         }
263
264         switch (cpu_dai->id) {
265         case PRIMARY_MI2S_RX:
266                 jack  = pdata->jack.jack;
267                 component = codec_dai->component;
268
269                 jack->private_data = component;
270                 jack->private_free = sdm845_jack_free;
271                 rval = snd_soc_component_set_jack(component,
272                                                   &pdata->jack, NULL);
273                 if (rval != 0 && rval != -ENOTSUPP) {
274                         dev_warn(card->dev, "Failed to set jack: %d\n", rval);
275                         return rval;
276                 }
277                 break;
278         case SLIMBUS_0_RX...SLIMBUS_6_TX:
279                 for_each_rtd_codec_dais(rtd, i, codec_dai) {
280                         rval = snd_soc_dai_set_channel_map(codec_dai,
281                                                           ARRAY_SIZE(tx_ch),
282                                                           tx_ch,
283                                                           ARRAY_SIZE(rx_ch),
284                                                           rx_ch);
285                         if (rval != 0 && rval != -ENOTSUPP)
286                                 return rval;
287
288                         snd_soc_dai_set_sysclk(codec_dai, 0,
289                                                WCD934X_DEFAULT_MCLK_RATE,
290                                                SNDRV_PCM_STREAM_PLAYBACK);
291                 }
292                 break;
293         default:
294                 break;
295         }
296
297         return 0;
298 }
299
300
301 static int sdm845_snd_startup(struct snd_pcm_substream *substream)
302 {
303         unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
304         unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
305         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
306         struct snd_soc_card *card = rtd->card;
307         struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
308         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
309         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
310         int j;
311         int ret;
312
313         switch (cpu_dai->id) {
314         case PRIMARY_MI2S_RX:
315         case PRIMARY_MI2S_TX:
316                 codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF;
317                 if (++(data->pri_mi2s_clk_count) == 1) {
318                         snd_soc_dai_set_sysclk(cpu_dai,
319                                 Q6AFE_LPASS_CLK_ID_MCLK_1,
320                                 DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
321                         snd_soc_dai_set_sysclk(cpu_dai,
322                                 Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
323                                 MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
324                 }
325                 snd_soc_dai_set_fmt(cpu_dai, fmt);
326                 snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
327                 break;
328
329         case SECONDARY_MI2S_TX:
330                 codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
331                 if (++(data->sec_mi2s_clk_count) == 1) {
332                         snd_soc_dai_set_sysclk(cpu_dai,
333                                 Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
334                                 MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
335                 }
336                 snd_soc_dai_set_fmt(cpu_dai, fmt);
337                 snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
338                 break;
339         case QUATERNARY_MI2S_RX:
340                 snd_soc_dai_set_sysclk(cpu_dai,
341                         Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
342                         MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
343                 snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
344
345
346                 break;
347
348         case QUATERNARY_TDM_RX_0:
349         case QUATERNARY_TDM_TX_0:
350                 if (++(data->quat_tdm_clk_count) == 1) {
351                         snd_soc_dai_set_sysclk(cpu_dai,
352                                 Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
353                                 TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
354                 }
355
356                 codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
357
358                 for_each_rtd_codec_dais(rtd, j, codec_dai) {
359
360                         if (!strcmp(codec_dai->component->name_prefix,
361                                     "Left")) {
362                                 ret = snd_soc_dai_set_fmt(
363                                                 codec_dai, codec_dai_fmt);
364                                 if (ret < 0) {
365                                         dev_err(rtd->dev,
366                                                 "Left TDM fmt err:%d\n", ret);
367                                         return ret;
368                                 }
369                         }
370
371                         if (!strcmp(codec_dai->component->name_prefix,
372                                     "Right")) {
373                                 ret = snd_soc_dai_set_fmt(
374                                                 codec_dai, codec_dai_fmt);
375                                 if (ret < 0) {
376                                         dev_err(rtd->dev,
377                                                 "Right TDM slot err:%d\n", ret);
378                                         return ret;
379                                 }
380                         }
381                 }
382                 break;
383         case SLIMBUS_0_RX...SLIMBUS_6_TX:
384                 break;
385
386         default:
387                 pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
388                 break;
389         }
390         return 0;
391 }
392
393 static void  sdm845_snd_shutdown(struct snd_pcm_substream *substream)
394 {
395         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
396         struct snd_soc_card *card = rtd->card;
397         struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
398         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
399
400         switch (cpu_dai->id) {
401         case PRIMARY_MI2S_RX:
402         case PRIMARY_MI2S_TX:
403                 if (--(data->pri_mi2s_clk_count) == 0) {
404                         snd_soc_dai_set_sysclk(cpu_dai,
405                                 Q6AFE_LPASS_CLK_ID_MCLK_1,
406                                 0, SNDRV_PCM_STREAM_PLAYBACK);
407                         snd_soc_dai_set_sysclk(cpu_dai,
408                                 Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
409                                 0, SNDRV_PCM_STREAM_PLAYBACK);
410                 }
411                 break;
412
413         case SECONDARY_MI2S_TX:
414                 if (--(data->sec_mi2s_clk_count) == 0) {
415                         snd_soc_dai_set_sysclk(cpu_dai,
416                                 Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
417                                 0, SNDRV_PCM_STREAM_CAPTURE);
418                 }
419                 break;
420
421         case QUATERNARY_TDM_RX_0:
422         case QUATERNARY_TDM_TX_0:
423                 if (--(data->quat_tdm_clk_count) == 0) {
424                         snd_soc_dai_set_sysclk(cpu_dai,
425                                 Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
426                                 0, SNDRV_PCM_STREAM_PLAYBACK);
427                 }
428                 break;
429         case SLIMBUS_0_RX...SLIMBUS_6_TX:
430         case QUATERNARY_MI2S_RX:
431                 break;
432
433         default:
434                 pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
435                 break;
436         }
437 }
438
439 static int sdm845_snd_prepare(struct snd_pcm_substream *substream)
440 {
441         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
442         struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
443         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
444         struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
445         int ret;
446
447         if (!sruntime)
448                 return 0;
449
450         if (data->stream_prepared[cpu_dai->id]) {
451                 sdw_disable_stream(sruntime);
452                 sdw_deprepare_stream(sruntime);
453                 data->stream_prepared[cpu_dai->id] = false;
454         }
455
456         ret = sdw_prepare_stream(sruntime);
457         if (ret)
458                 return ret;
459
460         /**
461          * NOTE: there is a strict hw requirement about the ordering of port
462          * enables and actual WSA881x PA enable. PA enable should only happen
463          * after soundwire ports are enabled if not DC on the line is
464          * accumulated resulting in Click/Pop Noise
465          * PA enable/mute are handled as part of codec DAPM and digital mute.
466          */
467
468         ret = sdw_enable_stream(sruntime);
469         if (ret) {
470                 sdw_deprepare_stream(sruntime);
471                 return ret;
472         }
473         data->stream_prepared[cpu_dai->id] = true;
474
475         return ret;
476 }
477
478 static int sdm845_snd_hw_free(struct snd_pcm_substream *substream)
479 {
480         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
481         struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
482         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
483         struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
484
485         if (sruntime && data->stream_prepared[cpu_dai->id]) {
486                 sdw_disable_stream(sruntime);
487                 sdw_deprepare_stream(sruntime);
488                 data->stream_prepared[cpu_dai->id] = false;
489         }
490
491         return 0;
492 }
493
494 static const struct snd_soc_ops sdm845_be_ops = {
495         .hw_params = sdm845_snd_hw_params,
496         .hw_free = sdm845_snd_hw_free,
497         .prepare = sdm845_snd_prepare,
498         .startup = sdm845_snd_startup,
499         .shutdown = sdm845_snd_shutdown,
500 };
501
502 static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
503                                 struct snd_pcm_hw_params *params)
504 {
505         struct snd_interval *rate = hw_param_interval(params,
506                                         SNDRV_PCM_HW_PARAM_RATE);
507         struct snd_interval *channels = hw_param_interval(params,
508                                         SNDRV_PCM_HW_PARAM_CHANNELS);
509         struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
510
511         rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
512         channels->min = channels->max = 2;
513         snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
514
515         return 0;
516 }
517
518 static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
519         SND_SOC_DAPM_HP("Headphone Jack", NULL),
520         SND_SOC_DAPM_MIC("Headset Mic", NULL),
521         SND_SOC_DAPM_SPK("Left Spk", NULL),
522         SND_SOC_DAPM_SPK("Right Spk", NULL),
523         SND_SOC_DAPM_MIC("Int Mic", NULL),
524 };
525
526 static void sdm845_add_ops(struct snd_soc_card *card)
527 {
528         struct snd_soc_dai_link *link;
529         int i;
530
531         for_each_card_prelinks(card, i, link) {
532                 if (link->no_pcm == 1) {
533                         link->ops = &sdm845_be_ops;
534                         link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
535                 }
536                 link->init = sdm845_dai_init;
537         }
538 }
539
540 static int sdm845_snd_platform_probe(struct platform_device *pdev)
541 {
542         struct snd_soc_card *card;
543         struct sdm845_snd_data *data;
544         struct device *dev = &pdev->dev;
545         int ret;
546
547         card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
548         if (!card)
549                 return -ENOMEM;
550
551         /* Allocate the private data */
552         data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
553         if (!data)
554                 return -ENOMEM;
555
556         card->driver_name = DRIVER_NAME;
557         card->dapm_widgets = sdm845_snd_widgets;
558         card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
559         card->dev = dev;
560         card->owner = THIS_MODULE;
561         dev_set_drvdata(dev, card);
562         ret = qcom_snd_parse_of(card);
563         if (ret)
564                 return ret;
565
566         data->card = card;
567         snd_soc_card_set_drvdata(card, data);
568
569         sdm845_add_ops(card);
570         return devm_snd_soc_register_card(dev, card);
571 }
572
573 static const struct of_device_id sdm845_snd_device_id[]  = {
574         { .compatible = "qcom,sdm845-sndcard" },
575         { .compatible = "qcom,db845c-sndcard" },
576         { .compatible = "lenovo,yoga-c630-sndcard" },
577         {},
578 };
579 MODULE_DEVICE_TABLE(of, sdm845_snd_device_id);
580
581 static struct platform_driver sdm845_snd_driver = {
582         .probe = sdm845_snd_platform_probe,
583         .driver = {
584                 .name = "msm-snd-sdm845",
585                 .of_match_table = sdm845_snd_device_id,
586         },
587 };
588 module_platform_driver(sdm845_snd_driver);
589
590 MODULE_DESCRIPTION("sdm845 ASoC Machine Driver");
591 MODULE_LICENSE("GPL v2");