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