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