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