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