brintos

brintos / linux-shallow public Read only

0
0
Text · 39.8 KiB · addd2c4 Raw
1388 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.4 *5 * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS6 */7 8#include <dt-bindings/sound/qcom,lpass.h>9#include <linux/dma-mapping.h>10#include <linux/export.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <sound/pcm_params.h>15#include <linux/regmap.h>16#include <sound/soc.h>17#include "lpass-lpaif-reg.h"18#include "lpass.h"19 20#define DRV_NAME "lpass-platform"21 22#define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)23#define LPASS_PLATFORM_PERIODS		224#define LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE (8 * 1024)25#define LPASS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)26#define LPASS_CDC_DMA_REGISTER_FIELDS_MAX 1527 28static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {29	.info			=	SNDRV_PCM_INFO_MMAP |30					SNDRV_PCM_INFO_MMAP_VALID |31					SNDRV_PCM_INFO_INTERLEAVED |32					SNDRV_PCM_INFO_PAUSE |33					SNDRV_PCM_INFO_RESUME,34	.formats		=	SNDRV_PCM_FMTBIT_S16 |35					SNDRV_PCM_FMTBIT_S24 |36					SNDRV_PCM_FMTBIT_S32,37	.rates			=	SNDRV_PCM_RATE_8000_192000,38	.rate_min		=	8000,39	.rate_max		=	192000,40	.channels_min		=	1,41	.channels_max		=	8,42	.buffer_bytes_max	=	LPASS_PLATFORM_BUFFER_SIZE,43	.period_bytes_max	=	LPASS_PLATFORM_BUFFER_SIZE /44						LPASS_PLATFORM_PERIODS,45	.period_bytes_min	=	LPASS_PLATFORM_BUFFER_SIZE /46						LPASS_PLATFORM_PERIODS,47	.periods_min		=	LPASS_PLATFORM_PERIODS,48	.periods_max		=	LPASS_PLATFORM_PERIODS,49	.fifo_size		=	0,50};51 52static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {53	.info			=	SNDRV_PCM_INFO_MMAP |54					SNDRV_PCM_INFO_MMAP_VALID |55					SNDRV_PCM_INFO_INTERLEAVED |56					SNDRV_PCM_INFO_PAUSE |57					SNDRV_PCM_INFO_RESUME,58	.formats		=	SNDRV_PCM_FMTBIT_S16 |59					SNDRV_PCM_FMTBIT_S24 |60					SNDRV_PCM_FMTBIT_S32,61	.rates			=	SNDRV_PCM_RATE_8000_192000,62	.rate_min		=	8000,63	.rate_max		=	192000,64	.channels_min		=	1,65	.channels_max		=	8,66	.buffer_bytes_max	=	LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE,67	.period_bytes_max	=	LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /68						LPASS_PLATFORM_PERIODS,69	.period_bytes_min	=	LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /70						LPASS_PLATFORM_PERIODS,71	.periods_min		=	LPASS_PLATFORM_PERIODS,72	.periods_max		=	LPASS_PLATFORM_PERIODS,73	.fifo_size		=	0,74};75 76static const struct snd_pcm_hardware lpass_platform_va_hardware = {77	.info			=	SNDRV_PCM_INFO_MMAP |78					SNDRV_PCM_INFO_MMAP_VALID |79					SNDRV_PCM_INFO_INTERLEAVED |80					SNDRV_PCM_INFO_PAUSE |81					SNDRV_PCM_INFO_RESUME,82	.formats		=	SNDRV_PCM_FMTBIT_S16 |83					SNDRV_PCM_FMTBIT_S24 |84					SNDRV_PCM_FMTBIT_S32,85	.rates			=	SNDRV_PCM_RATE_8000_192000,86	.rate_min		=	8000,87	.rate_max		=	192000,88	.channels_min		=	1,89	.channels_max		=	8,90	.buffer_bytes_max	=	LPASS_VA_CDC_DMA_LPM_BUFF_SIZE,91	.period_bytes_max	=	LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /92						LPASS_PLATFORM_PERIODS,93	.period_bytes_min	=	LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /94						LPASS_PLATFORM_PERIODS,95	.periods_min		=	LPASS_PLATFORM_PERIODS,96	.periods_max		=	LPASS_PLATFORM_PERIODS,97	.fifo_size		=	0,98};99 100static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,101					 struct regmap *map)102{103	struct lpass_data *drvdata = dev_get_drvdata(dev);104	const struct lpass_variant *v = drvdata->variant;105	struct lpaif_dmactl *rd_dmactl, *wr_dmactl;106	int rval;107 108	rd_dmactl = devm_kzalloc(dev, sizeof(*rd_dmactl), GFP_KERNEL);109	if (!rd_dmactl)110		return -ENOMEM;111 112	wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);113	if (!wr_dmactl)114		return -ENOMEM;115 116	drvdata->rxtx_rd_dmactl = rd_dmactl;117	drvdata->rxtx_wr_dmactl = wr_dmactl;118 119	rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,120					    &v->rxtx_rdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);121	if (rval)122		return rval;123 124	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,125					    &v->rxtx_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);126}127 128static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,129					 struct regmap *map)130{131	struct lpass_data *drvdata = dev_get_drvdata(dev);132	const struct lpass_variant *v = drvdata->variant;133	struct lpaif_dmactl *wr_dmactl;134 135	wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);136	if (!wr_dmactl)137		return -ENOMEM;138 139	drvdata->va_wr_dmactl = wr_dmactl;140	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,141					    &v->va_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);142}143 144 145static int lpass_platform_alloc_dmactl_fields(struct device *dev,146					 struct regmap *map)147{148	struct lpass_data *drvdata = dev_get_drvdata(dev);149	const struct lpass_variant *v = drvdata->variant;150	struct lpaif_dmactl *rd_dmactl, *wr_dmactl;151	int rval;152 153	drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),154					  GFP_KERNEL);155	if (drvdata->rd_dmactl == NULL)156		return -ENOMEM;157 158	drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),159					  GFP_KERNEL);160	if (drvdata->wr_dmactl == NULL)161		return -ENOMEM;162 163	rd_dmactl = drvdata->rd_dmactl;164	wr_dmactl = drvdata->wr_dmactl;165 166	rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,167					    &v->rdma_intf, 6);168	if (rval)169		return rval;170 171	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,172					    &v->wrdma_intf, 6);173}174 175static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev,176					 struct regmap *map)177{178	struct lpass_data *drvdata = dev_get_drvdata(dev);179	const struct lpass_variant *v = drvdata->variant;180	struct lpaif_dmactl *rd_dmactl;181 182	rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), GFP_KERNEL);183	if (rd_dmactl == NULL)184		return -ENOMEM;185 186	drvdata->hdmi_rd_dmactl = rd_dmactl;187 188	return devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->bursten,189					    &v->hdmi_rdma_bursten, 8);190}191 192static int lpass_platform_pcmops_open(struct snd_soc_component *component,193				      struct snd_pcm_substream *substream)194{195	struct snd_pcm_runtime *runtime = substream->runtime;196	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);197	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);198	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);199	const struct lpass_variant *v = drvdata->variant;200	int ret, dma_ch, dir = substream->stream;201	struct lpass_pcm_data *data;202	struct regmap *map;203	unsigned int dai_id = cpu_dai->driver->id;204 205	component->id = dai_id;206	data = kzalloc(sizeof(*data), GFP_KERNEL);207	if (!data)208		return -ENOMEM;209 210	data->i2s_port = cpu_dai->driver->id;211	runtime->private_data = data;212 213	if (v->alloc_dma_channel)214		dma_ch = v->alloc_dma_channel(drvdata, dir, dai_id);215	else216		dma_ch = 0;217 218	if (dma_ch < 0) {219		kfree(data);220		return dma_ch;221	}222 223	switch (dai_id) {224	case MI2S_PRIMARY ... MI2S_QUINARY:225		map = drvdata->lpaif_map;226		drvdata->substream[dma_ch] = substream;227		break;228	case LPASS_DP_RX:229		map = drvdata->hdmiif_map;230		drvdata->hdmi_substream[dma_ch] = substream;231		break;232	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:233	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:234		map = drvdata->rxtx_lpaif_map;235		drvdata->rxtx_substream[dma_ch] = substream;236		break;237	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:238		map = drvdata->va_lpaif_map;239		drvdata->va_substream[dma_ch] = substream;240		break;241	default:242		break;243	}244 245	data->dma_ch = dma_ch;246	switch (dai_id) {247	case MI2S_PRIMARY ... MI2S_QUINARY:248	case LPASS_DP_RX:249		ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);250		if (ret) {251			kfree(data);252			dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret);253			return ret;254		}255		snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);256		runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;257		break;258	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:259	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:260		snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);261		runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;262		snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);263		break;264	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:265		snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);266		runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;267		snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);268		break;269	default:270		break;271	}272	ret = snd_pcm_hw_constraint_integer(runtime,273			SNDRV_PCM_HW_PARAM_PERIODS);274	if (ret < 0) {275		kfree(data);276		dev_err(soc_runtime->dev, "setting constraints failed: %d\n",277			ret);278		return -EINVAL;279	}280 281	return 0;282}283 284static int lpass_platform_pcmops_close(struct snd_soc_component *component,285				       struct snd_pcm_substream *substream)286{287	struct snd_pcm_runtime *runtime = substream->runtime;288	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);289	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);290	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);291	const struct lpass_variant *v = drvdata->variant;292	struct lpass_pcm_data *data;293	unsigned int dai_id = cpu_dai->driver->id;294 295	data = runtime->private_data;296 297	switch (dai_id) {298	case MI2S_PRIMARY ... MI2S_QUINARY:299		drvdata->substream[data->dma_ch] = NULL;300		break;301	case LPASS_DP_RX:302		drvdata->hdmi_substream[data->dma_ch] = NULL;303		break;304	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:305	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:306		drvdata->rxtx_substream[data->dma_ch] = NULL;307		break;308	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:309		drvdata->va_substream[data->dma_ch] = NULL;310		break;311	default:312		break;313	}314 315	if (v->free_dma_channel)316		v->free_dma_channel(drvdata, data->dma_ch, dai_id);317 318	kfree(data);319	return 0;320}321 322static struct lpaif_dmactl *__lpass_get_dmactl_handle(const struct snd_pcm_substream *substream,323				     struct snd_soc_component *component)324{325	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);326	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);327	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);328	struct lpaif_dmactl *dmactl = NULL;329 330	switch (cpu_dai->driver->id) {331	case MI2S_PRIMARY ... MI2S_QUINARY:332		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)333			dmactl = drvdata->rd_dmactl;334		else335			dmactl = drvdata->wr_dmactl;336		break;337	case LPASS_DP_RX:338		dmactl = drvdata->hdmi_rd_dmactl;339		break;340	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:341		dmactl = drvdata->rxtx_rd_dmactl;342		break;343	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:344		dmactl = drvdata->rxtx_wr_dmactl;345		break;346	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:347		dmactl = drvdata->va_wr_dmactl;348		break;349	}350 351	return dmactl;352}353 354static int __lpass_get_id(const struct snd_pcm_substream *substream,355				     struct snd_soc_component *component)356{357	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);358	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);359	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);360	struct snd_pcm_runtime *rt = substream->runtime;361	struct lpass_pcm_data *pcm_data = rt->private_data;362	const struct lpass_variant *v = drvdata->variant;363	int id;364 365	switch (cpu_dai->driver->id) {366	case MI2S_PRIMARY ... MI2S_QUINARY:367		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)368			id = pcm_data->dma_ch;369		else370			id = pcm_data->dma_ch - v->wrdma_channel_start;371		break;372	case LPASS_DP_RX:373		id = pcm_data->dma_ch;374		break;375	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:376		id = pcm_data->dma_ch;377		break;378	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:379		id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;380		break;381	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:382		id = pcm_data->dma_ch - v->va_wrdma_channel_start;383		break;384	}385 386	return id;387}388 389static struct regmap *__lpass_get_regmap_handle(const struct snd_pcm_substream *substream,390				     struct snd_soc_component *component)391{392	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);393	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);394	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);395	struct regmap *map = NULL;396 397	switch (cpu_dai->driver->id) {398	case MI2S_PRIMARY ... MI2S_QUINARY:399		map = drvdata->lpaif_map;400		break;401	case LPASS_DP_RX:402		map = drvdata->hdmiif_map;403		break;404	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:405	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:406		map = drvdata->rxtx_lpaif_map;407		break;408	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:409		map = drvdata->va_lpaif_map;410		break;411	}412 413	return map;414}415 416static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,417					   struct snd_pcm_substream *substream,418					   struct snd_pcm_hw_params *params)419{420	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);421	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);422	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);423	struct snd_pcm_runtime *rt = substream->runtime;424	struct lpass_pcm_data *pcm_data = rt->private_data;425	const struct lpass_variant *v = drvdata->variant;426	snd_pcm_format_t format = params_format(params);427	unsigned int channels = params_channels(params);428	unsigned int regval;429	struct lpaif_dmactl *dmactl;430	int id;431	int bitwidth;432	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;433	unsigned int dai_id = cpu_dai->driver->id;434 435	dmactl = __lpass_get_dmactl_handle(substream, component);436	id = __lpass_get_id(substream, component);437 438	bitwidth = snd_pcm_format_width(format);439	if (bitwidth < 0) {440		dev_err(soc_runtime->dev, "invalid bit width given: %d\n",441				bitwidth);442		return bitwidth;443	}444 445	ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4);446	if (ret) {447		dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret);448		return ret;449	}450 451	ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);452	if (ret) {453		dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret);454		return ret;455	}456 457	switch (dai_id) {458	case LPASS_DP_RX:459		ret = regmap_fields_write(dmactl->burst8, id,460							LPAIF_DMACTL_BURSTEN_INCR4);461		if (ret) {462			dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret);463			return ret;464		}465		ret = regmap_fields_write(dmactl->burst16, id,466							LPAIF_DMACTL_BURSTEN_INCR4);467		if (ret) {468			dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret);469			return ret;470		}471		ret = regmap_fields_write(dmactl->dynburst, id,472							LPAIF_DMACTL_BURSTEN_INCR4);473		if (ret) {474			dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret);475			return ret;476		}477		break;478	case MI2S_PRIMARY:479	case MI2S_SECONDARY:480	case MI2S_TERTIARY:481	case MI2S_QUATERNARY:482	case MI2S_QUINARY:483		ret = regmap_fields_write(dmactl->intf, id,484						LPAIF_DMACTL_AUDINTF(dma_port));485		if (ret) {486			dev_err(soc_runtime->dev, "error updating audio interface field: %d\n",487					ret);488			return ret;489		}490 491		break;492	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:493	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:494	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:495		break;496	default:497		dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);498		break;499	}500	switch (bitwidth) {501	case 16:502		switch (channels) {503		case 1:504		case 2:505			regval = LPAIF_DMACTL_WPSCNT_ONE;506			break;507		case 4:508			regval = LPAIF_DMACTL_WPSCNT_TWO;509			break;510		case 6:511			regval = LPAIF_DMACTL_WPSCNT_THREE;512			break;513		case 8:514			regval = LPAIF_DMACTL_WPSCNT_FOUR;515			break;516		default:517			dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",518				bitwidth, channels);519			return -EINVAL;520		}521		break;522	case 24:523	case 32:524		switch (channels) {525		case 1:526			regval = LPAIF_DMACTL_WPSCNT_ONE;527			break;528		case 2:529			regval = (dai_id == LPASS_DP_RX ?530			LPAIF_DMACTL_WPSCNT_ONE :531			LPAIF_DMACTL_WPSCNT_TWO);532			break;533		case 4:534			regval = (dai_id == LPASS_DP_RX ?535			LPAIF_DMACTL_WPSCNT_TWO :536			LPAIF_DMACTL_WPSCNT_FOUR);537			break;538		case 6:539			regval = (dai_id == LPASS_DP_RX ?540			LPAIF_DMACTL_WPSCNT_THREE :541			LPAIF_DMACTL_WPSCNT_SIX);542			break;543		case 8:544			regval = (dai_id == LPASS_DP_RX ?545			LPAIF_DMACTL_WPSCNT_FOUR :546			LPAIF_DMACTL_WPSCNT_EIGHT);547			break;548		default:549			dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",550				bitwidth, channels);551			return -EINVAL;552		}553		break;554	default:555		dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",556			bitwidth, channels);557		return -EINVAL;558	}559 560	ret = regmap_fields_write(dmactl->wpscnt, id, regval);561	if (ret) {562		dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n",563			ret);564		return ret;565	}566 567	return 0;568}569 570static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,571					 struct snd_pcm_substream *substream)572{573	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);574	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);575	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);576	struct snd_pcm_runtime *rt = substream->runtime;577	struct lpass_pcm_data *pcm_data = rt->private_data;578	const struct lpass_variant *v = drvdata->variant;579	unsigned int reg;580	int ret;581	struct regmap *map;582	unsigned int dai_id = cpu_dai->driver->id;583 584	if (is_cdc_dma_port(dai_id))585		return 0;586	map = __lpass_get_regmap_handle(substream, component);587 588	reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);589	ret = regmap_write(map, reg, 0);590	if (ret)591		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",592			ret);593 594	return ret;595}596 597static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,598					 struct snd_pcm_substream *substream)599{600	struct snd_pcm_runtime *runtime = substream->runtime;601	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);602	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);603	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);604	struct snd_pcm_runtime *rt = substream->runtime;605	struct lpass_pcm_data *pcm_data = rt->private_data;606	const struct lpass_variant *v = drvdata->variant;607	struct lpaif_dmactl *dmactl;608	struct regmap *map;609	int ret, id, ch, dir = substream->stream;610	unsigned int dai_id = cpu_dai->driver->id;611 612	ch = pcm_data->dma_ch;613 614	dmactl = __lpass_get_dmactl_handle(substream, component);615	id = __lpass_get_id(substream, component);616	map = __lpass_get_regmap_handle(substream, component);617 618	ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),619				runtime->dma_addr);620	if (ret) {621		dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",622			ret);623		return ret;624	}625 626	ret = regmap_write(map, LPAIF_DMABUFF_REG(v, ch, dir, dai_id),627			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);628	if (ret) {629		dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",630			ret);631		return ret;632	}633 634	ret = regmap_write(map, LPAIF_DMAPER_REG(v, ch, dir, dai_id),635			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);636	if (ret) {637		dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",638			ret);639		return ret;640	}641 642	if (is_cdc_dma_port(dai_id)) {643		ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);644		if (ret) {645			dev_err(soc_runtime->dev, "error writing fifowm field to dmactl reg: %d, id: %d\n",646				ret, id);647			return ret;648		}649	}650	ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);651	if (ret) {652		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",653			ret);654		return ret;655	}656 657	return 0;658}659 660static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,661					 struct snd_pcm_substream *substream,662					 int cmd)663{664	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);665	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);666	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);667	struct snd_pcm_runtime *rt = substream->runtime;668	struct lpass_pcm_data *pcm_data = rt->private_data;669	const struct lpass_variant *v = drvdata->variant;670	struct lpaif_dmactl *dmactl;671	struct regmap *map;672	int ret, ch, id;673	unsigned int reg_irqclr = 0, val_irqclr = 0;674	unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;675	unsigned int dai_id = cpu_dai->driver->id;676 677	ch = pcm_data->dma_ch;678	dmactl = __lpass_get_dmactl_handle(substream, component);679	id = __lpass_get_id(substream, component);680	map = __lpass_get_regmap_handle(substream, component);681 682	switch (cmd) {683	case SNDRV_PCM_TRIGGER_START:684	case SNDRV_PCM_TRIGGER_RESUME:685	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:686		ret = regmap_fields_write(dmactl->enable, id,687						 LPAIF_DMACTL_ENABLE_ON);688		if (ret) {689			dev_err(soc_runtime->dev,690				"error writing to rdmactl reg: %d\n", ret);691			return ret;692		}693		switch (dai_id) {694		case LPASS_DP_RX:695			ret = regmap_fields_write(dmactl->dyncclk, id,696					 LPAIF_DMACTL_DYNCLK_ON);697			if (ret) {698				dev_err(soc_runtime->dev,699					"error writing to rdmactl reg: %d\n", ret);700				return ret;701			}702			reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);703			val_irqclr = (LPAIF_IRQ_ALL(ch) |704					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |705					LPAIF_IRQ_HDMI_METADONE |706					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));707 708			reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);709			val_mask = (LPAIF_IRQ_ALL(ch) |710					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |711					LPAIF_IRQ_HDMI_METADONE |712					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));713			val_irqen = (LPAIF_IRQ_ALL(ch) |714					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |715					LPAIF_IRQ_HDMI_METADONE |716					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));717			break;718		case MI2S_PRIMARY:719		case MI2S_SECONDARY:720		case MI2S_TERTIARY:721		case MI2S_QUATERNARY:722		case MI2S_QUINARY:723			reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);724			val_irqclr = LPAIF_IRQ_ALL(ch);725 726 727			reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);728			val_mask = LPAIF_IRQ_ALL(ch);729			val_irqen = LPAIF_IRQ_ALL(ch);730			break;731		case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:732		case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:733			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);734			if (ret) {735				dev_err(soc_runtime->dev,736					"error writing to rdmactl reg field: %d\n", ret);737				return ret;738			}739			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);740			val_irqclr = LPAIF_IRQ_ALL(ch);741 742			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);743			val_mask = LPAIF_IRQ_ALL(ch);744			val_irqen = LPAIF_IRQ_ALL(ch);745			break;746		case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:747			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);748			if (ret) {749				dev_err(soc_runtime->dev,750					"error writing to rdmactl reg field: %d\n", ret);751				return ret;752			}753			reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);754			val_irqclr = LPAIF_IRQ_ALL(ch);755 756			reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);757			val_mask = LPAIF_IRQ_ALL(ch);758			val_irqen = LPAIF_IRQ_ALL(ch);759			break;760		default:761			dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);762			return -EINVAL;763		}764 765		ret = regmap_write_bits(map, reg_irqclr, val_irqclr, val_irqclr);766		if (ret) {767			dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);768			return ret;769		}770		ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);771		if (ret) {772			dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret);773			return ret;774		}775		break;776	case SNDRV_PCM_TRIGGER_STOP:777	case SNDRV_PCM_TRIGGER_SUSPEND:778	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:779		ret = regmap_fields_write(dmactl->enable, id,780					 LPAIF_DMACTL_ENABLE_OFF);781		if (ret) {782			dev_err(soc_runtime->dev,783				"error writing to rdmactl reg: %d\n", ret);784			return ret;785		}786		switch (dai_id) {787		case LPASS_DP_RX:788			ret = regmap_fields_write(dmactl->dyncclk, id,789					 LPAIF_DMACTL_DYNCLK_OFF);790			if (ret) {791				dev_err(soc_runtime->dev,792					"error writing to rdmactl reg: %d\n", ret);793				return ret;794			}795			reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);796			val_mask = (LPAIF_IRQ_ALL(ch) |797					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |798					LPAIF_IRQ_HDMI_METADONE |799					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));800			val_irqen = 0;801			break;802		case MI2S_PRIMARY:803		case MI2S_SECONDARY:804		case MI2S_TERTIARY:805		case MI2S_QUATERNARY:806		case MI2S_QUINARY:807			reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);808			val_mask = LPAIF_IRQ_ALL(ch);809			val_irqen = 0;810			break;811		case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:812		case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:813			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);814			if (ret) {815				dev_err(soc_runtime->dev,816					"error writing to rdmactl reg field: %d\n", ret);817				return ret;818			}819 820			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);821			val_irqclr = LPAIF_IRQ_ALL(ch);822 823			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);824			val_mask = LPAIF_IRQ_ALL(ch);825			val_irqen = LPAIF_IRQ_ALL(ch);826			break;827		case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:828			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);829			if (ret) {830				dev_err(soc_runtime->dev,831					"error writing to rdmactl reg field: %d\n", ret);832				return ret;833			}834 835			reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);836			val_irqclr = LPAIF_IRQ_ALL(ch);837 838			reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);839			val_mask = LPAIF_IRQ_ALL(ch);840			val_irqen = LPAIF_IRQ_ALL(ch);841			break;842		default:843			dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);844			return -EINVAL;845		}846 847		ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);848		if (ret) {849			dev_err(soc_runtime->dev,850				"error writing to irqen reg: %d\n", ret);851			return ret;852		}853		break;854	}855 856	return 0;857}858 859static snd_pcm_uframes_t lpass_platform_pcmops_pointer(860		struct snd_soc_component *component,861		struct snd_pcm_substream *substream)862{863	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);864	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);865	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);866	struct snd_pcm_runtime *rt = substream->runtime;867	struct lpass_pcm_data *pcm_data = rt->private_data;868	const struct lpass_variant *v = drvdata->variant;869	unsigned int base_addr, curr_addr;870	int ret, ch, dir = substream->stream;871	struct regmap *map;872	unsigned int dai_id = cpu_dai->driver->id;873 874	map = __lpass_get_regmap_handle(substream, component);875	ch = pcm_data->dma_ch;876 877	ret = regmap_read(map,878			LPAIF_DMABASE_REG(v, ch, dir, dai_id), &base_addr);879	if (ret) {880		dev_err(soc_runtime->dev,881			"error reading from rdmabase reg: %d\n", ret);882		return ret;883	}884 885	ret = regmap_read(map,886			LPAIF_DMACURR_REG(v, ch, dir, dai_id), &curr_addr);887	if (ret) {888		dev_err(soc_runtime->dev,889			"error reading from rdmacurr reg: %d\n", ret);890		return ret;891	}892 893	return bytes_to_frames(substream->runtime, curr_addr - base_addr);894}895 896static int lpass_platform_cdc_dma_mmap(struct snd_pcm_substream *substream,897				       struct vm_area_struct *vma)898{899	struct snd_pcm_runtime *runtime = substream->runtime;900	unsigned long size, offset;901 902	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);903	size = vma->vm_end - vma->vm_start;904	offset = vma->vm_pgoff << PAGE_SHIFT;905	return io_remap_pfn_range(vma, vma->vm_start,906			(runtime->dma_addr + offset) >> PAGE_SHIFT,907			size, vma->vm_page_prot);908 909}910 911static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,912				      struct snd_pcm_substream *substream,913				      struct vm_area_struct *vma)914{915	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);916	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);917	unsigned int dai_id = cpu_dai->driver->id;918 919	if (is_cdc_dma_port(dai_id))920		return lpass_platform_cdc_dma_mmap(substream, vma);921 922	return snd_pcm_lib_default_mmap(substream, vma);923}924 925static irqreturn_t lpass_dma_interrupt_handler(926			struct snd_pcm_substream *substream,927			struct lpass_data *drvdata,928			int chan, u32 interrupts)929{930	struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);931	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);932	const struct lpass_variant *v = drvdata->variant;933	irqreturn_t ret = IRQ_NONE;934	int rv;935	unsigned int reg, val, mask;936	struct regmap *map;937	unsigned int dai_id = cpu_dai->driver->id;938 939	mask = LPAIF_IRQ_ALL(chan);940	switch (dai_id) {941	case LPASS_DP_RX:942		map = drvdata->hdmiif_map;943		reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);944		val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |945		LPAIF_IRQ_HDMI_METADONE |946		LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan));947	break;948	case MI2S_PRIMARY:949	case MI2S_SECONDARY:950	case MI2S_TERTIARY:951	case MI2S_QUATERNARY:952	case MI2S_QUINARY:953		map = drvdata->lpaif_map;954		reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);955		val = 0;956	break;957	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:958	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:959		map = drvdata->rxtx_lpaif_map;960		reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);961		val = 0;962	break;963	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:964		map = drvdata->va_lpaif_map;965		reg = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);966		val = 0;967	break;968	default:969	dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);970	return -EINVAL;971	}972	if (interrupts & LPAIF_IRQ_PER(chan)) {973		rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val));974		if (rv) {975			dev_err(soc_runtime->dev,976				"error writing to irqclear reg: %d\n", rv);977			return IRQ_NONE;978		}979		snd_pcm_period_elapsed(substream);980		ret = IRQ_HANDLED;981	}982 983	if (interrupts & LPAIF_IRQ_XRUN(chan)) {984		rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val));985		if (rv) {986			dev_err(soc_runtime->dev,987				"error writing to irqclear reg: %d\n", rv);988			return IRQ_NONE;989		}990		dev_warn_ratelimited(soc_runtime->dev, "xrun warning\n");991 992		snd_pcm_stop_xrun(substream);993		ret = IRQ_HANDLED;994	}995 996	if (interrupts & LPAIF_IRQ_ERR(chan)) {997		rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val));998		if (rv) {999			dev_err(soc_runtime->dev,1000				"error writing to irqclear reg: %d\n", rv);1001			return IRQ_NONE;1002		}1003		dev_err(soc_runtime->dev, "bus access error\n");1004		snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);1005		ret = IRQ_HANDLED;1006	}1007 1008	if (interrupts & val) {1009		rv = regmap_write(map, reg, val);1010		if (rv) {1011			dev_err(soc_runtime->dev,1012			"error writing to irqclear reg: %d\n", rv);1013			return IRQ_NONE;1014		}1015		ret = IRQ_HANDLED;1016	}1017 1018	return ret;1019}1020 1021static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)1022{1023	struct lpass_data *drvdata = data;1024	const struct lpass_variant *v = drvdata->variant;1025	unsigned int irqs;1026	int rv, chan;1027 1028	rv = regmap_read(drvdata->lpaif_map,1029			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);1030	if (rv) {1031		pr_err("error reading from irqstat reg: %d\n", rv);1032		return IRQ_NONE;1033	}1034 1035	/* Handle per channel interrupts */1036	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {1037		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {1038			rv = lpass_dma_interrupt_handler(1039						drvdata->substream[chan],1040						drvdata, chan, irqs);1041			if (rv != IRQ_HANDLED)1042				return rv;1043		}1044	}1045 1046	return IRQ_HANDLED;1047}1048 1049static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)1050{1051	struct lpass_data *drvdata = data;1052	const struct lpass_variant *v = drvdata->variant;1053	unsigned int irqs;1054	int rv, chan;1055 1056	rv = regmap_read(drvdata->hdmiif_map,1057			LPASS_HDMITX_APP_IRQSTAT_REG(v), &irqs);1058	if (rv) {1059		pr_err("error reading from irqstat reg: %d\n", rv);1060		return IRQ_NONE;1061	}1062 1063	/* Handle per channel interrupts */1064	for (chan = 0; chan < LPASS_MAX_HDMI_DMA_CHANNELS; chan++) {1065		if (irqs & (LPAIF_IRQ_ALL(chan) | LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |1066				LPAIF_IRQ_HDMI_METADONE |1067				LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan))1068			&& drvdata->hdmi_substream[chan]) {1069			rv = lpass_dma_interrupt_handler(1070						drvdata->hdmi_substream[chan],1071						drvdata, chan, irqs);1072			if (rv != IRQ_HANDLED)1073				return rv;1074		}1075	}1076	return IRQ_HANDLED;1077}1078 1079static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)1080{1081	struct lpass_data *drvdata = data;1082	const struct lpass_variant *v = drvdata->variant;1083	unsigned int irqs;1084	irqreturn_t rv;1085	int chan;1086 1087	rv = regmap_read(drvdata->rxtx_lpaif_map,1088			LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);1089 1090	/* Handle per channel interrupts */1091	for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {1092		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->rxtx_substream[chan]) {1093			rv = lpass_dma_interrupt_handler(1094						drvdata->rxtx_substream[chan],1095						drvdata, chan, irqs);1096			if (rv != IRQ_HANDLED)1097				return rv;1098		}1099	}1100 1101	return IRQ_HANDLED;1102}1103 1104static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)1105{1106	struct lpass_data *drvdata = data;1107	const struct lpass_variant *v = drvdata->variant;1108	unsigned int irqs;1109	irqreturn_t rv;1110	int chan;1111 1112	rv = regmap_read(drvdata->va_lpaif_map,1113			LPAIF_VA_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);1114 1115	/* Handle per channel interrupts */1116	for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {1117		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->va_substream[chan]) {1118			rv = lpass_dma_interrupt_handler(1119						drvdata->va_substream[chan],1120						drvdata, chan, irqs);1121			if (rv != IRQ_HANDLED)1122				return rv;1123		}1124	}1125	return IRQ_HANDLED;1126}1127 1128static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *component,1129						  struct snd_pcm *pcm, int dai_id)1130{1131	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);1132	struct snd_pcm_substream *substream;1133	struct snd_dma_buffer *buf;1134 1135	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)1136		substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;1137	else1138		substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;1139 1140	buf = &substream->dma_buffer;1141	buf->dev.dev = pcm->card->dev;1142	buf->private_data = NULL;1143 1144	/* Assign Codec DMA buffer pointers */1145	buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;1146 1147	switch (dai_id) {1148	case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:1149		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;1150		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;1151		break;1152	case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:1153		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;1154		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE;1155		break;1156	case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:1157		buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;1158		buf->addr = drvdata->va_cdc_dma_lpm_buf;1159		break;1160	default:1161		break;1162	}1163 1164	buf->area = (unsigned char * __force)memremap(buf->addr, buf->bytes, MEMREMAP_WC);1165 1166	return 0;1167}1168 1169static int lpass_platform_pcm_new(struct snd_soc_component *component,1170				  struct snd_soc_pcm_runtime *soc_runtime)1171{1172	struct snd_pcm *pcm = soc_runtime->pcm;1173	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);1174	unsigned int dai_id = cpu_dai->driver->id;1175 1176	size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;1177 1178	/*1179	 * Lpass codec dma can access only lpass lpm hardware memory.1180	 * ioremap is for HLOS to access hardware memory.1181	 */1182	if (is_cdc_dma_port(dai_id))1183		return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);1184 1185	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_NONCOHERENT,1186					    component->dev, size);1187}1188 1189static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)1190{1191	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);1192	struct regmap *map;1193	unsigned int dai_id = component->id;1194 1195	if (dai_id == LPASS_DP_RX)1196		map = drvdata->hdmiif_map;1197	else1198		map = drvdata->lpaif_map;1199 1200	regcache_cache_only(map, true);1201	regcache_mark_dirty(map);1202 1203	return 0;1204}1205 1206static int lpass_platform_pcmops_resume(struct snd_soc_component *component)1207{1208	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);1209	struct regmap *map;1210	unsigned int dai_id = component->id;1211 1212	if (dai_id == LPASS_DP_RX)1213		map = drvdata->hdmiif_map;1214	else1215		map = drvdata->lpaif_map;1216 1217	regcache_cache_only(map, false);1218	return regcache_sync(map);1219}1220 1221static int lpass_platform_copy(struct snd_soc_component *component,1222			       struct snd_pcm_substream *substream, int channel,1223			       unsigned long pos, struct iov_iter *buf,1224			       unsigned long bytes)1225{1226	struct snd_pcm_runtime *rt = substream->runtime;1227	unsigned int dai_id = component->id;1228	int ret = 0;1229 1230	void __iomem *dma_buf = (void __iomem *) (rt->dma_area + pos +1231				channel * (rt->dma_bytes / rt->channels));1232 1233	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {1234		if (is_cdc_dma_port(dai_id)) {1235			ret = copy_from_iter_toio(dma_buf, buf, bytes);1236		} else {1237			if (copy_from_iter((void __force *)dma_buf, bytes, buf) != bytes)1238				ret = -EFAULT;1239		}1240	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {1241		if (is_cdc_dma_port(dai_id)) {1242			ret = copy_to_iter_fromio(buf, dma_buf, bytes);1243		} else {1244			if (copy_to_iter((void __force *)dma_buf, bytes, buf) != bytes)1245				ret = -EFAULT;1246		}1247	}1248 1249	return ret;1250}1251 1252static const struct snd_soc_component_driver lpass_component_driver = {1253	.name		= DRV_NAME,1254	.open		= lpass_platform_pcmops_open,1255	.close		= lpass_platform_pcmops_close,1256	.hw_params	= lpass_platform_pcmops_hw_params,1257	.hw_free	= lpass_platform_pcmops_hw_free,1258	.prepare	= lpass_platform_pcmops_prepare,1259	.trigger	= lpass_platform_pcmops_trigger,1260	.pointer	= lpass_platform_pcmops_pointer,1261	.mmap		= lpass_platform_pcmops_mmap,1262	.pcm_construct	= lpass_platform_pcm_new,1263	.suspend		= lpass_platform_pcmops_suspend,1264	.resume			= lpass_platform_pcmops_resume,1265	.copy		= lpass_platform_copy,1266 1267};1268 1269int asoc_qcom_lpass_platform_register(struct platform_device *pdev)1270{1271	struct lpass_data *drvdata = platform_get_drvdata(pdev);1272	const struct lpass_variant *v = drvdata->variant;1273	int ret;1274 1275	drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");1276	if (drvdata->lpaif_irq < 0)1277		return -ENODEV;1278 1279	/* ensure audio hardware is disabled */1280	ret = regmap_write(drvdata->lpaif_map,1281			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);1282	if (ret) {1283		dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);1284		return ret;1285	}1286 1287	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,1288			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,1289			"lpass-irq-lpaif", drvdata);1290	if (ret) {1291		dev_err(&pdev->dev, "irq request failed: %d\n", ret);1292		return ret;1293	}1294 1295	ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,1296						 drvdata->lpaif_map);1297	if (ret) {1298		dev_err(&pdev->dev,1299			"error initializing dmactl fields: %d\n", ret);1300		return ret;1301	}1302 1303	if (drvdata->codec_dma_enable) {1304		ret = regmap_write(drvdata->rxtx_lpaif_map,1305			LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);1306		if (ret) {1307			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);1308			return ret;1309		}1310		ret = regmap_write(drvdata->va_lpaif_map,1311			LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);1312		if (ret) {1313			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);1314			return ret;1315		}1316		drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");1317		if (drvdata->rxtxif_irq < 0)1318			return -ENODEV;1319 1320		ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,1321				lpass_platform_rxtxif_irq, 0, "lpass-irq-rxtxif", drvdata);1322		if (ret) {1323			dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);1324			return ret;1325		}1326 1327		ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,1328						 drvdata->rxtx_lpaif_map);1329		if (ret) {1330			dev_err(&pdev->dev,1331				"error initializing rxtx dmactl fields: %d\n", ret);1332			return ret;1333		}1334 1335		drvdata->vaif_irq = platform_get_irq_byname(pdev, "lpass-irq-vaif");1336		if (drvdata->vaif_irq < 0)1337			return -ENODEV;1338 1339		ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,1340				lpass_platform_vaif_irq, 0, "lpass-irq-vaif", drvdata);1341		if (ret) {1342			dev_err(&pdev->dev, "va irq request failed: %d\n", ret);1343			return ret;1344		}1345 1346		ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,1347						 drvdata->va_lpaif_map);1348		if (ret) {1349			dev_err(&pdev->dev,1350				"error initializing va dmactl fields: %d\n", ret);1351			return ret;1352		}1353	}1354 1355	if (drvdata->hdmi_port_enable) {1356		drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");1357		if (drvdata->hdmiif_irq < 0)1358			return -ENODEV;1359 1360		ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq,1361				lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata);1362		if (ret) {1363			dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret);1364			return ret;1365		}1366		ret = regmap_write(drvdata->hdmiif_map,1367				LPASS_HDMITX_APP_IRQEN_REG(v), 0);1368		if (ret) {1369			dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret);1370			return ret;1371		}1372 1373		ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev,1374							 drvdata->hdmiif_map);1375		if (ret) {1376			dev_err(&pdev->dev,1377				"error initializing hdmidmactl fields: %d\n", ret);1378			return ret;1379		}1380	}1381	return devm_snd_soc_register_component(&pdev->dev,1382			&lpass_component_driver, NULL, 0);1383}1384EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);1385 1386MODULE_DESCRIPTION("QTi LPASS Platform Driver");1387MODULE_LICENSE("GPL");1388