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