cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lpass-platform.c (40525B)


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