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