xref: /linux/sound/soc/qcom/sc7180.c (revision 6179d4a213006491ff0d50073256f21fad22149b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Copyright (c) 2020, The Linux Foundation. All rights reserved.
4 //
5 // sc7180.c -- ALSA SoC Machine driver for SC7180
6 
7 #include <dt-bindings/sound/sc7180-lpass.h>
8 #include <dt-bindings/sound/qcom,q6afe.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/platform_device.h>
13 #include <sound/core.h>
14 #include <sound/jack.h>
15 #include <sound/pcm.h>
16 #include <sound/soc.h>
17 #include <uapi/linux/input-event-codes.h>
18 
19 #include "../codecs/rt5682.h"
20 #include "../codecs/rt5682s.h"
21 #include "common.h"
22 #include "qdsp6/q6afe.h"
23 
24 #define DEFAULT_MCLK_RATE		19200000
25 #define MI2S_BCLK_RATE			1536000
26 #define RT5682_PLL1_FREQ (48000 * 512)
27 
28 #define DRIVER_NAME "SC7180"
29 
30 struct sc7180_snd_data {
31 	struct snd_soc_card card;
32 	u32 pri_mi2s_clk_count;
33 	struct snd_soc_jack hs_jack;
34 	struct snd_soc_jack hdmi_jack;
35 	struct gpio_desc *dmic_sel;
36 	int dmic_switch;
37 };
38 
39 static void sc7180_jack_free(struct snd_jack *jack)
40 {
41 	struct snd_soc_component *component = jack->private_data;
42 
43 	snd_soc_component_set_jack(component, NULL, NULL);
44 }
45 
46 static struct snd_soc_jack_pin sc7180_jack_pins[] = {
47 	{
48 		.pin = "Headphone Jack",
49 		.mask = SND_JACK_HEADPHONE,
50 	},
51 	{
52 		.pin = "Headset Mic",
53 		.mask = SND_JACK_MICROPHONE,
54 	},
55 };
56 
57 static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd)
58 {
59 	struct snd_soc_card *card = rtd->card;
60 	struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card);
61 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
62 	struct snd_soc_component *component = codec_dai->component;
63 	struct snd_jack *jack;
64 	int rval;
65 
66 	rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
67 					  SND_JACK_HEADSET |
68 					  SND_JACK_HEADPHONE |
69 					  SND_JACK_BTN_0 | SND_JACK_BTN_1 |
70 					  SND_JACK_BTN_2 | SND_JACK_BTN_3,
71 					  &pdata->hs_jack,
72 					  sc7180_jack_pins,
73 					  ARRAY_SIZE(sc7180_jack_pins));
74 
75 	if (rval < 0) {
76 		dev_err(card->dev, "Unable to add Headset Jack\n");
77 		return rval;
78 	}
79 
80 	jack = pdata->hs_jack.jack;
81 
82 	snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
83 	snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
84 	snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
85 	snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
86 
87 	jack->private_data = component;
88 	jack->private_free = sc7180_jack_free;
89 
90 	return snd_soc_component_set_jack(component, &pdata->hs_jack, NULL);
91 }
92 
93 static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd)
94 {
95 	struct snd_soc_card *card = rtd->card;
96 	struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card);
97 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
98 	struct snd_soc_component *component = codec_dai->component;
99 	struct snd_jack *jack;
100 	int rval;
101 
102 	rval = snd_soc_card_jack_new(
103 			card, "HDMI Jack",
104 			SND_JACK_LINEOUT,
105 			&pdata->hdmi_jack);
106 
107 	if (rval < 0) {
108 		dev_err(card->dev, "Unable to add HDMI Jack\n");
109 		return rval;
110 	}
111 
112 	jack = pdata->hdmi_jack.jack;
113 	jack->private_data = component;
114 	jack->private_free = sc7180_jack_free;
115 
116 	return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL);
117 }
118 
119 static int sc7180_init(struct snd_soc_pcm_runtime *rtd)
120 {
121 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
122 
123 	switch (cpu_dai->id) {
124 	case MI2S_PRIMARY:
125 		return sc7180_headset_init(rtd);
126 	case MI2S_SECONDARY:
127 		return 0;
128 	case LPASS_DP_RX:
129 		return sc7180_hdmi_init(rtd);
130 	default:
131 		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
132 			cpu_dai->id);
133 		return -EINVAL;
134 	}
135 	return 0;
136 }
137 
138 static int sc7180_qdsp_init(struct snd_soc_pcm_runtime *rtd)
139 {
140 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
141 
142 	switch (cpu_dai->id) {
143 	case PRIMARY_MI2S_RX:
144 		return sc7180_headset_init(rtd);
145 	case PRIMARY_MI2S_TX:
146 	case TERTIARY_MI2S_RX:
147 		return 0;
148 	case DISPLAY_PORT_RX:
149 		return sc7180_hdmi_init(rtd);
150 	default:
151 		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
152 			cpu_dai->id);
153 		return -EINVAL;
154 	}
155 	return 0;
156 }
157 
158 static int sc7180_startup_realtek_codec(struct snd_soc_pcm_runtime *rtd)
159 {
160 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
161 	int pll_id, pll_source, pll_in, pll_out, clk_id, ret;
162 
163 	if (!strcmp(codec_dai->name, "rt5682-aif1")) {
164 		pll_source = RT5682_PLL1_S_MCLK;
165 		pll_id = 0;
166 		clk_id = RT5682_SCLK_S_PLL1;
167 		pll_out = RT5682_PLL1_FREQ;
168 		pll_in = DEFAULT_MCLK_RATE;
169 	} else if (!strcmp(codec_dai->name, "rt5682s-aif1")) {
170 		pll_source = RT5682S_PLL_S_MCLK;
171 		pll_id = RT5682S_PLL2;
172 		clk_id = RT5682S_SCLK_S_PLL2;
173 		pll_out = RT5682_PLL1_FREQ;
174 		pll_in = DEFAULT_MCLK_RATE;
175 	} else {
176 		return 0;
177 	}
178 	snd_soc_dai_set_fmt(codec_dai,
179 			    SND_SOC_DAIFMT_BC_FC |
180 			    SND_SOC_DAIFMT_NB_NF |
181 			    SND_SOC_DAIFMT_I2S);
182 
183 	/* Configure PLL1 for codec */
184 	ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source,
185 				  pll_in, pll_out);
186 	if (ret) {
187 		dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
188 		return ret;
189 	}
190 
191 	/* Configure sysclk for codec */
192 	ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out,
193 				     SND_SOC_CLOCK_IN);
194 	if (ret)
195 		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n",
196 			ret);
197 
198 	return ret;
199 }
200 
201 static int sc7180_snd_startup(struct snd_pcm_substream *substream)
202 {
203 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
204 	struct snd_soc_card *card = rtd->card;
205 	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
206 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
207 	int ret;
208 
209 	switch (cpu_dai->id) {
210 	case MI2S_PRIMARY:
211 		if (++data->pri_mi2s_clk_count == 1) {
212 			snd_soc_dai_set_sysclk(cpu_dai,
213 					       LPASS_MCLK0,
214 					       DEFAULT_MCLK_RATE,
215 					       SNDRV_PCM_STREAM_PLAYBACK);
216 		}
217 
218 		ret = sc7180_startup_realtek_codec(rtd);
219 		if (ret)
220 			return ret;
221 
222 		break;
223 	case MI2S_SECONDARY:
224 		break;
225 	case LPASS_DP_RX:
226 		break;
227 	default:
228 		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
229 			cpu_dai->id);
230 		return -EINVAL;
231 	}
232 	return 0;
233 }
234 
235 static int sc7180_qdsp_snd_startup(struct snd_pcm_substream *substream)
236 {
237 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
238 	struct snd_soc_card *card = rtd->card;
239 	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
240 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
241 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
242 	int ret;
243 
244 	switch (cpu_dai->id) {
245 	case PRIMARY_MI2S_RX:
246 	case PRIMARY_MI2S_TX:
247 		if (++data->pri_mi2s_clk_count == 1) {
248 			snd_soc_dai_set_sysclk(cpu_dai,
249 					       Q6AFE_LPASS_CLK_ID_MCLK_1,
250 					       DEFAULT_MCLK_RATE,
251 					       SNDRV_PCM_STREAM_PLAYBACK);
252 			snd_soc_dai_set_sysclk(cpu_dai,
253 					       Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
254 					       MI2S_BCLK_RATE,
255 					       SNDRV_PCM_STREAM_PLAYBACK);
256 		}
257 
258 		snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
259 
260 		ret = sc7180_startup_realtek_codec(rtd);
261 		if (ret)
262 			return ret;
263 
264 		break;
265 	case TERTIARY_MI2S_RX:
266 		snd_soc_dai_set_sysclk(cpu_dai,
267 				       Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
268 				       MI2S_BCLK_RATE,
269 				       SNDRV_PCM_STREAM_PLAYBACK);
270 
271 		snd_soc_dai_set_fmt(codec_dai,
272 				SND_SOC_DAIFMT_BC_FC |
273 				SND_SOC_DAIFMT_NB_NF |
274 				SND_SOC_DAIFMT_I2S);
275 		snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
276 		break;
277 	case DISPLAY_PORT_RX:
278 		break;
279 	default:
280 		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
281 			cpu_dai->id);
282 		return -EINVAL;
283 	}
284 	return 0;
285 }
286 
287 static int dmic_get(struct snd_kcontrol *kcontrol,
288 		    struct snd_ctl_elem_value *ucontrol)
289 {
290 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
291 	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card);
292 
293 	ucontrol->value.integer.value[0] = data->dmic_switch;
294 	return 0;
295 }
296 
297 static int dmic_set(struct snd_kcontrol *kcontrol,
298 		    struct snd_ctl_elem_value *ucontrol)
299 {
300 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
301 	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(dapm->card);
302 
303 	data->dmic_switch = ucontrol->value.integer.value[0];
304 	gpiod_set_value(data->dmic_sel, data->dmic_switch);
305 	return 0;
306 }
307 
308 static void sc7180_snd_shutdown(struct snd_pcm_substream *substream)
309 {
310 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
311 	struct snd_soc_card *card = rtd->card;
312 	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
313 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
314 
315 	switch (cpu_dai->id) {
316 	case MI2S_PRIMARY:
317 		if (--data->pri_mi2s_clk_count == 0) {
318 			snd_soc_dai_set_sysclk(cpu_dai,
319 					       LPASS_MCLK0,
320 					       0,
321 					       SNDRV_PCM_STREAM_PLAYBACK);
322 		}
323 		break;
324 	case MI2S_SECONDARY:
325 		break;
326 	case LPASS_DP_RX:
327 		break;
328 	default:
329 		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
330 			cpu_dai->id);
331 		break;
332 	}
333 }
334 
335 static void sc7180_qdsp_snd_shutdown(struct snd_pcm_substream *substream)
336 {
337 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
338 	struct snd_soc_card *card = rtd->card;
339 	struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card);
340 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
341 
342 	switch (cpu_dai->id) {
343 	case PRIMARY_MI2S_RX:
344 	case PRIMARY_MI2S_TX:
345 		if (--data->pri_mi2s_clk_count == 0) {
346 			snd_soc_dai_set_sysclk(cpu_dai,
347 					       Q6AFE_LPASS_CLK_ID_MCLK_1,
348 					       0,
349 					       SNDRV_PCM_STREAM_PLAYBACK);
350 			snd_soc_dai_set_sysclk(cpu_dai,
351 					       Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
352 					       0,
353 					       SNDRV_PCM_STREAM_PLAYBACK);
354 		}
355 		break;
356 	case TERTIARY_MI2S_RX:
357 		snd_soc_dai_set_sysclk(cpu_dai,
358 				       Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
359 				       0,
360 				       SNDRV_PCM_STREAM_PLAYBACK);
361 		break;
362 	case DISPLAY_PORT_RX:
363 		break;
364 	default:
365 		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
366 			cpu_dai->id);
367 		break;
368 	}
369 }
370 
371 static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd)
372 {
373 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
374 
375 	switch (cpu_dai->id) {
376 	case MI2S_PRIMARY:
377 		return 0;
378 	case MI2S_SECONDARY:
379 		return 0;
380 	case LPASS_DP_RX:
381 		return sc7180_hdmi_init(rtd);
382 	default:
383 		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
384 			cpu_dai->id);
385 		return -EINVAL;
386 	}
387 	return 0;
388 }
389 
390 static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream)
391 {
392 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
393 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
394 	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
395 	struct snd_pcm_runtime *runtime = substream->runtime;
396 
397 	switch (cpu_dai->id) {
398 	case MI2S_PRIMARY:
399 		snd_soc_dai_set_fmt(codec_dai,
400 				    SND_SOC_DAIFMT_CBS_CFS |
401 				    SND_SOC_DAIFMT_NB_NF |
402 				    SND_SOC_DAIFMT_I2S);
403 		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
404 		snd_pcm_hw_constraint_msbits(runtime, 0, 32, 32);
405 
406 		break;
407 	case MI2S_SECONDARY:
408 		break;
409 	case LPASS_DP_RX:
410 		break;
411 	default:
412 		dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__,
413 			cpu_dai->id);
414 		return -EINVAL;
415 	}
416 	return 0;
417 }
418 
419 static int sc7180_qdsp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
420 				     struct snd_pcm_hw_params *params)
421 {
422 	struct snd_interval *rate = hw_param_interval(params,
423 					SNDRV_PCM_HW_PARAM_RATE);
424 	struct snd_interval *channels = hw_param_interval(params,
425 					SNDRV_PCM_HW_PARAM_CHANNELS);
426 
427 	rate->min = rate->max = 48000;
428 	channels->min = channels->max = 2;
429 
430 	return 0;
431 }
432 
433 static const struct snd_soc_ops sc7180_ops = {
434 	.startup = sc7180_snd_startup,
435 	.shutdown = sc7180_snd_shutdown,
436 };
437 
438 static const struct snd_soc_ops sc7180_qdsp_ops = {
439 	.startup = sc7180_qdsp_snd_startup,
440 	.shutdown = sc7180_qdsp_snd_shutdown,
441 };
442 
443 static const struct snd_soc_ops sc7180_adau7002_ops = {
444 	.startup = sc7180_adau7002_snd_startup,
445 };
446 
447 static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = {
448 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
449 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
450 };
451 
452 static const struct snd_kcontrol_new sc7180_snd_controls[] = {
453 	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
454 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
455 };
456 
457 static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = {
458 	SND_SOC_DAPM_MIC("DMIC", NULL),
459 };
460 
461 static const char * const dmic_mux_text[] = {
462 	"Front Mic",
463 	"Rear Mic",
464 };
465 
466 static SOC_ENUM_SINGLE_DECL(sc7180_dmic_enum,
467 			    SND_SOC_NOPM, 0, dmic_mux_text);
468 
469 static const struct snd_kcontrol_new sc7180_dmic_mux_control =
470 	SOC_DAPM_ENUM_EXT("DMIC Select Mux", sc7180_dmic_enum,
471 			  dmic_get, dmic_set);
472 
473 static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = {
474 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
475 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
476 	SND_SOC_DAPM_MIC("DMIC", NULL),
477 	SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control),
478 };
479 
480 static const struct snd_kcontrol_new sc7180_snd_dual_mic_controls[] = {
481 	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
482 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
483 };
484 
485 static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = {
486 	{"Dmic Mux", "Front Mic", "DMIC"},
487 	{"Dmic Mux", "Rear Mic", "DMIC"},
488 };
489 
490 static int sc7180_snd_platform_probe(struct platform_device *pdev)
491 {
492 	struct snd_soc_card *card;
493 	struct sc7180_snd_data *data;
494 	struct device *dev = &pdev->dev;
495 	struct snd_soc_dai_link *link;
496 	int ret;
497 	int i;
498 	bool qdsp = false, no_headphone = false;
499 
500 	/* Allocate the private data */
501 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
502 	if (!data)
503 		return -ENOMEM;
504 
505 	card = &data->card;
506 	snd_soc_card_set_drvdata(card, data);
507 
508 	card->owner = THIS_MODULE;
509 	card->driver_name = DRIVER_NAME;
510 	card->dev = dev;
511 	card->dapm_widgets = sc7180_snd_widgets;
512 	card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets);
513 	card->controls = sc7180_snd_controls;
514 	card->num_controls = ARRAY_SIZE(sc7180_snd_controls);
515 
516 	if (of_property_read_bool(dev->of_node, "dmic-gpios")) {
517 		card->dapm_widgets = sc7180_snd_dual_mic_widgets,
518 		card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets),
519 		card->controls = sc7180_snd_dual_mic_controls,
520 		card->num_controls = ARRAY_SIZE(sc7180_snd_dual_mic_controls),
521 		card->dapm_routes = sc7180_snd_dual_mic_audio_route,
522 		card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route),
523 		data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW);
524 		if (IS_ERR(data->dmic_sel)) {
525 			dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n", PTR_ERR(data->dmic_sel));
526 			return PTR_ERR(data->dmic_sel);
527 		}
528 	}
529 
530 	if (of_device_is_compatible(dev->of_node, "google,sc7180-coachz")) {
531 		no_headphone = true;
532 		card->dapm_widgets = sc7180_adau7002_snd_widgets;
533 		card->num_dapm_widgets = ARRAY_SIZE(sc7180_adau7002_snd_widgets);
534 	} else if (of_device_is_compatible(dev->of_node, "qcom,sc7180-qdsp6-sndcard")) {
535 		qdsp = true;
536 	}
537 
538 	ret = qcom_snd_parse_of(card);
539 	if (ret)
540 		return ret;
541 
542 	for_each_card_prelinks(card, i, link) {
543 		if (no_headphone) {
544 			link->ops = &sc7180_adau7002_ops;
545 			link->init = sc7180_adau7002_init;
546 		} else if (qdsp) {
547 			if (link->no_pcm == 1) {
548 				link->ops = &sc7180_qdsp_ops;
549 				link->be_hw_params_fixup = sc7180_qdsp_be_hw_params_fixup;
550 				link->init = sc7180_qdsp_init;
551 			}
552 		} else {
553 			link->ops = &sc7180_ops;
554 			link->init = sc7180_init;
555 		}
556 	}
557 
558 	return devm_snd_soc_register_card(dev, card);
559 }
560 
561 static const struct of_device_id sc7180_snd_device_id[]  = {
562 	{.compatible = "google,sc7180-trogdor"},
563 	{.compatible = "google,sc7180-coachz"},
564 	{.compatible = "qcom,sc7180-qdsp6-sndcard"},
565 	{},
566 };
567 MODULE_DEVICE_TABLE(of, sc7180_snd_device_id);
568 
569 static struct platform_driver sc7180_snd_driver = {
570 	.probe = sc7180_snd_platform_probe,
571 	.driver = {
572 		.name = "msm-snd-sc7180",
573 		.of_match_table = sc7180_snd_device_id,
574 		.pm = &snd_soc_pm_ops,
575 	},
576 };
577 module_platform_driver(sc7180_snd_driver);
578 
579 MODULE_DESCRIPTION("sc7180 ASoC Machine Driver");
580 MODULE_LICENSE("GPL");
581