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