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