brintos

brintos / linux-shallow public Read only

0
0
Text · 18.6 KiB · 56ce9e4 Raw
702 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)2//3// This file is provided under a dual BSD/GPLv2 license. When using or4// redistributing this file, you may do so under either license.5//6// Copyright(c) 2021 Advanced Micro Devices, Inc.7//8// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>9//10 11/*12 * Generic Hardware interface for ACP Audio I2S controller13 */14 15#include <linux/platform_device.h>16#include <linux/module.h>17#include <linux/err.h>18#include <linux/io.h>19#include <sound/pcm_params.h>20#include <sound/soc.h>21#include <sound/soc-dai.h>22#include <linux/dma-mapping.h>23#include <linux/bitfield.h>24 25#include "amd.h"26 27#define DRV_NAME "acp_i2s_playcap"28#define	I2S_MASTER_MODE_ENABLE		129#define	LRCLK_DIV_FIELD			GENMASK(10, 2)30#define	BCLK_DIV_FIELD			GENMASK(23, 11)31#define	ACP63_LRCLK_DIV_FIELD		GENMASK(12, 2)32#define	ACP63_BCLK_DIV_FIELD		GENMASK(23, 13)33 34static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)35{36	u32 i2s_clk_reg, val;37	struct acp_chip_info *chip;38	struct device *dev;39 40	dev = adata->dev;41	chip = dev_get_platdata(dev);42	switch (dai_id) {43	case I2S_SP_INSTANCE:44		i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;45		break;46	case I2S_BT_INSTANCE:47		i2s_clk_reg = ACP_I2STDM1_MSTRCLKGEN;48		break;49	case I2S_HS_INSTANCE:50		i2s_clk_reg = ACP_I2STDM2_MSTRCLKGEN;51		break;52	default:53		i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;54		break;55	}56 57	val  = I2S_MASTER_MODE_ENABLE;58	if (adata->tdm_mode)59		val |= BIT(1);60 61	switch (chip->acp_rev) {62	case ACP63_DEV:63	case ACP70_DEV:64	case ACP71_DEV:65		val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div);66		val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div);67		break;68	default:69		val |= FIELD_PREP(LRCLK_DIV_FIELD, adata->lrclk_div);70		val |= FIELD_PREP(BCLK_DIV_FIELD, adata->bclk_div);71	}72	writel(val, adata->acp_base + i2s_clk_reg);73}74 75static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai,76			   unsigned int fmt)77{78	struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);79	int mode;80 81	mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;82	switch (mode) {83	case SND_SOC_DAIFMT_I2S:84		adata->tdm_mode = TDM_DISABLE;85		break;86	case SND_SOC_DAIFMT_DSP_A:87		adata->tdm_mode = TDM_ENABLE;88		break;89	default:90		return -EINVAL;91	}92	return 0;93}94 95static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask,96				int slots, int slot_width)97{98	struct device *dev = dai->component->dev;99	struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);100	struct acp_chip_info *chip;101	struct acp_stream *stream;102	int slot_len, no_of_slots;103 104	chip = dev_get_platdata(dev);105	switch (slot_width) {106	case SLOT_WIDTH_8:107		slot_len = 8;108		break;109	case SLOT_WIDTH_16:110		slot_len = 16;111		break;112	case SLOT_WIDTH_24:113		slot_len = 24;114		break;115	case SLOT_WIDTH_32:116		slot_len = 0;117		break;118	default:119		dev_err(dev, "Unsupported bitdepth %d\n", slot_width);120		return -EINVAL;121	}122 123	switch (chip->acp_rev) {124	case ACP3X_DEV:125	case ACP6X_DEV:126		switch (slots) {127		case 1 ... 7:128			no_of_slots = slots;129			break;130		case 8:131			no_of_slots = 0;132			break;133		default:134			dev_err(dev, "Unsupported slots %d\n", slots);135			return -EINVAL;136		}137		break;138	case ACP63_DEV:139	case ACP70_DEV:140	case ACP71_DEV:141		switch (slots) {142		case 1 ... 31:143			no_of_slots = slots;144			break;145		case 32:146			no_of_slots = 0;147			break;148		default:149			dev_err(dev, "Unsupported slots %d\n", slots);150			return -EINVAL;151		}152		break;153	default:154		dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);155		return -EINVAL;156	}157 158	slots = no_of_slots;159 160	spin_lock_irq(&adata->acp_lock);161	list_for_each_entry(stream, &adata->stream_list, list) {162		switch (chip->acp_rev) {163		case ACP3X_DEV:164		case ACP6X_DEV:165			if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)166				adata->tdm_tx_fmt[stream->dai_id - 1] =167					FRM_LEN | (slots << 15) | (slot_len << 18);168			else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)169				adata->tdm_rx_fmt[stream->dai_id - 1] =170					FRM_LEN | (slots << 15) | (slot_len << 18);171			break;172		case ACP63_DEV:173		case ACP70_DEV:174		case ACP71_DEV:175			if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)176				adata->tdm_tx_fmt[stream->dai_id - 1] =177						FRM_LEN | (slots << 13) | (slot_len << 18);178			else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)179				adata->tdm_rx_fmt[stream->dai_id - 1] =180						FRM_LEN | (slots << 13) | (slot_len << 18);181			break;182		default:183			dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);184			return -EINVAL;185		}186	}187	spin_unlock_irq(&adata->acp_lock);188	return 0;189}190 191static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,192			    struct snd_soc_dai *dai)193{194	struct device *dev = dai->component->dev;195	struct acp_dev_data *adata;196	struct acp_resource *rsrc;197	u32 val;198	u32 xfer_resolution;199	u32 reg_val, fmt_reg, tdm_fmt;200	u32 lrclk_div_val, bclk_div_val;201 202	adata = snd_soc_dai_get_drvdata(dai);203	rsrc = adata->rsrc;204 205	/* These values are as per Hardware Spec */206	switch (params_format(params)) {207	case SNDRV_PCM_FORMAT_U8:208	case SNDRV_PCM_FORMAT_S8:209		xfer_resolution = 0x0;210		break;211	case SNDRV_PCM_FORMAT_S16_LE:212		xfer_resolution = 0x02;213		break;214	case SNDRV_PCM_FORMAT_S24_LE:215		xfer_resolution = 0x04;216		break;217	case SNDRV_PCM_FORMAT_S32_LE:218		xfer_resolution = 0x05;219		break;220	default:221		return -EINVAL;222	}223 224	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {225		switch (dai->driver->id) {226		case I2S_BT_INSTANCE:227			reg_val = ACP_BTTDM_ITER;228			fmt_reg = ACP_BTTDM_TXFRMT;229			break;230		case I2S_SP_INSTANCE:231			reg_val = ACP_I2STDM_ITER;232			fmt_reg = ACP_I2STDM_TXFRMT;233			break;234		case I2S_HS_INSTANCE:235			reg_val = ACP_HSTDM_ITER;236			fmt_reg = ACP_HSTDM_TXFRMT;237			break;238		default:239			dev_err(dev, "Invalid dai id %x\n", dai->driver->id);240			return -EINVAL;241		}242		adata->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution;243	} else {244		switch (dai->driver->id) {245		case I2S_BT_INSTANCE:246			reg_val = ACP_BTTDM_IRER;247			fmt_reg = ACP_BTTDM_RXFRMT;248			break;249		case I2S_SP_INSTANCE:250			reg_val = ACP_I2STDM_IRER;251			fmt_reg = ACP_I2STDM_RXFRMT;252			break;253		case I2S_HS_INSTANCE:254			reg_val = ACP_HSTDM_IRER;255			fmt_reg = ACP_HSTDM_RXFRMT;256			break;257		default:258			dev_err(dev, "Invalid dai id %x\n", dai->driver->id);259			return -EINVAL;260		}261		adata->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution;262	}263 264	val = readl(adata->acp_base + reg_val);265	val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;266	val = val | (xfer_resolution  << 3);267	writel(val, adata->acp_base + reg_val);268 269	if (adata->tdm_mode) {270		val = readl(adata->acp_base + reg_val);271		writel(val | BIT(1), adata->acp_base + reg_val);272		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)273			tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1];274		else275			tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1];276		writel(tdm_fmt, adata->acp_base + fmt_reg);277	}278 279	if (rsrc->soc_mclk) {280		switch (params_format(params)) {281		case SNDRV_PCM_FORMAT_S16_LE:282			switch (params_rate(params)) {283			case 8000:284				bclk_div_val = 768;285				break;286			case 16000:287				bclk_div_val = 384;288				break;289			case 24000:290				bclk_div_val = 256;291				break;292			case 32000:293				bclk_div_val = 192;294				break;295			case 44100:296			case 48000:297				bclk_div_val = 128;298				break;299			case 88200:300			case 96000:301				bclk_div_val = 64;302				break;303			case 192000:304				bclk_div_val = 32;305				break;306			default:307				return -EINVAL;308			}309			lrclk_div_val = 32;310			break;311		case SNDRV_PCM_FORMAT_S32_LE:312			switch (params_rate(params)) {313			case 8000:314				bclk_div_val = 384;315				break;316			case 16000:317				bclk_div_val = 192;318				break;319			case 24000:320				bclk_div_val = 128;321				break;322			case 32000:323				bclk_div_val = 96;324				break;325			case 44100:326			case 48000:327				bclk_div_val = 64;328				break;329			case 88200:330			case 96000:331				bclk_div_val = 32;332				break;333			case 192000:334				bclk_div_val = 16;335				break;336			default:337				return -EINVAL;338			}339			lrclk_div_val = 64;340			break;341		default:342			return -EINVAL;343		}344 345		switch (params_rate(params)) {346		case 8000:347		case 16000:348		case 24000:349		case 48000:350		case 96000:351		case 192000:352			switch (params_channels(params)) {353			case 2:354				break;355			case 4:356				bclk_div_val = bclk_div_val >> 1;357				lrclk_div_val = lrclk_div_val << 1;358				break;359			case 8:360				bclk_div_val = bclk_div_val >> 2;361				lrclk_div_val = lrclk_div_val << 2;362				break;363			case 16:364				bclk_div_val = bclk_div_val >> 3;365				lrclk_div_val = lrclk_div_val << 3;366				break;367			case 32:368				bclk_div_val = bclk_div_val >> 4;369				lrclk_div_val = lrclk_div_val << 4;370				break;371			default:372				dev_err(dev, "Unsupported channels %#x\n",373					params_channels(params));374			}375			break;376		default:377			break;378		}379		adata->lrclk_div = lrclk_div_val;380		adata->bclk_div = bclk_div_val;381	}382	return 0;383}384 385static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)386{387	struct acp_stream *stream = substream->runtime->private_data;388	struct device *dev = dai->component->dev;389	struct acp_dev_data *adata = dev_get_drvdata(dev);390	struct acp_resource *rsrc = adata->rsrc;391	u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;392 393	period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);394	buf_size = frames_to_bytes(substream->runtime, substream->runtime->buffer_size);395 396	switch (cmd) {397	case SNDRV_PCM_TRIGGER_START:398	case SNDRV_PCM_TRIGGER_RESUME:399	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:400		stream->bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);401		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {402			switch (dai->driver->id) {403			case I2S_BT_INSTANCE:404				water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(adata);405				reg_val = ACP_BTTDM_ITER;406				ier_val = ACP_BTTDM_IER;407				buf_reg = ACP_BT_TX_RINGBUFSIZE(adata);408				break;409			case I2S_SP_INSTANCE:410				water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(adata);411				reg_val = ACP_I2STDM_ITER;412				ier_val = ACP_I2STDM_IER;413				buf_reg = ACP_I2S_TX_RINGBUFSIZE(adata);414				break;415			case I2S_HS_INSTANCE:416				water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;417				reg_val = ACP_HSTDM_ITER;418				ier_val = ACP_HSTDM_IER;419				buf_reg = ACP_HS_TX_RINGBUFSIZE;420				break;421			default:422				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);423				return -EINVAL;424			}425		} else {426			switch (dai->driver->id) {427			case I2S_BT_INSTANCE:428				water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(adata);429				reg_val = ACP_BTTDM_IRER;430				ier_val = ACP_BTTDM_IER;431				buf_reg = ACP_BT_RX_RINGBUFSIZE(adata);432				break;433			case I2S_SP_INSTANCE:434				water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(adata);435				reg_val = ACP_I2STDM_IRER;436				ier_val = ACP_I2STDM_IER;437				buf_reg = ACP_I2S_RX_RINGBUFSIZE(adata);438				break;439			case I2S_HS_INSTANCE:440				water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;441				reg_val = ACP_HSTDM_IRER;442				ier_val = ACP_HSTDM_IER;443				buf_reg = ACP_HS_RX_RINGBUFSIZE;444				break;445			default:446				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);447				return -EINVAL;448			}449		}450 451		writel(period_bytes, adata->acp_base + water_val);452		writel(buf_size, adata->acp_base + buf_reg);453		if (rsrc->soc_mclk)454			acp_set_i2s_clk(adata, dai->driver->id);455		val = readl(adata->acp_base + reg_val);456		val = val | BIT(0);457		writel(val, adata->acp_base + reg_val);458		writel(1, adata->acp_base + ier_val);459		return 0;460	case SNDRV_PCM_TRIGGER_STOP:461	case SNDRV_PCM_TRIGGER_SUSPEND:462	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:463		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {464			switch (dai->driver->id) {465			case I2S_BT_INSTANCE:466				reg_val = ACP_BTTDM_ITER;467				break;468			case I2S_SP_INSTANCE:469				reg_val = ACP_I2STDM_ITER;470				break;471			case I2S_HS_INSTANCE:472				reg_val = ACP_HSTDM_ITER;473				break;474			default:475				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);476				return -EINVAL;477			}478 479		} else {480			switch (dai->driver->id) {481			case I2S_BT_INSTANCE:482				reg_val = ACP_BTTDM_IRER;483				break;484			case I2S_SP_INSTANCE:485				reg_val = ACP_I2STDM_IRER;486				break;487			case I2S_HS_INSTANCE:488				reg_val = ACP_HSTDM_IRER;489				break;490			default:491				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);492				return -EINVAL;493			}494		}495		val = readl(adata->acp_base + reg_val);496		val = val & ~BIT(0);497		writel(val, adata->acp_base + reg_val);498 499		if (!(readl(adata->acp_base + ACP_BTTDM_ITER) & BIT(0)) &&500		    !(readl(adata->acp_base + ACP_BTTDM_IRER) & BIT(0)))501			writel(0, adata->acp_base + ACP_BTTDM_IER);502		if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&503		    !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))504			writel(0, adata->acp_base + ACP_I2STDM_IER);505		if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&506		    !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))507			writel(0, adata->acp_base + ACP_HSTDM_IER);508		return 0;509	default:510		return -EINVAL;511	}512 513	return 0;514}515 516static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)517{518	struct device *dev = dai->component->dev;519	struct acp_dev_data *adata = dev_get_drvdata(dev);520	struct acp_chip_info *chip;521	struct acp_resource *rsrc = adata->rsrc;522	struct acp_stream *stream = substream->runtime->private_data;523	u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;524	u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;525	unsigned int dir = substream->stream;526 527	chip = dev_get_platdata(dev);528	switch (dai->driver->id) {529	case I2S_SP_INSTANCE:530		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {531			reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata);532			acp_fifo_addr = rsrc->sram_pte_offset +533						SP_PB_FIFO_ADDR_OFFSET;534			reg_fifo_addr =	ACP_I2S_TX_FIFOADDR(adata);535			reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata);536 537			if (chip->acp_rev >= ACP70_DEV)538				phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START;539			else540				phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;541			writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata));542		} else {543			reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata);544			acp_fifo_addr = rsrc->sram_pte_offset +545						SP_CAPT_FIFO_ADDR_OFFSET;546			reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata);547			reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata);548 549			if (chip->acp_rev >= ACP70_DEV)550				phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START;551			else552				phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;553			writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata));554		}555		break;556	case I2S_BT_INSTANCE:557		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {558			reg_dma_size = ACP_BT_TX_DMA_SIZE(adata);559			acp_fifo_addr = rsrc->sram_pte_offset +560						BT_PB_FIFO_ADDR_OFFSET;561			reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata);562			reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata);563 564			if (chip->acp_rev >= ACP70_DEV)565				phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START;566			else567				phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;568			writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata));569		} else {570			reg_dma_size = ACP_BT_RX_DMA_SIZE(adata);571			acp_fifo_addr = rsrc->sram_pte_offset +572						BT_CAPT_FIFO_ADDR_OFFSET;573			reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata);574			reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata);575 576			if (chip->acp_rev >= ACP70_DEV)577				phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START;578			else579				phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;580			writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata));581		}582		break;583	case I2S_HS_INSTANCE:584		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {585			reg_dma_size = ACP_HS_TX_DMA_SIZE;586			acp_fifo_addr = rsrc->sram_pte_offset +587				HS_PB_FIFO_ADDR_OFFSET;588			reg_fifo_addr = ACP_HS_TX_FIFOADDR;589			reg_fifo_size = ACP_HS_TX_FIFOSIZE;590 591			if (chip->acp_rev >= ACP70_DEV)592				phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;593			else594				phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;595			writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);596		} else {597			reg_dma_size = ACP_HS_RX_DMA_SIZE;598			acp_fifo_addr = rsrc->sram_pte_offset +599					HS_CAPT_FIFO_ADDR_OFFSET;600			reg_fifo_addr = ACP_HS_RX_FIFOADDR;601			reg_fifo_size = ACP_HS_RX_FIFOSIZE;602 603			if (chip->acp_rev >= ACP70_DEV)604				phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;605			else606				phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;607			writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);608		}609		break;610	default:611		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);612		return -EINVAL;613	}614 615	writel(DMA_SIZE, adata->acp_base + reg_dma_size);616	writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);617	writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);618 619	ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));620	ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |621			BIT(BT_RX_THRESHOLD(rsrc->offset)) |622			BIT(I2S_TX_THRESHOLD(rsrc->offset)) |623			BIT(BT_TX_THRESHOLD(rsrc->offset)) |624			BIT(HS_RX_THRESHOLD(rsrc->offset)) |625			BIT(HS_TX_THRESHOLD(rsrc->offset));626 627	writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));628 629	return 0;630}631 632static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)633{634	struct acp_stream *stream = substream->runtime->private_data;635	struct device *dev = dai->component->dev;636	struct acp_dev_data *adata = dev_get_drvdata(dev);637	struct acp_resource *rsrc = adata->rsrc;638	unsigned int dir = substream->stream;639	unsigned int irq_bit = 0;640 641	switch (dai->driver->id) {642	case I2S_SP_INSTANCE:643		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {644			irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset));645			stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET;646			stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET;647		} else {648			irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset));649			stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET;650			stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET;651		}652		break;653	case I2S_BT_INSTANCE:654		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {655			irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset));656			stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET;657			stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET;658		} else {659			irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset));660			stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET;661			stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;662		}663		break;664	case I2S_HS_INSTANCE:665		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {666			irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));667			stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;668			stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;669		} else {670			irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));671			stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;672			stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;673		}674		break;675	default:676		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);677		return -EINVAL;678	}679 680	/* Save runtime dai configuration in stream */681	stream->id = dai->driver->id + dir;682	stream->dai_id = dai->driver->id;683	stream->irq_bit = irq_bit;684	stream->dir = substream->stream;685 686	return 0;687}688 689const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {690	.startup	= acp_i2s_startup,691	.hw_params	= acp_i2s_hwparams,692	.prepare	= acp_i2s_prepare,693	.trigger	= acp_i2s_trigger,694	.set_fmt	= acp_i2s_set_fmt,695	.set_tdm_slot	= acp_i2s_set_tdm_slot,696};697EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);698 699MODULE_DESCRIPTION("AMD ACP Audio I2S controller");700MODULE_LICENSE("Dual BSD/GPL");701MODULE_ALIAS(DRV_NAME);702