GNU Linux-libre 4.19.304-gnu1
[releases.git] / sound / soc / samsung / tm2_wm5110.c
1 /*
2  * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
3  *
4  * Authors: Inha Song <ideal.song@samsung.com>
5  *          Sylwester Nawrocki <s.nawrocki@samsung.com>
6  *
7  * This program is free software; you can redistribute  it and/or modify it
8  * under  the terms of  the GNU General  Public License as published by the
9  * Free Software Foundation;  either version 2 of the  License, or (at your
10  * option) any later version.
11  */
12
13 #include <linux/clk.h>
14 #include <linux/gpio.h>
15 #include <linux/gpio/consumer.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
20
21 #include "i2s.h"
22 #include "../codecs/wm5110.h"
23
24 /*
25  * The source clock is XCLKOUT with its mux set to the external fixed rate
26  * oscillator (XXTI).
27  */
28 #define MCLK_RATE       24000000U
29
30 #define TM2_DAI_AIF1    0
31 #define TM2_DAI_AIF2    1
32
33 struct tm2_machine_priv {
34         struct snd_soc_component *component;
35         unsigned int sysclk_rate;
36         struct gpio_desc *gpio_mic_bias;
37 };
38
39 static int tm2_start_sysclk(struct snd_soc_card *card)
40 {
41         struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
42         struct snd_soc_component *component = priv->component;
43         int ret;
44
45         ret = snd_soc_component_set_pll(component, WM5110_FLL1_REFCLK,
46                                     ARIZONA_FLL_SRC_MCLK1,
47                                     MCLK_RATE,
48                                     priv->sysclk_rate);
49         if (ret < 0) {
50                 dev_err(component->dev, "Failed to set FLL1 source: %d\n", ret);
51                 return ret;
52         }
53
54         ret = snd_soc_component_set_pll(component, WM5110_FLL1,
55                                     ARIZONA_FLL_SRC_MCLK1,
56                                     MCLK_RATE,
57                                     priv->sysclk_rate);
58         if (ret < 0) {
59                 dev_err(component->dev, "Failed to start FLL1: %d\n", ret);
60                 return ret;
61         }
62
63         ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
64                                        ARIZONA_CLK_SRC_FLL1,
65                                        priv->sysclk_rate,
66                                        SND_SOC_CLOCK_IN);
67         if (ret < 0) {
68                 dev_err(component->dev, "Failed to set SYSCLK source: %d\n", ret);
69                 return ret;
70         }
71
72         return 0;
73 }
74
75 static int tm2_stop_sysclk(struct snd_soc_card *card)
76 {
77         struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
78         struct snd_soc_component *component = priv->component;
79         int ret;
80
81         ret = snd_soc_component_set_pll(component, WM5110_FLL1, 0, 0, 0);
82         if (ret < 0) {
83                 dev_err(component->dev, "Failed to stop FLL1: %d\n", ret);
84                 return ret;
85         }
86
87         ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK,
88                                        ARIZONA_CLK_SRC_FLL1, 0, 0);
89         if (ret < 0) {
90                 dev_err(component->dev, "Failed to stop SYSCLK: %d\n", ret);
91                 return ret;
92         }
93
94         return 0;
95 }
96
97 static int tm2_aif1_hw_params(struct snd_pcm_substream *substream,
98                                 struct snd_pcm_hw_params *params)
99 {
100         struct snd_soc_pcm_runtime *rtd = substream->private_data;
101         struct snd_soc_component *component = rtd->codec_dai->component;
102         struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card);
103
104         switch (params_rate(params)) {
105         case 4000:
106         case 8000:
107         case 12000:
108         case 16000:
109         case 24000:
110         case 32000:
111         case 48000:
112         case 96000:
113         case 192000:
114                 /* Highest possible SYSCLK frequency: 147.456MHz */
115                 priv->sysclk_rate = 147456000U;
116                 break;
117         case 11025:
118         case 22050:
119         case 44100:
120         case 88200:
121         case 176400:
122                 /* Highest possible SYSCLK frequency: 135.4752 MHz */
123                 priv->sysclk_rate = 135475200U;
124                 break;
125         default:
126                 dev_err(component->dev, "Not supported sample rate: %d\n",
127                         params_rate(params));
128                 return -EINVAL;
129         }
130
131         return tm2_start_sysclk(rtd->card);
132 }
133
134 static struct snd_soc_ops tm2_aif1_ops = {
135         .hw_params = tm2_aif1_hw_params,
136 };
137
138 static int tm2_aif2_hw_params(struct snd_pcm_substream *substream,
139                                 struct snd_pcm_hw_params *params)
140 {
141         struct snd_soc_pcm_runtime *rtd = substream->private_data;
142         struct snd_soc_component *component = rtd->codec_dai->component;
143         unsigned int asyncclk_rate;
144         int ret;
145
146         switch (params_rate(params)) {
147         case 8000:
148         case 12000:
149         case 16000:
150                 /* Highest possible ASYNCCLK frequency: 49.152MHz */
151                 asyncclk_rate = 49152000U;
152                 break;
153         case 11025:
154                 /* Highest possible ASYNCCLK frequency: 45.1584 MHz */
155                 asyncclk_rate = 45158400U;
156                 break;
157         default:
158                 dev_err(component->dev, "Not supported sample rate: %d\n",
159                         params_rate(params));
160                 return -EINVAL;
161         }
162
163         ret = snd_soc_component_set_pll(component, WM5110_FLL2_REFCLK,
164                                     ARIZONA_FLL_SRC_MCLK1,
165                                     MCLK_RATE,
166                                     asyncclk_rate);
167         if (ret < 0) {
168                 dev_err(component->dev, "Failed to set FLL2 source: %d\n", ret);
169                 return ret;
170         }
171
172         ret = snd_soc_component_set_pll(component, WM5110_FLL2,
173                                     ARIZONA_FLL_SRC_MCLK1,
174                                     MCLK_RATE,
175                                     asyncclk_rate);
176         if (ret < 0) {
177                 dev_err(component->dev, "Failed to start FLL2: %d\n", ret);
178                 return ret;
179         }
180
181         ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK,
182                                        ARIZONA_CLK_SRC_FLL2,
183                                        asyncclk_rate,
184                                        SND_SOC_CLOCK_IN);
185         if (ret < 0) {
186                 dev_err(component->dev, "Failed to set ASYNCCLK source: %d\n", ret);
187                 return ret;
188         }
189
190         return 0;
191 }
192
193 static int tm2_aif2_hw_free(struct snd_pcm_substream *substream)
194 {
195         struct snd_soc_pcm_runtime *rtd = substream->private_data;
196         struct snd_soc_component *component = rtd->codec_dai->component;
197         int ret;
198
199         /* disable FLL2 */
200         ret = snd_soc_component_set_pll(component, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1,
201                                     0, 0);
202         if (ret < 0)
203                 dev_err(component->dev, "Failed to stop FLL2: %d\n", ret);
204
205         return ret;
206 }
207
208 static struct snd_soc_ops tm2_aif2_ops = {
209         .hw_params = tm2_aif2_hw_params,
210         .hw_free = tm2_aif2_hw_free,
211 };
212
213 static int tm2_hdmi_hw_params(struct snd_pcm_substream *substream,
214                               struct snd_pcm_hw_params *params)
215 {
216         struct snd_soc_pcm_runtime *rtd = substream->private_data;
217         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
218         unsigned int bfs;
219         int bitwidth, ret;
220
221         bitwidth = snd_pcm_format_width(params_format(params));
222         if (bitwidth < 0) {
223                 dev_err(rtd->card->dev, "Invalid bit-width: %d\n", bitwidth);
224                 return bitwidth;
225         }
226
227         switch (bitwidth) {
228         case 48:
229                 bfs = 64;
230                 break;
231         case 16:
232                 bfs = 32;
233                 break;
234         default:
235                 dev_err(rtd->card->dev, "Unsupported bit-width: %d\n", bitwidth);
236                 return -EINVAL;
237         }
238
239         switch (params_rate(params)) {
240         case 48000:
241         case 96000:
242         case 192000:
243                 break;
244         default:
245                 dev_err(rtd->card->dev, "Unsupported sample rate: %d\n",
246                         params_rate(params));
247                 return -EINVAL;
248         }
249
250         ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK,
251                                         0, SAMSUNG_I2S_OPCLK_PCLK);
252         if (ret < 0)
253                 return ret;
254
255         ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs);
256         if (ret < 0)
257                 return ret;
258
259         return 0;
260 }
261
262 static struct snd_soc_ops tm2_hdmi_ops = {
263         .hw_params = tm2_hdmi_hw_params,
264 };
265
266 static int tm2_mic_bias(struct snd_soc_dapm_widget *w,
267                                 struct snd_kcontrol *kcontrol, int event)
268 {
269         struct snd_soc_card *card = w->dapm->card;
270         struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
271
272         switch (event) {
273         case SND_SOC_DAPM_PRE_PMU:
274                 gpiod_set_value_cansleep(priv->gpio_mic_bias,  1);
275                 break;
276         case SND_SOC_DAPM_POST_PMD:
277                 gpiod_set_value_cansleep(priv->gpio_mic_bias,  0);
278                 break;
279         }
280
281         return 0;
282 }
283
284 static int tm2_set_bias_level(struct snd_soc_card *card,
285                                 struct snd_soc_dapm_context *dapm,
286                                 enum snd_soc_bias_level level)
287 {
288         struct snd_soc_pcm_runtime *rtd;
289
290         rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
291
292         if (dapm->dev != rtd->codec_dai->dev)
293                 return 0;
294
295         switch (level) {
296         case SND_SOC_BIAS_STANDBY:
297                 if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
298                         tm2_start_sysclk(card);
299                 break;
300         case SND_SOC_BIAS_OFF:
301                 tm2_stop_sysclk(card);
302                 break;
303         default:
304                 break;
305         }
306
307         return 0;
308 }
309
310 static struct snd_soc_aux_dev tm2_speaker_amp_dev;
311
312 static int tm2_late_probe(struct snd_soc_card *card)
313 {
314         struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card);
315         struct snd_soc_dai_link_component dlc = { 0 };
316         unsigned int ch_map[] = { 0, 1 };
317         struct snd_soc_dai *amp_pdm_dai;
318         struct snd_soc_pcm_runtime *rtd;
319         struct snd_soc_dai *aif1_dai;
320         struct snd_soc_dai *aif2_dai;
321         int ret;
322
323         rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name);
324         aif1_dai = rtd->codec_dai;
325         priv->component = rtd->codec_dai->component;
326
327         ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
328         if (ret < 0) {
329                 dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret);
330                 return ret;
331         }
332
333         rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF2].name);
334         aif2_dai = rtd->codec_dai;
335
336         ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
337         if (ret < 0) {
338                 dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret);
339                 return ret;
340         }
341
342         dlc.of_node = tm2_speaker_amp_dev.codec_of_node;
343         amp_pdm_dai = snd_soc_find_dai(&dlc);
344         if (!amp_pdm_dai)
345                 return -ENODEV;
346
347         /* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */
348         ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map),
349                                           ch_map, 0, NULL);
350         if (ret < 0)
351                 return ret;
352
353         ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16);
354         if (ret < 0)
355                 return ret;
356
357         return 0;
358 }
359
360 static const struct snd_kcontrol_new tm2_controls[] = {
361         SOC_DAPM_PIN_SWITCH("HP"),
362         SOC_DAPM_PIN_SWITCH("SPK"),
363         SOC_DAPM_PIN_SWITCH("RCV"),
364         SOC_DAPM_PIN_SWITCH("VPS"),
365         SOC_DAPM_PIN_SWITCH("HDMI"),
366
367         SOC_DAPM_PIN_SWITCH("Main Mic"),
368         SOC_DAPM_PIN_SWITCH("Sub Mic"),
369         SOC_DAPM_PIN_SWITCH("Third Mic"),
370
371         SOC_DAPM_PIN_SWITCH("Headset Mic"),
372 };
373
374 static const struct snd_soc_dapm_widget tm2_dapm_widgets[] = {
375         SND_SOC_DAPM_HP("HP", NULL),
376         SND_SOC_DAPM_SPK("SPK", NULL),
377         SND_SOC_DAPM_SPK("RCV", NULL),
378         SND_SOC_DAPM_LINE("VPS", NULL),
379         SND_SOC_DAPM_LINE("HDMI", NULL),
380
381         SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias),
382         SND_SOC_DAPM_MIC("Sub Mic", NULL),
383         SND_SOC_DAPM_MIC("Third Mic", NULL),
384
385         SND_SOC_DAPM_MIC("Headset Mic", NULL),
386 };
387
388 static const struct snd_soc_component_driver tm2_component = {
389         .name   = "tm2-audio",
390 };
391
392 static struct snd_soc_dai_driver tm2_ext_dai[] = {
393         {
394                 .name = "Voice call",
395                 .playback = {
396                         .channels_min = 1,
397                         .channels_max = 4,
398                         .rate_min = 8000,
399                         .rate_max = 48000,
400                         .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
401                                         SNDRV_PCM_RATE_48000),
402                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
403                 },
404                 .capture = {
405                         .channels_min = 1,
406                         .channels_max = 4,
407                         .rate_min = 8000,
408                         .rate_max = 48000,
409                         .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
410                                         SNDRV_PCM_RATE_48000),
411                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
412                 },
413         },
414         {
415                 .name = "Bluetooth",
416                 .playback = {
417                         .channels_min = 1,
418                         .channels_max = 4,
419                         .rate_min = 8000,
420                         .rate_max = 16000,
421                         .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
422                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
423                 },
424                 .capture = {
425                         .channels_min = 1,
426                         .channels_max = 2,
427                         .rate_min = 8000,
428                         .rate_max = 16000,
429                         .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
430                         .formats = SNDRV_PCM_FMTBIT_S16_LE,
431                 },
432         },
433 };
434
435 static struct snd_soc_dai_link tm2_dai_links[] = {
436         {
437                 .name           = "WM5110 AIF1",
438                 .stream_name    = "HiFi Primary",
439                 .cpu_dai_name   = SAMSUNG_I2S_DAI,
440                 .codec_dai_name = "wm5110-aif1",
441                 .ops            = &tm2_aif1_ops,
442                 .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
443                                   SND_SOC_DAIFMT_CBM_CFM,
444         }, {
445                 .name           = "WM5110 Voice",
446                 .stream_name    = "Voice call",
447                 .cpu_dai_name   = SAMSUNG_I2S_DAI,
448                 .codec_dai_name = "wm5110-aif2",
449                 .ops            = &tm2_aif2_ops,
450                 .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
451                                   SND_SOC_DAIFMT_CBM_CFM,
452                 .ignore_suspend = 1,
453         }, {
454                 .name           = "WM5110 BT",
455                 .stream_name    = "Bluetooth",
456                 .cpu_dai_name   = SAMSUNG_I2S_DAI,
457                 .codec_dai_name = "wm5110-aif3",
458                 .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
459                                   SND_SOC_DAIFMT_CBM_CFM,
460                 .ignore_suspend = 1,
461         }, {
462                 .name           = "HDMI",
463                 .stream_name    = "i2s1",
464                 .ops            = &tm2_hdmi_ops,
465                 .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
466                                   SND_SOC_DAIFMT_CBS_CFS,
467         }
468 };
469
470 static struct snd_soc_card tm2_card = {
471         .owner                  = THIS_MODULE,
472
473         .dai_link               = tm2_dai_links,
474         .controls               = tm2_controls,
475         .num_controls           = ARRAY_SIZE(tm2_controls),
476         .dapm_widgets           = tm2_dapm_widgets,
477         .num_dapm_widgets       = ARRAY_SIZE(tm2_dapm_widgets),
478         .aux_dev                = &tm2_speaker_amp_dev,
479         .num_aux_devs           = 1,
480
481         .late_probe             = tm2_late_probe,
482         .set_bias_level         = tm2_set_bias_level,
483 };
484
485 static int tm2_probe(struct platform_device *pdev)
486 {
487         struct device_node *cpu_dai_node[2] = {};
488         struct device_node *codec_dai_node[2] = {};
489         const char *cells_name = NULL;
490         struct device *dev = &pdev->dev;
491         struct snd_soc_card *card = &tm2_card;
492         struct tm2_machine_priv *priv;
493         struct of_phandle_args args;
494         int num_codecs, ret, i;
495
496         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
497         if (!priv)
498                 return -ENOMEM;
499
500         snd_soc_card_set_drvdata(card, priv);
501         card->dev = dev;
502
503         priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias", GPIOD_OUT_HIGH);
504         if (IS_ERR(priv->gpio_mic_bias)) {
505                 dev_err(dev, "Failed to get mic bias gpio\n");
506                 return PTR_ERR(priv->gpio_mic_bias);
507         }
508
509         ret = snd_soc_of_parse_card_name(card, "model");
510         if (ret < 0) {
511                 dev_err(dev, "Card name is not specified\n");
512                 return ret;
513         }
514
515         ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
516         if (ret < 0) {
517                 dev_err(dev, "Audio routing is not specified or invalid\n");
518                 return ret;
519         }
520
521         card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node,
522                                                         "audio-amplifier", 0);
523         if (!card->aux_dev[0].codec_of_node) {
524                 dev_err(dev, "audio-amplifier property invalid or missing\n");
525                 return -EINVAL;
526         }
527
528         num_codecs = of_count_phandle_with_args(dev->of_node, "audio-codec",
529                                                  NULL);
530
531         /* Skip the HDMI link if not specified in DT */
532         if (num_codecs > 1) {
533                 card->num_links = ARRAY_SIZE(tm2_dai_links);
534                 cells_name = "#sound-dai-cells";
535         } else {
536                 card->num_links = ARRAY_SIZE(tm2_dai_links) - 1;
537         }
538
539         for (i = 0; i < num_codecs; i++) {
540                 struct of_phandle_args args;
541
542                 ret = of_parse_phandle_with_args(dev->of_node, "i2s-controller",
543                                                  cells_name, i, &args);
544                 if (ret) {
545                         dev_err(dev, "i2s-controller property parse error: %d\n", i);
546                         ret = -EINVAL;
547                         goto dai_node_put;
548                 }
549                 cpu_dai_node[i] = args.np;
550
551                 codec_dai_node[i] = of_parse_phandle(dev->of_node,
552                                                      "audio-codec", i);
553                 if (!codec_dai_node[i]) {
554                         dev_err(dev, "audio-codec property parse error\n");
555                         ret = -EINVAL;
556                         goto dai_node_put;
557                 }
558         }
559
560         /* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */
561         for (i = 0; i < card->num_links; i++) {
562                 unsigned int dai_index = 0; /* WM5110 */
563
564                 card->dai_link[i].cpu_name = NULL;
565                 card->dai_link[i].platform_name = NULL;
566
567                 if (num_codecs > 1 && i == card->num_links - 1)
568                         dai_index = 1; /* HDMI */
569
570                 card->dai_link[i].codec_of_node = codec_dai_node[dai_index];
571                 card->dai_link[i].cpu_of_node = cpu_dai_node[dai_index];
572                 card->dai_link[i].platform_of_node = cpu_dai_node[dai_index];
573         }
574
575         if (num_codecs > 1) {
576                 /* HDMI DAI link (I2S1) */
577                 i = card->num_links - 1;
578
579                 ret = of_parse_phandle_with_fixed_args(dev->of_node,
580                                                 "audio-codec", 0, 1, &args);
581                 if (ret) {
582                         dev_err(dev, "audio-codec property parse error\n");
583                         goto dai_node_put;
584                 }
585
586                 ret = snd_soc_get_dai_name(&args, &card->dai_link[i].codec_dai_name);
587                 if (ret) {
588                         dev_err(dev, "Unable to get codec_dai_name\n");
589                         goto dai_node_put;
590                 }
591         }
592
593         ret = devm_snd_soc_register_component(dev, &tm2_component,
594                                 tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai));
595         if (ret < 0) {
596                 dev_err(dev, "Failed to register component: %d\n", ret);
597                 goto dai_node_put;
598         }
599
600         ret = devm_snd_soc_register_card(dev, card);
601         if (ret < 0) {
602                 dev_err(dev, "Failed to register card: %d\n", ret);
603                 goto dai_node_put;
604         }
605
606 dai_node_put:
607         for (i = 0; i < num_codecs; i++) {
608                 of_node_put(codec_dai_node[i]);
609                 of_node_put(cpu_dai_node[i]);
610         }
611
612         of_node_put(card->aux_dev[0].codec_of_node);
613
614         return ret;
615 }
616
617 static int tm2_pm_prepare(struct device *dev)
618 {
619         struct snd_soc_card *card = dev_get_drvdata(dev);
620
621         return tm2_stop_sysclk(card);
622 }
623
624 static void tm2_pm_complete(struct device *dev)
625 {
626         struct snd_soc_card *card = dev_get_drvdata(dev);
627
628         tm2_start_sysclk(card);
629 }
630
631 static const struct dev_pm_ops tm2_pm_ops = {
632         .prepare        = tm2_pm_prepare,
633         .suspend        = snd_soc_suspend,
634         .resume         = snd_soc_resume,
635         .complete       = tm2_pm_complete,
636         .freeze         = snd_soc_suspend,
637         .thaw           = snd_soc_resume,
638         .poweroff       = snd_soc_poweroff,
639         .restore        = snd_soc_resume,
640 };
641
642 static const struct of_device_id tm2_of_match[] = {
643         { .compatible = "samsung,tm2-audio" },
644         { },
645 };
646 MODULE_DEVICE_TABLE(of, tm2_of_match);
647
648 static struct platform_driver tm2_driver = {
649         .driver = {
650                 .name           = "tm2-audio",
651                 .pm             = &tm2_pm_ops,
652                 .of_match_table = tm2_of_match,
653         },
654         .probe  = tm2_probe,
655 };
656 module_platform_driver(tm2_driver);
657
658 MODULE_AUTHOR("Inha Song <ideal.song@samsung.com>");
659 MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support");
660 MODULE_LICENSE("GPL v2");