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