xref: /openbmc/linux/sound/soc/qcom/lpass-platform.c (revision 11a163f2)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
4  *
5  * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
6  */
7 
8 #include <linux/dma-mapping.h>
9 #include <linux/export.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <sound/pcm_params.h>
14 #include <linux/regmap.h>
15 #include <sound/soc.h>
16 #include "lpass-lpaif-reg.h"
17 #include "lpass.h"
18 
19 #define DRV_NAME "lpass-platform"
20 
21 struct lpass_pcm_data {
22 	int dma_ch;
23 	int i2s_port;
24 };
25 
26 #define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)
27 #define LPASS_PLATFORM_PERIODS		2
28 
29 static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
30 	.info			=	SNDRV_PCM_INFO_MMAP |
31 					SNDRV_PCM_INFO_MMAP_VALID |
32 					SNDRV_PCM_INFO_INTERLEAVED |
33 					SNDRV_PCM_INFO_PAUSE |
34 					SNDRV_PCM_INFO_RESUME,
35 	.formats		=	SNDRV_PCM_FMTBIT_S16 |
36 					SNDRV_PCM_FMTBIT_S24 |
37 					SNDRV_PCM_FMTBIT_S32,
38 	.rates			=	SNDRV_PCM_RATE_8000_192000,
39 	.rate_min		=	8000,
40 	.rate_max		=	192000,
41 	.channels_min		=	1,
42 	.channels_max		=	8,
43 	.buffer_bytes_max	=	LPASS_PLATFORM_BUFFER_SIZE,
44 	.period_bytes_max	=	LPASS_PLATFORM_BUFFER_SIZE /
45 						LPASS_PLATFORM_PERIODS,
46 	.period_bytes_min	=	LPASS_PLATFORM_BUFFER_SIZE /
47 						LPASS_PLATFORM_PERIODS,
48 	.periods_min		=	LPASS_PLATFORM_PERIODS,
49 	.periods_max		=	LPASS_PLATFORM_PERIODS,
50 	.fifo_size		=	0,
51 };
52 
53 static int lpass_platform_alloc_dmactl_fields(struct device *dev,
54 					 struct regmap *map)
55 {
56 	struct lpass_data *drvdata = dev_get_drvdata(dev);
57 	struct lpass_variant *v = drvdata->variant;
58 	struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
59 	int rval;
60 
61 	drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
62 					  GFP_KERNEL);
63 	if (drvdata->rd_dmactl == NULL)
64 		return -ENOMEM;
65 
66 	drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
67 					  GFP_KERNEL);
68 	if (drvdata->wr_dmactl == NULL)
69 		return -ENOMEM;
70 
71 	rd_dmactl = drvdata->rd_dmactl;
72 	wr_dmactl = drvdata->wr_dmactl;
73 
74 	rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
75 					    &v->rdma_intf, 6);
76 	if (rval)
77 		return rval;
78 
79 	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
80 					    &v->wrdma_intf, 6);
81 }
82 
83 static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev,
84 					 struct regmap *map)
85 {
86 	struct lpass_data *drvdata = dev_get_drvdata(dev);
87 	struct lpass_variant *v = drvdata->variant;
88 	struct lpaif_dmactl *rd_dmactl;
89 
90 	rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), GFP_KERNEL);
91 	if (rd_dmactl == NULL)
92 		return -ENOMEM;
93 
94 	drvdata->hdmi_rd_dmactl = rd_dmactl;
95 
96 	return devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->bursten,
97 					    &v->hdmi_rdma_bursten, 8);
98 }
99 
100 static int lpass_platform_pcmops_open(struct snd_soc_component *component,
101 				      struct snd_pcm_substream *substream)
102 {
103 	struct snd_pcm_runtime *runtime = substream->runtime;
104 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
105 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
106 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
107 	struct lpass_variant *v = drvdata->variant;
108 	int ret, dma_ch, dir = substream->stream;
109 	struct lpass_pcm_data *data;
110 	struct regmap *map;
111 	unsigned int dai_id = cpu_dai->driver->id;
112 
113 	data = kzalloc(sizeof(*data), GFP_KERNEL);
114 	if (!data)
115 		return -ENOMEM;
116 
117 	data->i2s_port = cpu_dai->driver->id;
118 	runtime->private_data = data;
119 
120 	if (v->alloc_dma_channel)
121 		dma_ch = v->alloc_dma_channel(drvdata, dir, dai_id);
122 	else
123 		dma_ch = 0;
124 
125 	if (dma_ch < 0)
126 		return dma_ch;
127 
128 	if (cpu_dai->driver->id == LPASS_DP_RX) {
129 		map = drvdata->hdmiif_map;
130 		drvdata->hdmi_substream[dma_ch] = substream;
131 	} else {
132 		map = drvdata->lpaif_map;
133 		drvdata->substream[dma_ch] = substream;
134 	}
135 	data->dma_ch = dma_ch;
136 	ret = regmap_write(map,
137 			LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
138 	if (ret) {
139 		dev_err(soc_runtime->dev,
140 			"error writing to rdmactl reg: %d\n", ret);
141 		return ret;
142 	}
143 	snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
144 
145 	runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
146 
147 	ret = snd_pcm_hw_constraint_integer(runtime,
148 			SNDRV_PCM_HW_PARAM_PERIODS);
149 	if (ret < 0) {
150 		dev_err(soc_runtime->dev, "setting constraints failed: %d\n",
151 			ret);
152 		return -EINVAL;
153 	}
154 
155 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
156 
157 	return 0;
158 }
159 
160 static int lpass_platform_pcmops_close(struct snd_soc_component *component,
161 				       struct snd_pcm_substream *substream)
162 {
163 	struct snd_pcm_runtime *runtime = substream->runtime;
164 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
165 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
166 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
167 	struct lpass_variant *v = drvdata->variant;
168 	struct lpass_pcm_data *data;
169 	unsigned int dai_id = cpu_dai->driver->id;
170 
171 	data = runtime->private_data;
172 	if (dai_id == LPASS_DP_RX)
173 		drvdata->hdmi_substream[data->dma_ch] = NULL;
174 	else
175 		drvdata->substream[data->dma_ch] = NULL;
176 	if (v->free_dma_channel)
177 		v->free_dma_channel(drvdata, data->dma_ch, dai_id);
178 
179 	kfree(data);
180 	return 0;
181 }
182 
183 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
184 					   struct snd_pcm_substream *substream,
185 					   struct snd_pcm_hw_params *params)
186 {
187 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
188 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
189 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
190 	struct snd_pcm_runtime *rt = substream->runtime;
191 	struct lpass_pcm_data *pcm_data = rt->private_data;
192 	struct lpass_variant *v = drvdata->variant;
193 	snd_pcm_format_t format = params_format(params);
194 	unsigned int channels = params_channels(params);
195 	unsigned int regval;
196 	struct lpaif_dmactl *dmactl;
197 	int id, dir = substream->stream;
198 	int bitwidth;
199 	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
200 	unsigned int dai_id = cpu_dai->driver->id;
201 
202 	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
203 		id = pcm_data->dma_ch;
204 		if (dai_id == LPASS_DP_RX)
205 			dmactl = drvdata->hdmi_rd_dmactl;
206 		else
207 			dmactl = drvdata->rd_dmactl;
208 
209 	} else {
210 		dmactl = drvdata->wr_dmactl;
211 		id = pcm_data->dma_ch - v->wrdma_channel_start;
212 	}
213 
214 	bitwidth = snd_pcm_format_width(format);
215 	if (bitwidth < 0) {
216 		dev_err(soc_runtime->dev, "invalid bit width given: %d\n",
217 				bitwidth);
218 		return bitwidth;
219 	}
220 
221 	ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4);
222 	if (ret) {
223 		dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret);
224 		return ret;
225 	}
226 
227 	ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
228 	if (ret) {
229 		dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret);
230 		return ret;
231 	}
232 
233 	switch (dai_id) {
234 	case LPASS_DP_RX:
235 		ret = regmap_fields_write(dmactl->burst8, id,
236 							LPAIF_DMACTL_BURSTEN_INCR4);
237 		if (ret) {
238 			dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret);
239 			return ret;
240 		}
241 		ret = regmap_fields_write(dmactl->burst16, id,
242 							LPAIF_DMACTL_BURSTEN_INCR4);
243 		if (ret) {
244 			dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret);
245 			return ret;
246 		}
247 		ret = regmap_fields_write(dmactl->dynburst, id,
248 							LPAIF_DMACTL_BURSTEN_INCR4);
249 		if (ret) {
250 			dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret);
251 			return ret;
252 		}
253 		break;
254 	case MI2S_PRIMARY:
255 	case MI2S_SECONDARY:
256 		ret = regmap_fields_write(dmactl->intf, id,
257 						LPAIF_DMACTL_AUDINTF(dma_port));
258 		if (ret) {
259 			dev_err(soc_runtime->dev, "error updating audio interface field: %d\n",
260 					ret);
261 			return ret;
262 		}
263 
264 		break;
265 	default:
266 		dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
267 		break;
268 	}
269 	switch (bitwidth) {
270 	case 16:
271 		switch (channels) {
272 		case 1:
273 		case 2:
274 			regval = LPAIF_DMACTL_WPSCNT_ONE;
275 			break;
276 		case 4:
277 			regval = LPAIF_DMACTL_WPSCNT_TWO;
278 			break;
279 		case 6:
280 			regval = LPAIF_DMACTL_WPSCNT_THREE;
281 			break;
282 		case 8:
283 			regval = LPAIF_DMACTL_WPSCNT_FOUR;
284 			break;
285 		default:
286 			dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
287 				bitwidth, channels);
288 			return -EINVAL;
289 		}
290 		break;
291 	case 24:
292 	case 32:
293 		switch (channels) {
294 		case 1:
295 			regval = LPAIF_DMACTL_WPSCNT_ONE;
296 			break;
297 		case 2:
298 			regval = (dai_id == LPASS_DP_RX ?
299 			LPAIF_DMACTL_WPSCNT_ONE :
300 			LPAIF_DMACTL_WPSCNT_TWO);
301 			break;
302 		case 4:
303 			regval = (dai_id == LPASS_DP_RX ?
304 			LPAIF_DMACTL_WPSCNT_TWO :
305 			LPAIF_DMACTL_WPSCNT_FOUR);
306 			break;
307 		case 6:
308 			regval = (dai_id == LPASS_DP_RX ?
309 			LPAIF_DMACTL_WPSCNT_THREE :
310 			LPAIF_DMACTL_WPSCNT_SIX);
311 			break;
312 		case 8:
313 			regval = (dai_id == LPASS_DP_RX ?
314 			LPAIF_DMACTL_WPSCNT_FOUR :
315 			LPAIF_DMACTL_WPSCNT_EIGHT);
316 			break;
317 		default:
318 			dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
319 				bitwidth, channels);
320 			return -EINVAL;
321 		}
322 		break;
323 	default:
324 		dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
325 			bitwidth, channels);
326 		return -EINVAL;
327 	}
328 
329 	ret = regmap_fields_write(dmactl->wpscnt, id, regval);
330 	if (ret) {
331 		dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n",
332 			ret);
333 		return ret;
334 	}
335 
336 	return 0;
337 }
338 
339 static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
340 					 struct snd_pcm_substream *substream)
341 {
342 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
343 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
344 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
345 	struct snd_pcm_runtime *rt = substream->runtime;
346 	struct lpass_pcm_data *pcm_data = rt->private_data;
347 	struct lpass_variant *v = drvdata->variant;
348 	unsigned int reg;
349 	int ret;
350 	struct regmap *map;
351 	unsigned int dai_id = cpu_dai->driver->id;
352 
353 	if (dai_id == LPASS_DP_RX)
354 		map = drvdata->hdmiif_map;
355 	else
356 		map = drvdata->lpaif_map;
357 
358 	reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
359 	ret = regmap_write(map, reg, 0);
360 	if (ret)
361 		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
362 			ret);
363 
364 	return ret;
365 }
366 
367 static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
368 					 struct snd_pcm_substream *substream)
369 {
370 	struct snd_pcm_runtime *runtime = substream->runtime;
371 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
372 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
373 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
374 	struct snd_pcm_runtime *rt = substream->runtime;
375 	struct lpass_pcm_data *pcm_data = rt->private_data;
376 	struct lpass_variant *v = drvdata->variant;
377 	struct lpaif_dmactl *dmactl;
378 	struct regmap *map;
379 	int ret, id, ch, dir = substream->stream;
380 	unsigned int dai_id = cpu_dai->driver->id;
381 
382 
383 	ch = pcm_data->dma_ch;
384 	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
385 		if (dai_id == LPASS_DP_RX) {
386 			dmactl = drvdata->hdmi_rd_dmactl;
387 			map = drvdata->hdmiif_map;
388 		} else {
389 			dmactl = drvdata->rd_dmactl;
390 			map = drvdata->lpaif_map;
391 		}
392 
393 		id = pcm_data->dma_ch;
394 	} else {
395 		dmactl = drvdata->wr_dmactl;
396 		id = pcm_data->dma_ch - v->wrdma_channel_start;
397 		map = drvdata->lpaif_map;
398 	}
399 
400 	ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
401 				runtime->dma_addr);
402 	if (ret) {
403 		dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
404 			ret);
405 		return ret;
406 	}
407 
408 	ret = regmap_write(map, LPAIF_DMABUFF_REG(v, ch, dir, dai_id),
409 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
410 	if (ret) {
411 		dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
412 			ret);
413 		return ret;
414 	}
415 
416 	ret = regmap_write(map, LPAIF_DMAPER_REG(v, ch, dir, dai_id),
417 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
418 	if (ret) {
419 		dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
420 			ret);
421 		return ret;
422 	}
423 
424 	ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
425 	if (ret) {
426 		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
427 			ret);
428 		return ret;
429 	}
430 
431 	return 0;
432 }
433 
434 static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
435 					 struct snd_pcm_substream *substream,
436 					 int cmd)
437 {
438 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
439 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
440 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
441 	struct snd_pcm_runtime *rt = substream->runtime;
442 	struct lpass_pcm_data *pcm_data = rt->private_data;
443 	struct lpass_variant *v = drvdata->variant;
444 	struct lpaif_dmactl *dmactl;
445 	struct regmap *map;
446 	int ret, ch, id;
447 	int dir = substream->stream;
448 	unsigned int reg_irqclr = 0, val_irqclr = 0;
449 	unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
450 	unsigned int dai_id = cpu_dai->driver->id;
451 
452 	ch = pcm_data->dma_ch;
453 	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
454 		id = pcm_data->dma_ch;
455 		if (dai_id == LPASS_DP_RX)
456 			dmactl = drvdata->hdmi_rd_dmactl;
457 		else
458 			dmactl = drvdata->rd_dmactl;
459 	} else {
460 		dmactl = drvdata->wr_dmactl;
461 		id = pcm_data->dma_ch - v->wrdma_channel_start;
462 	}
463 
464 	switch (cmd) {
465 	case SNDRV_PCM_TRIGGER_START:
466 	case SNDRV_PCM_TRIGGER_RESUME:
467 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
468 		ret = regmap_fields_write(dmactl->enable, id,
469 						 LPAIF_DMACTL_ENABLE_ON);
470 		if (ret) {
471 			dev_err(soc_runtime->dev,
472 				"error writing to rdmactl reg: %d\n", ret);
473 			return ret;
474 		}
475 		switch (dai_id) {
476 		case LPASS_DP_RX:
477 			ret = regmap_fields_write(dmactl->dyncclk, id,
478 					 LPAIF_DMACTL_DYNCLK_ON);
479 			if (ret) {
480 				dev_err(soc_runtime->dev,
481 					"error writing to rdmactl reg: %d\n", ret);
482 				return ret;
483 			}
484 			map = drvdata->hdmiif_map;
485 			reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
486 			val_irqclr = (LPAIF_IRQ_ALL(ch) |
487 					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
488 					LPAIF_IRQ_HDMI_METADONE |
489 					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
490 
491 			reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
492 			val_mask = (LPAIF_IRQ_ALL(ch) |
493 					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
494 					LPAIF_IRQ_HDMI_METADONE |
495 					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
496 			val_irqen = (LPAIF_IRQ_ALL(ch) |
497 					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
498 					LPAIF_IRQ_HDMI_METADONE |
499 					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
500 			break;
501 		case MI2S_PRIMARY:
502 		case MI2S_SECONDARY:
503 			map = drvdata->lpaif_map;
504 			reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
505 			val_irqclr = LPAIF_IRQ_ALL(ch);
506 
507 
508 			reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
509 			val_mask = LPAIF_IRQ_ALL(ch);
510 			val_irqen = LPAIF_IRQ_ALL(ch);
511 			break;
512 		default:
513 			dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
514 			return -EINVAL;
515 		}
516 
517 		ret = regmap_write(map, reg_irqclr, val_irqclr);
518 		if (ret) {
519 			dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);
520 			return ret;
521 		}
522 		ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
523 		if (ret) {
524 			dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret);
525 			return ret;
526 		}
527 		break;
528 	case SNDRV_PCM_TRIGGER_STOP:
529 	case SNDRV_PCM_TRIGGER_SUSPEND:
530 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
531 		ret = regmap_fields_write(dmactl->enable, id,
532 					 LPAIF_DMACTL_ENABLE_OFF);
533 		if (ret) {
534 			dev_err(soc_runtime->dev,
535 				"error writing to rdmactl reg: %d\n", ret);
536 			return ret;
537 		}
538 		switch (dai_id) {
539 		case LPASS_DP_RX:
540 			ret = regmap_fields_write(dmactl->dyncclk, id,
541 					 LPAIF_DMACTL_DYNCLK_OFF);
542 			if (ret) {
543 				dev_err(soc_runtime->dev,
544 					"error writing to rdmactl reg: %d\n", ret);
545 				return ret;
546 			}
547 			map = drvdata->hdmiif_map;
548 			reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
549 			val_mask = (LPAIF_IRQ_ALL(ch) |
550 					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
551 					LPAIF_IRQ_HDMI_METADONE |
552 					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
553 			val_irqen = 0;
554 			break;
555 		case MI2S_PRIMARY:
556 		case MI2S_SECONDARY:
557 			map = drvdata->lpaif_map;
558 			reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
559 			val_mask = LPAIF_IRQ_ALL(ch);
560 			val_irqen = 0;
561 			break;
562 		default:
563 			dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
564 			return -EINVAL;
565 		}
566 
567 		ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
568 		if (ret) {
569 			dev_err(soc_runtime->dev,
570 				"error writing to irqen reg: %d\n", ret);
571 			return ret;
572 		}
573 		break;
574 	}
575 
576 	return 0;
577 }
578 
579 static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
580 		struct snd_soc_component *component,
581 		struct snd_pcm_substream *substream)
582 {
583 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
584 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
585 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
586 	struct snd_pcm_runtime *rt = substream->runtime;
587 	struct lpass_pcm_data *pcm_data = rt->private_data;
588 	struct lpass_variant *v = drvdata->variant;
589 	unsigned int base_addr, curr_addr;
590 	int ret, ch, dir = substream->stream;
591 	struct regmap *map;
592 	unsigned int dai_id = cpu_dai->driver->id;
593 
594 	if (dai_id == LPASS_DP_RX)
595 		map = drvdata->hdmiif_map;
596 	else
597 		map = drvdata->lpaif_map;
598 
599 	ch = pcm_data->dma_ch;
600 
601 	ret = regmap_read(map,
602 			LPAIF_DMABASE_REG(v, ch, dir, dai_id), &base_addr);
603 	if (ret) {
604 		dev_err(soc_runtime->dev,
605 			"error reading from rdmabase reg: %d\n", ret);
606 		return ret;
607 	}
608 
609 	ret = regmap_read(map,
610 			LPAIF_DMACURR_REG(v, ch, dir, dai_id), &curr_addr);
611 	if (ret) {
612 		dev_err(soc_runtime->dev,
613 			"error reading from rdmacurr reg: %d\n", ret);
614 		return ret;
615 	}
616 
617 	return bytes_to_frames(substream->runtime, curr_addr - base_addr);
618 }
619 
620 static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
621 				      struct snd_pcm_substream *substream,
622 				      struct vm_area_struct *vma)
623 {
624 	struct snd_pcm_runtime *runtime = substream->runtime;
625 
626 	return dma_mmap_coherent(component->dev, vma, runtime->dma_area,
627 				 runtime->dma_addr, runtime->dma_bytes);
628 }
629 
630 static irqreturn_t lpass_dma_interrupt_handler(
631 			struct snd_pcm_substream *substream,
632 			struct lpass_data *drvdata,
633 			int chan, u32 interrupts)
634 {
635 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
636 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
637 	struct lpass_variant *v = drvdata->variant;
638 	irqreturn_t ret = IRQ_NONE;
639 	int rv;
640 	unsigned int reg = 0, val = 0;
641 	struct regmap *map;
642 	unsigned int dai_id = cpu_dai->driver->id;
643 
644 	switch (dai_id) {
645 	case LPASS_DP_RX:
646 		map = drvdata->hdmiif_map;
647 		reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
648 		val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
649 		LPAIF_IRQ_HDMI_METADONE |
650 		LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan));
651 	break;
652 	case MI2S_PRIMARY:
653 	case MI2S_SECONDARY:
654 		map = drvdata->lpaif_map;
655 		reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
656 		val = 0;
657 	break;
658 	default:
659 	dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
660 	return -EINVAL;
661 	}
662 	if (interrupts & LPAIF_IRQ_PER(chan)) {
663 
664 		rv = regmap_write(map, reg, LPAIF_IRQ_PER(chan) | val);
665 		if (rv) {
666 			dev_err(soc_runtime->dev,
667 				"error writing to irqclear reg: %d\n", rv);
668 			return IRQ_NONE;
669 		}
670 		snd_pcm_period_elapsed(substream);
671 		ret = IRQ_HANDLED;
672 	}
673 
674 	if (interrupts & LPAIF_IRQ_XRUN(chan)) {
675 		rv = regmap_write(map, reg, LPAIF_IRQ_XRUN(chan) | val);
676 		if (rv) {
677 			dev_err(soc_runtime->dev,
678 				"error writing to irqclear reg: %d\n", rv);
679 			return IRQ_NONE;
680 		}
681 		dev_warn(soc_runtime->dev, "xrun warning\n");
682 		snd_pcm_stop_xrun(substream);
683 		ret = IRQ_HANDLED;
684 	}
685 
686 	if (interrupts & LPAIF_IRQ_ERR(chan)) {
687 		rv = regmap_write(map, reg, LPAIF_IRQ_ERR(chan) | val);
688 		if (rv) {
689 			dev_err(soc_runtime->dev,
690 				"error writing to irqclear reg: %d\n", rv);
691 			return IRQ_NONE;
692 		}
693 		dev_err(soc_runtime->dev, "bus access error\n");
694 		snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
695 		ret = IRQ_HANDLED;
696 	}
697 
698 	if (interrupts & val) {
699 		rv = regmap_write(map, reg, val);
700 		if (rv) {
701 			dev_err(soc_runtime->dev,
702 			"error writing to irqclear reg: %d\n", rv);
703 			return IRQ_NONE;
704 		}
705 		ret = IRQ_HANDLED;
706 	}
707 
708 	return ret;
709 }
710 
711 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
712 {
713 	struct lpass_data *drvdata = data;
714 	struct lpass_variant *v = drvdata->variant;
715 	unsigned int irqs;
716 	int rv, chan;
717 
718 	rv = regmap_read(drvdata->lpaif_map,
719 			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
720 	if (rv) {
721 		pr_err("error reading from irqstat reg: %d\n", rv);
722 		return IRQ_NONE;
723 	}
724 
725 	/* Handle per channel interrupts */
726 	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
727 		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
728 			rv = lpass_dma_interrupt_handler(
729 						drvdata->substream[chan],
730 						drvdata, chan, irqs);
731 			if (rv != IRQ_HANDLED)
732 				return rv;
733 		}
734 	}
735 
736 	return IRQ_HANDLED;
737 }
738 
739 static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
740 {
741 	struct lpass_data *drvdata = data;
742 	struct lpass_variant *v = drvdata->variant;
743 	unsigned int irqs;
744 	int rv, chan;
745 
746 	rv = regmap_read(drvdata->hdmiif_map,
747 			LPASS_HDMITX_APP_IRQSTAT_REG(v), &irqs);
748 	if (rv) {
749 		pr_err("error reading from irqstat reg: %d\n", rv);
750 		return IRQ_NONE;
751 	}
752 
753 	/* Handle per channel interrupts */
754 	for (chan = 0; chan < LPASS_MAX_HDMI_DMA_CHANNELS; chan++) {
755 		if (irqs & (LPAIF_IRQ_ALL(chan) | LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
756 				LPAIF_IRQ_HDMI_METADONE |
757 				LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan))
758 			&& drvdata->hdmi_substream[chan]) {
759 			rv = lpass_dma_interrupt_handler(
760 						drvdata->hdmi_substream[chan],
761 						drvdata, chan, irqs);
762 			if (rv != IRQ_HANDLED)
763 				return rv;
764 		}
765 	}
766 
767 	return IRQ_HANDLED;
768 }
769 
770 static int lpass_platform_pcm_new(struct snd_soc_component *component,
771 				  struct snd_soc_pcm_runtime *soc_runtime)
772 {
773 	struct snd_pcm *pcm = soc_runtime->pcm;
774 	struct snd_pcm_substream *psubstream, *csubstream;
775 	int ret = -EINVAL;
776 	size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
777 
778 	psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
779 	if (psubstream) {
780 		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
781 					component->dev,
782 					size, &psubstream->dma_buffer);
783 		if (ret) {
784 			dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
785 			return ret;
786 		}
787 	}
788 
789 	csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
790 	if (csubstream) {
791 		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
792 					component->dev,
793 					size, &csubstream->dma_buffer);
794 		if (ret) {
795 			dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
796 			if (psubstream)
797 				snd_dma_free_pages(&psubstream->dma_buffer);
798 			return ret;
799 		}
800 
801 	}
802 
803 	return 0;
804 }
805 
806 static void lpass_platform_pcm_free(struct snd_soc_component *component,
807 				    struct snd_pcm *pcm)
808 {
809 	struct snd_pcm_substream *substream;
810 	int i;
811 
812 	for_each_pcm_streams(i) {
813 		substream = pcm->streams[i].substream;
814 		if (substream) {
815 			snd_dma_free_pages(&substream->dma_buffer);
816 			substream->dma_buffer.area = NULL;
817 			substream->dma_buffer.addr = 0;
818 		}
819 	}
820 }
821 
822 static const struct snd_soc_component_driver lpass_component_driver = {
823 	.name		= DRV_NAME,
824 	.open		= lpass_platform_pcmops_open,
825 	.close		= lpass_platform_pcmops_close,
826 	.hw_params	= lpass_platform_pcmops_hw_params,
827 	.hw_free	= lpass_platform_pcmops_hw_free,
828 	.prepare	= lpass_platform_pcmops_prepare,
829 	.trigger	= lpass_platform_pcmops_trigger,
830 	.pointer	= lpass_platform_pcmops_pointer,
831 	.mmap		= lpass_platform_pcmops_mmap,
832 	.pcm_construct	= lpass_platform_pcm_new,
833 	.pcm_destruct	= lpass_platform_pcm_free,
834 
835 };
836 
837 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
838 {
839 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
840 	struct lpass_variant *v = drvdata->variant;
841 	int ret;
842 
843 	drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
844 	if (drvdata->lpaif_irq < 0)
845 		return -ENODEV;
846 
847 	/* ensure audio hardware is disabled */
848 	ret = regmap_write(drvdata->lpaif_map,
849 			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
850 	if (ret) {
851 		dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
852 		return ret;
853 	}
854 
855 	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
856 			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
857 			"lpass-irq-lpaif", drvdata);
858 	if (ret) {
859 		dev_err(&pdev->dev, "irq request failed: %d\n", ret);
860 		return ret;
861 	}
862 
863 	ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
864 						 drvdata->lpaif_map);
865 	if (ret) {
866 		dev_err(&pdev->dev,
867 			"error initializing dmactl fields: %d\n", ret);
868 		return ret;
869 	}
870 
871 	if (drvdata->hdmi_port_enable) {
872 		drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
873 		if (drvdata->hdmiif_irq < 0)
874 			return -ENODEV;
875 
876 		ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq,
877 				lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata);
878 		if (ret) {
879 			dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret);
880 			return ret;
881 		}
882 		ret = regmap_write(drvdata->hdmiif_map,
883 				LPASS_HDMITX_APP_IRQEN_REG(v), 0);
884 		if (ret) {
885 			dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret);
886 			return ret;
887 		}
888 
889 		ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev,
890 							 drvdata->hdmiif_map);
891 		if (ret) {
892 			dev_err(&pdev->dev,
893 				"error initializing hdmidmactl fields: %d\n", ret);
894 			return ret;
895 		}
896 	}
897 	return devm_snd_soc_register_component(&pdev->dev,
898 			&lpass_component_driver, NULL, 0);
899 }
900 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
901 
902 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
903 MODULE_LICENSE("GPL v2");
904