162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or
462306a36Sopenharmony_ci// redistributing this file, you may do so under either license.
562306a36Sopenharmony_ci//
662306a36Sopenharmony_ci// Copyright(c) 2021 Advanced Micro Devices, Inc.
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
962306a36Sopenharmony_ci//
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * Generic Hardware interface for ACP Audio I2S controller
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/err.h>
1862306a36Sopenharmony_ci#include <linux/io.h>
1962306a36Sopenharmony_ci#include <sound/pcm_params.h>
2062306a36Sopenharmony_ci#include <sound/soc.h>
2162306a36Sopenharmony_ci#include <sound/soc-dai.h>
2262306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "amd.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define DRV_NAME "acp_i2s_playcap"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
2962306a36Sopenharmony_ci			   unsigned int fmt)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
3262306a36Sopenharmony_ci	int mode;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
3562306a36Sopenharmony_ci	switch (mode) {
3662306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
3762306a36Sopenharmony_ci		adata->tdm_mode = TDM_DISABLE;
3862306a36Sopenharmony_ci		break;
3962306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A:
4062306a36Sopenharmony_ci		adata->tdm_mode = TDM_ENABLE;
4162306a36Sopenharmony_ci		break;
4262306a36Sopenharmony_ci	default:
4362306a36Sopenharmony_ci		return -EINVAL;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci	return 0;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask,
4962306a36Sopenharmony_ci				int slots, int slot_width)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct device *dev = dai->component->dev;
5262306a36Sopenharmony_ci	struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
5362306a36Sopenharmony_ci	struct acp_stream *stream;
5462306a36Sopenharmony_ci	int slot_len, no_of_slots;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	switch (slot_width) {
5762306a36Sopenharmony_ci	case SLOT_WIDTH_8:
5862306a36Sopenharmony_ci		slot_len = 8;
5962306a36Sopenharmony_ci		break;
6062306a36Sopenharmony_ci	case SLOT_WIDTH_16:
6162306a36Sopenharmony_ci		slot_len = 16;
6262306a36Sopenharmony_ci		break;
6362306a36Sopenharmony_ci	case SLOT_WIDTH_24:
6462306a36Sopenharmony_ci		slot_len = 24;
6562306a36Sopenharmony_ci		break;
6662306a36Sopenharmony_ci	case SLOT_WIDTH_32:
6762306a36Sopenharmony_ci		slot_len = 0;
6862306a36Sopenharmony_ci		break;
6962306a36Sopenharmony_ci	default:
7062306a36Sopenharmony_ci		dev_err(dev, "Unsupported bitdepth %d\n", slot_width);
7162306a36Sopenharmony_ci		return -EINVAL;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	switch (slots) {
7562306a36Sopenharmony_ci	case 1 ... 7:
7662306a36Sopenharmony_ci		no_of_slots = slots;
7762306a36Sopenharmony_ci		break;
7862306a36Sopenharmony_ci	case 8:
7962306a36Sopenharmony_ci		no_of_slots = 0;
8062306a36Sopenharmony_ci		break;
8162306a36Sopenharmony_ci	default:
8262306a36Sopenharmony_ci		dev_err(dev, "Unsupported slots %d\n", slots);
8362306a36Sopenharmony_ci		return -EINVAL;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	slots = no_of_slots;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	spin_lock_irq(&adata->acp_lock);
8962306a36Sopenharmony_ci	list_for_each_entry(stream, &adata->stream_list, list) {
9062306a36Sopenharmony_ci		if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
9162306a36Sopenharmony_ci			adata->tdm_tx_fmt[stream->dai_id - 1] =
9262306a36Sopenharmony_ci					FRM_LEN | (slots << 15) | (slot_len << 18);
9362306a36Sopenharmony_ci		else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
9462306a36Sopenharmony_ci			adata->tdm_rx_fmt[stream->dai_id - 1] =
9562306a36Sopenharmony_ci					FRM_LEN | (slots << 15) | (slot_len << 18);
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	spin_unlock_irq(&adata->acp_lock);
9862306a36Sopenharmony_ci	return 0;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
10262306a36Sopenharmony_ci			    struct snd_soc_dai *dai)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct device *dev = dai->component->dev;
10562306a36Sopenharmony_ci	struct acp_dev_data *adata;
10662306a36Sopenharmony_ci	struct acp_resource *rsrc;
10762306a36Sopenharmony_ci	u32 val;
10862306a36Sopenharmony_ci	u32 xfer_resolution;
10962306a36Sopenharmony_ci	u32 reg_val, fmt_reg, tdm_fmt;
11062306a36Sopenharmony_ci	u32 lrclk_div_val, bclk_div_val;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	adata = snd_soc_dai_get_drvdata(dai);
11362306a36Sopenharmony_ci	rsrc = adata->rsrc;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* These values are as per Hardware Spec */
11662306a36Sopenharmony_ci	switch (params_format(params)) {
11762306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_U8:
11862306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S8:
11962306a36Sopenharmony_ci		xfer_resolution = 0x0;
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
12262306a36Sopenharmony_ci		xfer_resolution = 0x02;
12362306a36Sopenharmony_ci		break;
12462306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
12562306a36Sopenharmony_ci		xfer_resolution = 0x04;
12662306a36Sopenharmony_ci		break;
12762306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S32_LE:
12862306a36Sopenharmony_ci		xfer_resolution = 0x05;
12962306a36Sopenharmony_ci		break;
13062306a36Sopenharmony_ci	default:
13162306a36Sopenharmony_ci		return -EINVAL;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
13562306a36Sopenharmony_ci		switch (dai->driver->id) {
13662306a36Sopenharmony_ci		case I2S_BT_INSTANCE:
13762306a36Sopenharmony_ci			reg_val = ACP_BTTDM_ITER;
13862306a36Sopenharmony_ci			fmt_reg = ACP_BTTDM_TXFRMT;
13962306a36Sopenharmony_ci			break;
14062306a36Sopenharmony_ci		case I2S_SP_INSTANCE:
14162306a36Sopenharmony_ci			reg_val = ACP_I2STDM_ITER;
14262306a36Sopenharmony_ci			fmt_reg = ACP_I2STDM_TXFRMT;
14362306a36Sopenharmony_ci			break;
14462306a36Sopenharmony_ci		case I2S_HS_INSTANCE:
14562306a36Sopenharmony_ci			reg_val = ACP_HSTDM_ITER;
14662306a36Sopenharmony_ci			fmt_reg = ACP_HSTDM_TXFRMT;
14762306a36Sopenharmony_ci			break;
14862306a36Sopenharmony_ci		default:
14962306a36Sopenharmony_ci			dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
15062306a36Sopenharmony_ci			return -EINVAL;
15162306a36Sopenharmony_ci		}
15262306a36Sopenharmony_ci		adata->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution;
15362306a36Sopenharmony_ci	} else {
15462306a36Sopenharmony_ci		switch (dai->driver->id) {
15562306a36Sopenharmony_ci		case I2S_BT_INSTANCE:
15662306a36Sopenharmony_ci			reg_val = ACP_BTTDM_IRER;
15762306a36Sopenharmony_ci			fmt_reg = ACP_BTTDM_RXFRMT;
15862306a36Sopenharmony_ci			break;
15962306a36Sopenharmony_ci		case I2S_SP_INSTANCE:
16062306a36Sopenharmony_ci			reg_val = ACP_I2STDM_IRER;
16162306a36Sopenharmony_ci			fmt_reg = ACP_I2STDM_RXFRMT;
16262306a36Sopenharmony_ci			break;
16362306a36Sopenharmony_ci		case I2S_HS_INSTANCE:
16462306a36Sopenharmony_ci			reg_val = ACP_HSTDM_IRER;
16562306a36Sopenharmony_ci			fmt_reg = ACP_HSTDM_RXFRMT;
16662306a36Sopenharmony_ci			break;
16762306a36Sopenharmony_ci		default:
16862306a36Sopenharmony_ci			dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
16962306a36Sopenharmony_ci			return -EINVAL;
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci		adata->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	val = readl(adata->acp_base + reg_val);
17562306a36Sopenharmony_ci	val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
17662306a36Sopenharmony_ci	val = val | (xfer_resolution  << 3);
17762306a36Sopenharmony_ci	writel(val, adata->acp_base + reg_val);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (adata->tdm_mode) {
18062306a36Sopenharmony_ci		val = readl(adata->acp_base + reg_val);
18162306a36Sopenharmony_ci		writel(val | BIT(1), adata->acp_base + reg_val);
18262306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
18362306a36Sopenharmony_ci			tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1];
18462306a36Sopenharmony_ci		else
18562306a36Sopenharmony_ci			tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1];
18662306a36Sopenharmony_ci		writel(tdm_fmt, adata->acp_base + fmt_reg);
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (rsrc->soc_mclk) {
19062306a36Sopenharmony_ci		switch (params_format(params)) {
19162306a36Sopenharmony_ci		case SNDRV_PCM_FORMAT_S16_LE:
19262306a36Sopenharmony_ci			switch (params_rate(params)) {
19362306a36Sopenharmony_ci			case 8000:
19462306a36Sopenharmony_ci				bclk_div_val = 768;
19562306a36Sopenharmony_ci				break;
19662306a36Sopenharmony_ci			case 16000:
19762306a36Sopenharmony_ci				bclk_div_val = 384;
19862306a36Sopenharmony_ci				break;
19962306a36Sopenharmony_ci			case 24000:
20062306a36Sopenharmony_ci				bclk_div_val = 256;
20162306a36Sopenharmony_ci				break;
20262306a36Sopenharmony_ci			case 32000:
20362306a36Sopenharmony_ci				bclk_div_val = 192;
20462306a36Sopenharmony_ci				break;
20562306a36Sopenharmony_ci			case 44100:
20662306a36Sopenharmony_ci			case 48000:
20762306a36Sopenharmony_ci				bclk_div_val = 128;
20862306a36Sopenharmony_ci				break;
20962306a36Sopenharmony_ci			case 88200:
21062306a36Sopenharmony_ci			case 96000:
21162306a36Sopenharmony_ci				bclk_div_val = 64;
21262306a36Sopenharmony_ci				break;
21362306a36Sopenharmony_ci			case 192000:
21462306a36Sopenharmony_ci				bclk_div_val = 32;
21562306a36Sopenharmony_ci				break;
21662306a36Sopenharmony_ci			default:
21762306a36Sopenharmony_ci				return -EINVAL;
21862306a36Sopenharmony_ci			}
21962306a36Sopenharmony_ci			lrclk_div_val = 32;
22062306a36Sopenharmony_ci			break;
22162306a36Sopenharmony_ci		case SNDRV_PCM_FORMAT_S32_LE:
22262306a36Sopenharmony_ci			switch (params_rate(params)) {
22362306a36Sopenharmony_ci			case 8000:
22462306a36Sopenharmony_ci				bclk_div_val = 384;
22562306a36Sopenharmony_ci				break;
22662306a36Sopenharmony_ci			case 16000:
22762306a36Sopenharmony_ci				bclk_div_val = 192;
22862306a36Sopenharmony_ci				break;
22962306a36Sopenharmony_ci			case 24000:
23062306a36Sopenharmony_ci				bclk_div_val = 128;
23162306a36Sopenharmony_ci				break;
23262306a36Sopenharmony_ci			case 32000:
23362306a36Sopenharmony_ci				bclk_div_val = 96;
23462306a36Sopenharmony_ci				break;
23562306a36Sopenharmony_ci			case 44100:
23662306a36Sopenharmony_ci			case 48000:
23762306a36Sopenharmony_ci				bclk_div_val = 64;
23862306a36Sopenharmony_ci				break;
23962306a36Sopenharmony_ci			case 88200:
24062306a36Sopenharmony_ci			case 96000:
24162306a36Sopenharmony_ci				bclk_div_val = 32;
24262306a36Sopenharmony_ci				break;
24362306a36Sopenharmony_ci			case 192000:
24462306a36Sopenharmony_ci				bclk_div_val = 16;
24562306a36Sopenharmony_ci				break;
24662306a36Sopenharmony_ci			default:
24762306a36Sopenharmony_ci				return -EINVAL;
24862306a36Sopenharmony_ci			}
24962306a36Sopenharmony_ci			lrclk_div_val = 64;
25062306a36Sopenharmony_ci			break;
25162306a36Sopenharmony_ci		default:
25262306a36Sopenharmony_ci			return -EINVAL;
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci		adata->lrclk_div = lrclk_div_val;
25562306a36Sopenharmony_ci		adata->bclk_div = bclk_div_val;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci	return 0;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct acp_stream *stream = substream->runtime->private_data;
26362306a36Sopenharmony_ci	struct device *dev = dai->component->dev;
26462306a36Sopenharmony_ci	struct acp_dev_data *adata = dev_get_drvdata(dev);
26562306a36Sopenharmony_ci	struct acp_resource *rsrc = adata->rsrc;
26662306a36Sopenharmony_ci	u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
26962306a36Sopenharmony_ci	buf_size = frames_to_bytes(substream->runtime, substream->runtime->buffer_size);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	switch (cmd) {
27262306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
27362306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
27462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
27562306a36Sopenharmony_ci		stream->bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);
27662306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
27762306a36Sopenharmony_ci			switch (dai->driver->id) {
27862306a36Sopenharmony_ci			case I2S_BT_INSTANCE:
27962306a36Sopenharmony_ci				water_val = ACP_BT_TX_INTR_WATERMARK_SIZE;
28062306a36Sopenharmony_ci				reg_val = ACP_BTTDM_ITER;
28162306a36Sopenharmony_ci				ier_val = ACP_BTTDM_IER;
28262306a36Sopenharmony_ci				buf_reg = ACP_BT_TX_RINGBUFSIZE;
28362306a36Sopenharmony_ci				break;
28462306a36Sopenharmony_ci			case I2S_SP_INSTANCE:
28562306a36Sopenharmony_ci				water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE;
28662306a36Sopenharmony_ci				reg_val = ACP_I2STDM_ITER;
28762306a36Sopenharmony_ci				ier_val = ACP_I2STDM_IER;
28862306a36Sopenharmony_ci				buf_reg = ACP_I2S_TX_RINGBUFSIZE;
28962306a36Sopenharmony_ci				break;
29062306a36Sopenharmony_ci			case I2S_HS_INSTANCE:
29162306a36Sopenharmony_ci				water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
29262306a36Sopenharmony_ci				reg_val = ACP_HSTDM_ITER;
29362306a36Sopenharmony_ci				ier_val = ACP_HSTDM_IER;
29462306a36Sopenharmony_ci				buf_reg = ACP_HS_TX_RINGBUFSIZE;
29562306a36Sopenharmony_ci				break;
29662306a36Sopenharmony_ci			default:
29762306a36Sopenharmony_ci				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
29862306a36Sopenharmony_ci				return -EINVAL;
29962306a36Sopenharmony_ci			}
30062306a36Sopenharmony_ci		} else {
30162306a36Sopenharmony_ci			switch (dai->driver->id) {
30262306a36Sopenharmony_ci			case I2S_BT_INSTANCE:
30362306a36Sopenharmony_ci				water_val = ACP_BT_RX_INTR_WATERMARK_SIZE;
30462306a36Sopenharmony_ci				reg_val = ACP_BTTDM_IRER;
30562306a36Sopenharmony_ci				ier_val = ACP_BTTDM_IER;
30662306a36Sopenharmony_ci				buf_reg = ACP_BT_RX_RINGBUFSIZE;
30762306a36Sopenharmony_ci				break;
30862306a36Sopenharmony_ci			case I2S_SP_INSTANCE:
30962306a36Sopenharmony_ci				water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE;
31062306a36Sopenharmony_ci				reg_val = ACP_I2STDM_IRER;
31162306a36Sopenharmony_ci				ier_val = ACP_I2STDM_IER;
31262306a36Sopenharmony_ci				buf_reg = ACP_I2S_RX_RINGBUFSIZE;
31362306a36Sopenharmony_ci				break;
31462306a36Sopenharmony_ci			case I2S_HS_INSTANCE:
31562306a36Sopenharmony_ci				water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
31662306a36Sopenharmony_ci				reg_val = ACP_HSTDM_IRER;
31762306a36Sopenharmony_ci				ier_val = ACP_HSTDM_IER;
31862306a36Sopenharmony_ci				buf_reg = ACP_HS_RX_RINGBUFSIZE;
31962306a36Sopenharmony_ci				break;
32062306a36Sopenharmony_ci			default:
32162306a36Sopenharmony_ci				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
32262306a36Sopenharmony_ci				return -EINVAL;
32362306a36Sopenharmony_ci			}
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci		writel(period_bytes, adata->acp_base + water_val);
32662306a36Sopenharmony_ci		writel(buf_size, adata->acp_base + buf_reg);
32762306a36Sopenharmony_ci		val = readl(adata->acp_base + reg_val);
32862306a36Sopenharmony_ci		val = val | BIT(0);
32962306a36Sopenharmony_ci		writel(val, adata->acp_base + reg_val);
33062306a36Sopenharmony_ci		writel(1, adata->acp_base + ier_val);
33162306a36Sopenharmony_ci		if (rsrc->soc_mclk)
33262306a36Sopenharmony_ci			acp_set_i2s_clk(adata, dai->driver->id);
33362306a36Sopenharmony_ci		return 0;
33462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
33562306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
33662306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
33762306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
33862306a36Sopenharmony_ci			switch (dai->driver->id) {
33962306a36Sopenharmony_ci			case I2S_BT_INSTANCE:
34062306a36Sopenharmony_ci				reg_val = ACP_BTTDM_ITER;
34162306a36Sopenharmony_ci				break;
34262306a36Sopenharmony_ci			case I2S_SP_INSTANCE:
34362306a36Sopenharmony_ci				reg_val = ACP_I2STDM_ITER;
34462306a36Sopenharmony_ci				break;
34562306a36Sopenharmony_ci			case I2S_HS_INSTANCE:
34662306a36Sopenharmony_ci				reg_val = ACP_HSTDM_ITER;
34762306a36Sopenharmony_ci				break;
34862306a36Sopenharmony_ci			default:
34962306a36Sopenharmony_ci				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
35062306a36Sopenharmony_ci				return -EINVAL;
35162306a36Sopenharmony_ci			}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		} else {
35462306a36Sopenharmony_ci			switch (dai->driver->id) {
35562306a36Sopenharmony_ci			case I2S_BT_INSTANCE:
35662306a36Sopenharmony_ci				reg_val = ACP_BTTDM_IRER;
35762306a36Sopenharmony_ci				break;
35862306a36Sopenharmony_ci			case I2S_SP_INSTANCE:
35962306a36Sopenharmony_ci				reg_val = ACP_I2STDM_IRER;
36062306a36Sopenharmony_ci				break;
36162306a36Sopenharmony_ci			case I2S_HS_INSTANCE:
36262306a36Sopenharmony_ci				reg_val = ACP_HSTDM_IRER;
36362306a36Sopenharmony_ci				break;
36462306a36Sopenharmony_ci			default:
36562306a36Sopenharmony_ci				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
36662306a36Sopenharmony_ci				return -EINVAL;
36762306a36Sopenharmony_ci			}
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci		val = readl(adata->acp_base + reg_val);
37062306a36Sopenharmony_ci		val = val & ~BIT(0);
37162306a36Sopenharmony_ci		writel(val, adata->acp_base + reg_val);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		if (!(readl(adata->acp_base + ACP_BTTDM_ITER) & BIT(0)) &&
37462306a36Sopenharmony_ci		    !(readl(adata->acp_base + ACP_BTTDM_IRER) & BIT(0)))
37562306a36Sopenharmony_ci			writel(0, adata->acp_base + ACP_BTTDM_IER);
37662306a36Sopenharmony_ci		if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
37762306a36Sopenharmony_ci		    !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
37862306a36Sopenharmony_ci			writel(0, adata->acp_base + ACP_I2STDM_IER);
37962306a36Sopenharmony_ci		if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&
38062306a36Sopenharmony_ci		    !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))
38162306a36Sopenharmony_ci			writel(0, adata->acp_base + ACP_HSTDM_IER);
38262306a36Sopenharmony_ci		return 0;
38362306a36Sopenharmony_ci	default:
38462306a36Sopenharmony_ci		return -EINVAL;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return 0;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct device *dev = dai->component->dev;
39362306a36Sopenharmony_ci	struct acp_dev_data *adata = dev_get_drvdata(dev);
39462306a36Sopenharmony_ci	struct acp_resource *rsrc = adata->rsrc;
39562306a36Sopenharmony_ci	struct acp_stream *stream = substream->runtime->private_data;
39662306a36Sopenharmony_ci	u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;
39762306a36Sopenharmony_ci	u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;
39862306a36Sopenharmony_ci	unsigned int dir = substream->stream;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	switch (dai->driver->id) {
40162306a36Sopenharmony_ci	case I2S_SP_INSTANCE:
40262306a36Sopenharmony_ci		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
40362306a36Sopenharmony_ci			reg_dma_size = ACP_I2S_TX_DMA_SIZE;
40462306a36Sopenharmony_ci			acp_fifo_addr = rsrc->sram_pte_offset +
40562306a36Sopenharmony_ci						SP_PB_FIFO_ADDR_OFFSET;
40662306a36Sopenharmony_ci			reg_fifo_addr =	ACP_I2S_TX_FIFOADDR;
40762306a36Sopenharmony_ci			reg_fifo_size = ACP_I2S_TX_FIFOSIZE;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci			phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
41062306a36Sopenharmony_ci			writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
41162306a36Sopenharmony_ci		} else {
41262306a36Sopenharmony_ci			reg_dma_size = ACP_I2S_RX_DMA_SIZE;
41362306a36Sopenharmony_ci			acp_fifo_addr = rsrc->sram_pte_offset +
41462306a36Sopenharmony_ci						SP_CAPT_FIFO_ADDR_OFFSET;
41562306a36Sopenharmony_ci			reg_fifo_addr = ACP_I2S_RX_FIFOADDR;
41662306a36Sopenharmony_ci			reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
41762306a36Sopenharmony_ci			phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
41862306a36Sopenharmony_ci			writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR);
41962306a36Sopenharmony_ci		}
42062306a36Sopenharmony_ci		break;
42162306a36Sopenharmony_ci	case I2S_BT_INSTANCE:
42262306a36Sopenharmony_ci		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
42362306a36Sopenharmony_ci			reg_dma_size = ACP_BT_TX_DMA_SIZE;
42462306a36Sopenharmony_ci			acp_fifo_addr = rsrc->sram_pte_offset +
42562306a36Sopenharmony_ci						BT_PB_FIFO_ADDR_OFFSET;
42662306a36Sopenharmony_ci			reg_fifo_addr = ACP_BT_TX_FIFOADDR;
42762306a36Sopenharmony_ci			reg_fifo_size = ACP_BT_TX_FIFOSIZE;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci			phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
43062306a36Sopenharmony_ci			writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
43162306a36Sopenharmony_ci		} else {
43262306a36Sopenharmony_ci			reg_dma_size = ACP_BT_RX_DMA_SIZE;
43362306a36Sopenharmony_ci			acp_fifo_addr = rsrc->sram_pte_offset +
43462306a36Sopenharmony_ci						BT_CAPT_FIFO_ADDR_OFFSET;
43562306a36Sopenharmony_ci			reg_fifo_addr = ACP_BT_RX_FIFOADDR;
43662306a36Sopenharmony_ci			reg_fifo_size = ACP_BT_RX_FIFOSIZE;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci			phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
43962306a36Sopenharmony_ci			writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
44062306a36Sopenharmony_ci		}
44162306a36Sopenharmony_ci		break;
44262306a36Sopenharmony_ci	case I2S_HS_INSTANCE:
44362306a36Sopenharmony_ci		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
44462306a36Sopenharmony_ci			reg_dma_size = ACP_HS_TX_DMA_SIZE;
44562306a36Sopenharmony_ci			acp_fifo_addr = rsrc->sram_pte_offset +
44662306a36Sopenharmony_ci				HS_PB_FIFO_ADDR_OFFSET;
44762306a36Sopenharmony_ci			reg_fifo_addr = ACP_HS_TX_FIFOADDR;
44862306a36Sopenharmony_ci			reg_fifo_size = ACP_HS_TX_FIFOSIZE;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci			phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
45162306a36Sopenharmony_ci			writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
45262306a36Sopenharmony_ci		} else {
45362306a36Sopenharmony_ci			reg_dma_size = ACP_HS_RX_DMA_SIZE;
45462306a36Sopenharmony_ci			acp_fifo_addr = rsrc->sram_pte_offset +
45562306a36Sopenharmony_ci					HS_CAPT_FIFO_ADDR_OFFSET;
45662306a36Sopenharmony_ci			reg_fifo_addr = ACP_HS_RX_FIFOADDR;
45762306a36Sopenharmony_ci			reg_fifo_size = ACP_HS_RX_FIFOSIZE;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci			phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
46062306a36Sopenharmony_ci			writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci		break;
46362306a36Sopenharmony_ci	default:
46462306a36Sopenharmony_ci		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
46562306a36Sopenharmony_ci		return -EINVAL;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	writel(DMA_SIZE, adata->acp_base + reg_dma_size);
46962306a36Sopenharmony_ci	writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
47062306a36Sopenharmony_ci	writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
47362306a36Sopenharmony_ci	ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
47462306a36Sopenharmony_ci			BIT(BT_RX_THRESHOLD(rsrc->offset)) |
47562306a36Sopenharmony_ci			BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
47662306a36Sopenharmony_ci			BIT(BT_TX_THRESHOLD(rsrc->offset)) |
47762306a36Sopenharmony_ci			BIT(HS_RX_THRESHOLD(rsrc->offset)) |
47862306a36Sopenharmony_ci			BIT(HS_TX_THRESHOLD(rsrc->offset));
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	return 0;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct acp_stream *stream = substream->runtime->private_data;
48862306a36Sopenharmony_ci	struct device *dev = dai->component->dev;
48962306a36Sopenharmony_ci	struct acp_dev_data *adata = dev_get_drvdata(dev);
49062306a36Sopenharmony_ci	struct acp_resource *rsrc = adata->rsrc;
49162306a36Sopenharmony_ci	unsigned int dir = substream->stream;
49262306a36Sopenharmony_ci	unsigned int irq_bit = 0;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	switch (dai->driver->id) {
49562306a36Sopenharmony_ci	case I2S_SP_INSTANCE:
49662306a36Sopenharmony_ci		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
49762306a36Sopenharmony_ci			irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset));
49862306a36Sopenharmony_ci			stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET;
49962306a36Sopenharmony_ci			stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET;
50062306a36Sopenharmony_ci		} else {
50162306a36Sopenharmony_ci			irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset));
50262306a36Sopenharmony_ci			stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET;
50362306a36Sopenharmony_ci			stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET;
50462306a36Sopenharmony_ci		}
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci	case I2S_BT_INSTANCE:
50762306a36Sopenharmony_ci		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
50862306a36Sopenharmony_ci			irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset));
50962306a36Sopenharmony_ci			stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET;
51062306a36Sopenharmony_ci			stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET;
51162306a36Sopenharmony_ci		} else {
51262306a36Sopenharmony_ci			irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset));
51362306a36Sopenharmony_ci			stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET;
51462306a36Sopenharmony_ci			stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
51562306a36Sopenharmony_ci		}
51662306a36Sopenharmony_ci		break;
51762306a36Sopenharmony_ci	case I2S_HS_INSTANCE:
51862306a36Sopenharmony_ci		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
51962306a36Sopenharmony_ci			irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));
52062306a36Sopenharmony_ci			stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;
52162306a36Sopenharmony_ci			stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;
52262306a36Sopenharmony_ci		} else {
52362306a36Sopenharmony_ci			irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));
52462306a36Sopenharmony_ci			stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;
52562306a36Sopenharmony_ci			stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;
52662306a36Sopenharmony_ci		}
52762306a36Sopenharmony_ci		break;
52862306a36Sopenharmony_ci	default:
52962306a36Sopenharmony_ci		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
53062306a36Sopenharmony_ci		return -EINVAL;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* Save runtime dai configuration in stream */
53462306a36Sopenharmony_ci	stream->id = dai->driver->id + dir;
53562306a36Sopenharmony_ci	stream->dai_id = dai->driver->id;
53662306a36Sopenharmony_ci	stream->irq_bit = irq_bit;
53762306a36Sopenharmony_ci	stream->dir = substream->stream;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic int acp_i2s_probe(struct snd_soc_dai *dai)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct device *dev = dai->component->dev;
54562306a36Sopenharmony_ci	struct acp_dev_data *adata = dev_get_drvdata(dev);
54662306a36Sopenharmony_ci	struct acp_resource *rsrc = adata->rsrc;
54762306a36Sopenharmony_ci	unsigned int val;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (!adata->acp_base) {
55062306a36Sopenharmony_ci		dev_err(dev, "I2S base is NULL\n");
55162306a36Sopenharmony_ci		return -EINVAL;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	val = readl(adata->acp_base + rsrc->i2s_pin_cfg_offset);
55562306a36Sopenharmony_ci	if (val != rsrc->i2s_mode) {
55662306a36Sopenharmony_ci		dev_err(dev, "I2S Mode not supported val %x\n", val);
55762306a36Sopenharmony_ci		return -EINVAL;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	return 0;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ciconst struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
56462306a36Sopenharmony_ci	.probe		= acp_i2s_probe,
56562306a36Sopenharmony_ci	.startup	= acp_i2s_startup,
56662306a36Sopenharmony_ci	.hw_params	= acp_i2s_hwparams,
56762306a36Sopenharmony_ci	.prepare	= acp_i2s_prepare,
56862306a36Sopenharmony_ci	.trigger	= acp_i2s_trigger,
56962306a36Sopenharmony_ci	.set_fmt	= acp_i2s_set_fmt,
57062306a36Sopenharmony_ci	.set_tdm_slot	= acp_i2s_set_tdm_slot,
57162306a36Sopenharmony_ci};
57262306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
57562306a36Sopenharmony_ciMODULE_ALIAS(DRV_NAME);
576