GNU Linux-libre 5.4.200-gnu1
[releases.git] / sound / soc / qcom / lpass-platform.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
4  *
5  * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
6  */
7
8 #include <linux/dma-mapping.h>
9 #include <linux/export.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <sound/pcm_params.h>
14 #include <linux/regmap.h>
15 #include <sound/soc.h>
16 #include "lpass-lpaif-reg.h"
17 #include "lpass.h"
18
19 #define DRV_NAME "lpass-platform"
20
21 struct lpass_pcm_data {
22         int dma_ch;
23         int i2s_port;
24 };
25
26 #define LPASS_PLATFORM_BUFFER_SIZE      (16 * 1024)
27 #define LPASS_PLATFORM_PERIODS          2
28
29 static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
30         .info                   =       SNDRV_PCM_INFO_MMAP |
31                                         SNDRV_PCM_INFO_MMAP_VALID |
32                                         SNDRV_PCM_INFO_INTERLEAVED |
33                                         SNDRV_PCM_INFO_PAUSE |
34                                         SNDRV_PCM_INFO_RESUME,
35         .formats                =       SNDRV_PCM_FMTBIT_S16 |
36                                         SNDRV_PCM_FMTBIT_S24 |
37                                         SNDRV_PCM_FMTBIT_S32,
38         .rates                  =       SNDRV_PCM_RATE_8000_192000,
39         .rate_min               =       8000,
40         .rate_max               =       192000,
41         .channels_min           =       1,
42         .channels_max           =       8,
43         .buffer_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE,
44         .period_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE /
45                                                 LPASS_PLATFORM_PERIODS,
46         .period_bytes_min       =       LPASS_PLATFORM_BUFFER_SIZE /
47                                                 LPASS_PLATFORM_PERIODS,
48         .periods_min            =       LPASS_PLATFORM_PERIODS,
49         .periods_max            =       LPASS_PLATFORM_PERIODS,
50         .fifo_size              =       0,
51 };
52
53 static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
54 {
55         struct snd_pcm_runtime *runtime = substream->runtime;
56         struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
57         struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
58         struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
59         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
60         struct lpass_variant *v = drvdata->variant;
61         int ret, dma_ch, dir = substream->stream;
62         struct lpass_pcm_data *data;
63
64         data = kzalloc(sizeof(*data), GFP_KERNEL);
65         if (!data)
66                 return -ENOMEM;
67
68         data->i2s_port = cpu_dai->driver->id;
69         runtime->private_data = data;
70
71         if (v->alloc_dma_channel)
72                 dma_ch = v->alloc_dma_channel(drvdata, dir);
73         else
74                 dma_ch = 0;
75
76         if (dma_ch < 0) {
77                 kfree(data);
78                 return dma_ch;
79         }
80
81         drvdata->substream[dma_ch] = substream;
82
83         ret = regmap_write(drvdata->lpaif_map,
84                         LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
85         if (ret) {
86                 dev_err(soc_runtime->dev,
87                         "error writing to rdmactl reg: %d\n", ret);
88                 return ret;
89         }
90
91         data->dma_ch = dma_ch;
92
93         snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
94
95         runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
96
97         ret = snd_pcm_hw_constraint_integer(runtime,
98                         SNDRV_PCM_HW_PARAM_PERIODS);
99         if (ret < 0) {
100                 kfree(data);
101                 dev_err(soc_runtime->dev, "setting constraints failed: %d\n",
102                         ret);
103                 return -EINVAL;
104         }
105
106         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
107
108         return 0;
109 }
110
111 static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
112 {
113         struct snd_pcm_runtime *runtime = substream->runtime;
114         struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
115         struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
116         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
117         struct lpass_variant *v = drvdata->variant;
118         struct lpass_pcm_data *data;
119
120         data = runtime->private_data;
121         drvdata->substream[data->dma_ch] = NULL;
122         if (v->free_dma_channel)
123                 v->free_dma_channel(drvdata, data->dma_ch);
124
125         kfree(data);
126         return 0;
127 }
128
129 static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
130                 struct snd_pcm_hw_params *params)
131 {
132         struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
133         struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
134         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
135         struct snd_pcm_runtime *rt = substream->runtime;
136         struct lpass_pcm_data *pcm_data = rt->private_data;
137         struct lpass_variant *v = drvdata->variant;
138         snd_pcm_format_t format = params_format(params);
139         unsigned int channels = params_channels(params);
140         unsigned int regval;
141         int ch, dir = substream->stream;
142         int bitwidth;
143         int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
144
145         ch = pcm_data->dma_ch;
146
147         bitwidth = snd_pcm_format_width(format);
148         if (bitwidth < 0) {
149                 dev_err(soc_runtime->dev, "invalid bit width given: %d\n",
150                                 bitwidth);
151                 return bitwidth;
152         }
153
154         regval = LPAIF_DMACTL_BURSTEN_INCR4 |
155                         LPAIF_DMACTL_AUDINTF(dma_port) |
156                         LPAIF_DMACTL_FIFOWM_8;
157
158         switch (bitwidth) {
159         case 16:
160                 switch (channels) {
161                 case 1:
162                 case 2:
163                         regval |= LPAIF_DMACTL_WPSCNT_ONE;
164                         break;
165                 case 4:
166                         regval |= LPAIF_DMACTL_WPSCNT_TWO;
167                         break;
168                 case 6:
169                         regval |= LPAIF_DMACTL_WPSCNT_THREE;
170                         break;
171                 case 8:
172                         regval |= LPAIF_DMACTL_WPSCNT_FOUR;
173                         break;
174                 default:
175                         dev_err(soc_runtime->dev,
176                                 "invalid PCM config given: bw=%d, ch=%u\n",
177                                 bitwidth, channels);
178                         return -EINVAL;
179                 }
180                 break;
181         case 24:
182         case 32:
183                 switch (channels) {
184                 case 1:
185                         regval |= LPAIF_DMACTL_WPSCNT_ONE;
186                         break;
187                 case 2:
188                         regval |= LPAIF_DMACTL_WPSCNT_TWO;
189                         break;
190                 case 4:
191                         regval |= LPAIF_DMACTL_WPSCNT_FOUR;
192                         break;
193                 case 6:
194                         regval |= LPAIF_DMACTL_WPSCNT_SIX;
195                         break;
196                 case 8:
197                         regval |= LPAIF_DMACTL_WPSCNT_EIGHT;
198                         break;
199                 default:
200                         dev_err(soc_runtime->dev,
201                                 "invalid PCM config given: bw=%d, ch=%u\n",
202                                 bitwidth, channels);
203                         return -EINVAL;
204                 }
205                 break;
206         default:
207                 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
208                         bitwidth, channels);
209                 return -EINVAL;
210         }
211
212         ret = regmap_write(drvdata->lpaif_map,
213                         LPAIF_DMACTL_REG(v, ch, dir), regval);
214         if (ret) {
215                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
216                         ret);
217                 return ret;
218         }
219
220         return 0;
221 }
222
223 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
224 {
225         struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
226         struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
227         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
228         struct snd_pcm_runtime *rt = substream->runtime;
229         struct lpass_pcm_data *pcm_data = rt->private_data;
230         struct lpass_variant *v = drvdata->variant;
231         unsigned int reg;
232         int ret;
233
234         reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream);
235         ret = regmap_write(drvdata->lpaif_map, reg, 0);
236         if (ret)
237                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
238                         ret);
239
240         return ret;
241 }
242
243 static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
244 {
245         struct snd_pcm_runtime *runtime = substream->runtime;
246         struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
247         struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
248         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
249         struct snd_pcm_runtime *rt = substream->runtime;
250         struct lpass_pcm_data *pcm_data = rt->private_data;
251         struct lpass_variant *v = drvdata->variant;
252         int ret, ch, dir = substream->stream;
253
254         ch = pcm_data->dma_ch;
255
256         ret = regmap_write(drvdata->lpaif_map,
257                         LPAIF_DMABASE_REG(v, ch, dir),
258                         runtime->dma_addr);
259         if (ret) {
260                 dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
261                         ret);
262                 return ret;
263         }
264
265         ret = regmap_write(drvdata->lpaif_map,
266                         LPAIF_DMABUFF_REG(v, ch, dir),
267                         (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
268         if (ret) {
269                 dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
270                         ret);
271                 return ret;
272         }
273
274         ret = regmap_write(drvdata->lpaif_map,
275                         LPAIF_DMAPER_REG(v, ch, dir),
276                         (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
277         if (ret) {
278                 dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
279                         ret);
280                 return ret;
281         }
282
283         ret = regmap_update_bits(drvdata->lpaif_map,
284                         LPAIF_DMACTL_REG(v, ch, dir),
285                         LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON);
286         if (ret) {
287                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
288                         ret);
289                 return ret;
290         }
291
292         return 0;
293 }
294
295 static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
296                 int cmd)
297 {
298         struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
299         struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
300         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
301         struct snd_pcm_runtime *rt = substream->runtime;
302         struct lpass_pcm_data *pcm_data = rt->private_data;
303         struct lpass_variant *v = drvdata->variant;
304         int ret, ch, dir = substream->stream;
305
306         ch = pcm_data->dma_ch;
307
308         switch (cmd) {
309         case SNDRV_PCM_TRIGGER_START:
310         case SNDRV_PCM_TRIGGER_RESUME:
311         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
312                 /* clear status before enabling interrupts */
313                 ret = regmap_write(drvdata->lpaif_map,
314                                 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
315                                 LPAIF_IRQ_ALL(ch));
316                 if (ret) {
317                         dev_err(soc_runtime->dev,
318                                 "error writing to irqclear reg: %d\n", ret);
319                         return ret;
320                 }
321
322                 ret = regmap_update_bits(drvdata->lpaif_map,
323                                 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
324                                 LPAIF_IRQ_ALL(ch),
325                                 LPAIF_IRQ_ALL(ch));
326                 if (ret) {
327                         dev_err(soc_runtime->dev,
328                                 "error writing to irqen reg: %d\n", ret);
329                         return ret;
330                 }
331
332                 ret = regmap_update_bits(drvdata->lpaif_map,
333                                 LPAIF_DMACTL_REG(v, ch, dir),
334                                 LPAIF_DMACTL_ENABLE_MASK,
335                                 LPAIF_DMACTL_ENABLE_ON);
336                 if (ret) {
337                         dev_err(soc_runtime->dev,
338                                 "error writing to rdmactl reg: %d\n", ret);
339                         return ret;
340                 }
341                 break;
342         case SNDRV_PCM_TRIGGER_STOP:
343         case SNDRV_PCM_TRIGGER_SUSPEND:
344         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
345                 ret = regmap_update_bits(drvdata->lpaif_map,
346                                 LPAIF_DMACTL_REG(v, ch, dir),
347                                 LPAIF_DMACTL_ENABLE_MASK,
348                                 LPAIF_DMACTL_ENABLE_OFF);
349                 if (ret) {
350                         dev_err(soc_runtime->dev,
351                                 "error writing to rdmactl reg: %d\n", ret);
352                         return ret;
353                 }
354
355                 ret = regmap_update_bits(drvdata->lpaif_map,
356                                 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
357                                 LPAIF_IRQ_ALL(ch), 0);
358                 if (ret) {
359                         dev_err(soc_runtime->dev,
360                                 "error writing to irqen reg: %d\n", ret);
361                         return ret;
362                 }
363                 break;
364         }
365
366         return 0;
367 }
368
369 static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
370                 struct snd_pcm_substream *substream)
371 {
372         struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
373         struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
374         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
375         struct snd_pcm_runtime *rt = substream->runtime;
376         struct lpass_pcm_data *pcm_data = rt->private_data;
377         struct lpass_variant *v = drvdata->variant;
378         unsigned int base_addr, curr_addr;
379         int ret, ch, dir = substream->stream;
380
381         ch = pcm_data->dma_ch;
382
383         ret = regmap_read(drvdata->lpaif_map,
384                         LPAIF_DMABASE_REG(v, ch, dir), &base_addr);
385         if (ret) {
386                 dev_err(soc_runtime->dev,
387                         "error reading from rdmabase reg: %d\n", ret);
388                 return ret;
389         }
390
391         ret = regmap_read(drvdata->lpaif_map,
392                         LPAIF_DMACURR_REG(v, ch, dir), &curr_addr);
393         if (ret) {
394                 dev_err(soc_runtime->dev,
395                         "error reading from rdmacurr reg: %d\n", ret);
396                 return ret;
397         }
398
399         return bytes_to_frames(substream->runtime, curr_addr - base_addr);
400 }
401
402 static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
403                 struct vm_area_struct *vma)
404 {
405         struct snd_pcm_runtime *runtime = substream->runtime;
406
407         return dma_mmap_coherent(substream->pcm->card->dev, vma,
408                         runtime->dma_area, runtime->dma_addr,
409                         runtime->dma_bytes);
410 }
411
412 static const struct snd_pcm_ops lpass_platform_pcm_ops = {
413         .open           = lpass_platform_pcmops_open,
414         .close          = lpass_platform_pcmops_close,
415         .ioctl          = snd_pcm_lib_ioctl,
416         .hw_params      = lpass_platform_pcmops_hw_params,
417         .hw_free        = lpass_platform_pcmops_hw_free,
418         .prepare        = lpass_platform_pcmops_prepare,
419         .trigger        = lpass_platform_pcmops_trigger,
420         .pointer        = lpass_platform_pcmops_pointer,
421         .mmap           = lpass_platform_pcmops_mmap,
422 };
423
424 static irqreturn_t lpass_dma_interrupt_handler(
425                         struct snd_pcm_substream *substream,
426                         struct lpass_data *drvdata,
427                         int chan, u32 interrupts)
428 {
429         struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
430         struct lpass_variant *v = drvdata->variant;
431         irqreturn_t ret = IRQ_NONE;
432         int rv;
433
434         if (interrupts & LPAIF_IRQ_PER(chan)) {
435                 rv = regmap_write(drvdata->lpaif_map,
436                                 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
437                                 LPAIF_IRQ_PER(chan));
438                 if (rv) {
439                         dev_err(soc_runtime->dev,
440                                 "error writing to irqclear reg: %d\n", rv);
441                         return IRQ_NONE;
442                 }
443                 snd_pcm_period_elapsed(substream);
444                 ret = IRQ_HANDLED;
445         }
446
447         if (interrupts & LPAIF_IRQ_XRUN(chan)) {
448                 rv = regmap_write(drvdata->lpaif_map,
449                                 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
450                                 LPAIF_IRQ_XRUN(chan));
451                 if (rv) {
452                         dev_err(soc_runtime->dev,
453                                 "error writing to irqclear reg: %d\n", rv);
454                         return IRQ_NONE;
455                 }
456                 dev_warn(soc_runtime->dev, "xrun warning\n");
457                 snd_pcm_stop_xrun(substream);
458                 ret = IRQ_HANDLED;
459         }
460
461         if (interrupts & LPAIF_IRQ_ERR(chan)) {
462                 rv = regmap_write(drvdata->lpaif_map,
463                                 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
464                                 LPAIF_IRQ_ERR(chan));
465                 if (rv) {
466                         dev_err(soc_runtime->dev,
467                                 "error writing to irqclear reg: %d\n", rv);
468                         return IRQ_NONE;
469                 }
470                 dev_err(soc_runtime->dev, "bus access error\n");
471                 snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
472                 ret = IRQ_HANDLED;
473         }
474
475         return ret;
476 }
477
478 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
479 {
480         struct lpass_data *drvdata = data;
481         struct lpass_variant *v = drvdata->variant;
482         unsigned int irqs;
483         int rv, chan;
484
485         rv = regmap_read(drvdata->lpaif_map,
486                         LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
487         if (rv) {
488                 pr_err("error reading from irqstat reg: %d\n", rv);
489                 return IRQ_NONE;
490         }
491
492         /* Handle per channel interrupts */
493         for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
494                 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
495                         rv = lpass_dma_interrupt_handler(
496                                                 drvdata->substream[chan],
497                                                 drvdata, chan, irqs);
498                         if (rv != IRQ_HANDLED)
499                                 return rv;
500                 }
501         }
502
503         return IRQ_HANDLED;
504 }
505
506 static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
507 {
508         struct snd_pcm *pcm = soc_runtime->pcm;
509         struct snd_pcm_substream *psubstream, *csubstream;
510         struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
511         int ret = -EINVAL;
512         size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
513
514         psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
515         if (psubstream) {
516                 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
517                                         component->dev,
518                                         size, &psubstream->dma_buffer);
519                 if (ret) {
520                         dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
521                         return ret;
522                 }
523         }
524
525         csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
526         if (csubstream) {
527                 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
528                                         component->dev,
529                                         size, &csubstream->dma_buffer);
530                 if (ret) {
531                         dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
532                         if (psubstream)
533                                 snd_dma_free_pages(&psubstream->dma_buffer);
534                         return ret;
535                 }
536
537         }
538
539         return 0;
540 }
541
542 static void lpass_platform_pcm_free(struct snd_pcm *pcm)
543 {
544         struct snd_pcm_substream *substream;
545         int i;
546
547         for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
548                 substream = pcm->streams[i].substream;
549                 if (substream) {
550                         snd_dma_free_pages(&substream->dma_buffer);
551                         substream->dma_buffer.area = NULL;
552                         substream->dma_buffer.addr = 0;
553                 }
554         }
555 }
556
557 static const struct snd_soc_component_driver lpass_component_driver = {
558         .name           = DRV_NAME,
559         .pcm_new        = lpass_platform_pcm_new,
560         .pcm_free       = lpass_platform_pcm_free,
561         .ops            = &lpass_platform_pcm_ops,
562 };
563
564 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
565 {
566         struct lpass_data *drvdata = platform_get_drvdata(pdev);
567         struct lpass_variant *v = drvdata->variant;
568         int ret;
569
570         drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
571         if (drvdata->lpaif_irq < 0)
572                 return -ENODEV;
573
574         /* ensure audio hardware is disabled */
575         ret = regmap_write(drvdata->lpaif_map,
576                         LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
577         if (ret) {
578                 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
579                 return ret;
580         }
581
582         ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
583                         lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
584                         "lpass-irq-lpaif", drvdata);
585         if (ret) {
586                 dev_err(&pdev->dev, "irq request failed: %d\n", ret);
587                 return ret;
588         }
589
590
591         return devm_snd_soc_register_component(&pdev->dev,
592                         &lpass_component_driver, NULL, 0);
593 }
594 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
595
596 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
597 MODULE_LICENSE("GPL v2");