Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/sound/soc/amd/acp/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 18 kB image not shown  

Quelle  acp-i2s.c   Sprache: C

 
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2021 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
//

/*
 * Generic Hardware interface for ACP Audio I2S controller
 */


#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include <linux/dma-mapping.h>
#include <linux/bitfield.h>

#include "amd.h"

#define DRV_NAME "acp_i2s_playcap"
#define I2S_MASTER_MODE_ENABLE  1
#define LRCLK_DIV_FIELD   GENMASK(10, 2)
#define BCLK_DIV_FIELD   GENMASK(23, 11)
#define ACP63_LRCLK_DIV_FIELD  GENMASK(12, 2)
#define ACP63_BCLK_DIV_FIELD  GENMASK(23, 13)

static inline void acp_set_i2s_clk(struct acp_chip_info *chip, int dai_id)
{
 u32 i2s_clk_reg, val;

 switch (dai_id) {
 case I2S_SP_INSTANCE:
  i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;
  break;
 case I2S_BT_INSTANCE:
  i2s_clk_reg = ACP_I2STDM1_MSTRCLKGEN;
  break;
 case I2S_HS_INSTANCE:
  i2s_clk_reg = ACP_I2STDM2_MSTRCLKGEN;
  break;
 default:
  i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;
  break;
 }

 val  = I2S_MASTER_MODE_ENABLE;
 if (chip->tdm_mode)
  val |= BIT(1);

 switch (chip->acp_rev) {
 case ACP63_PCI_ID:
 case ACP70_PCI_ID:
 case ACP71_PCI_ID:
 case ACP72_PCI_ID:
  val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, chip->lrclk_div);
  val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, chip->bclk_div);
  break;
 default:
  val |= FIELD_PREP(LRCLK_DIV_FIELD, chip->lrclk_div);
  val |= FIELD_PREP(BCLK_DIV_FIELD, chip->bclk_div);
 }
 writel(val, chip->base + i2s_clk_reg);
}

static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
      unsigned int fmt)
{
 struct device *dev = cpu_dai->component->dev;
 struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
 int mode;

 mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 switch (mode) {
 case SND_SOC_DAIFMT_I2S:
  chip->tdm_mode = TDM_DISABLE;
  break;
 case SND_SOC_DAIFMT_DSP_A:
  chip->tdm_mode = TDM_ENABLE;
  break;
 default:
  return -EINVAL;
 }
 return 0;
}

static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask,
    int slots, int slot_width)
{
 struct device *dev = dai->component->dev;
 struct acp_chip_info *chip;
 struct acp_stream *stream;
 int slot_len, no_of_slots;

 chip = dev_get_drvdata(dev->parent);
 switch (slot_width) {
 case SLOT_WIDTH_8:
  slot_len = 8;
  break;
 case SLOT_WIDTH_16:
  slot_len = 16;
  break;
 case SLOT_WIDTH_24:
  slot_len = 24;
  break;
 case SLOT_WIDTH_32:
  slot_len = 0;
  break;
 default:
  dev_err(dev, "Unsupported bitdepth %d\n", slot_width);
  return -EINVAL;
 }

 switch (chip->acp_rev) {
 case ACP_RN_PCI_ID:
 case ACP_RMB_PCI_ID:
  switch (slots) {
  case 1 ... 7:
   no_of_slots = slots;
   break;
  case 8:
   no_of_slots = 0;
   break;
  default:
   dev_err(dev, "Unsupported slots %d\n", slots);
   return -EINVAL;
  }
  break;
 case ACP63_PCI_ID:
 case ACP70_PCI_ID:
 case ACP71_PCI_ID:
 case ACP72_PCI_ID:
  switch (slots) {
  case 1 ... 31:
   no_of_slots = slots;
   break;
  case 32:
   no_of_slots = 0;
   break;
  default:
   dev_err(dev, "Unsupported slots %d\n", slots);
   return -EINVAL;
  }
  break;
 default:
  dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);
  return -EINVAL;
 }

 slots = no_of_slots;

 spin_lock_irq(&chip->acp_lock);
 list_for_each_entry(stream, &chip->stream_list, list) {
  switch (chip->acp_rev) {
  case ACP_RN_PCI_ID:
  case ACP_RMB_PCI_ID:
   if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
    chip->tdm_tx_fmt[stream->dai_id - 1] =
     FRM_LEN | (slots << 15) | (slot_len << 18);
   else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
    chip->tdm_rx_fmt[stream->dai_id - 1] =
     FRM_LEN | (slots << 15) | (slot_len << 18);
   break;
  case ACP63_PCI_ID:
  case ACP70_PCI_ID:
  case ACP71_PCI_ID:
  case ACP72_PCI_ID:
   if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
    chip->tdm_tx_fmt[stream->dai_id - 1] =
      FRM_LEN | (slots << 13) | (slot_len << 18);
   else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
    chip->tdm_rx_fmt[stream->dai_id - 1] =
      FRM_LEN | (slots << 13) | (slot_len << 18);
   break;
  default:
   dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);
   spin_unlock_irq(&chip->acp_lock);
   return -EINVAL;
  }
 }
 spin_unlock_irq(&chip->acp_lock);
 return 0;
}

static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
       struct snd_soc_dai *dai)
{
 struct device *dev = dai->component->dev;
 struct acp_chip_info *chip;
 struct acp_resource *rsrc;
 u32 val;
 u32 xfer_resolution;
 u32 reg_val, fmt_reg, tdm_fmt;
 u32 lrclk_div_val, bclk_div_val;

 chip = dev_get_drvdata(dev->parent);
 rsrc = chip->rsrc;

 /* These values are as per Hardware Spec */
 switch (params_format(params)) {
 case SNDRV_PCM_FORMAT_U8:
 case SNDRV_PCM_FORMAT_S8:
  xfer_resolution = 0x0;
  break;
 case SNDRV_PCM_FORMAT_S16_LE:
  xfer_resolution = 0x02;
  break;
 case SNDRV_PCM_FORMAT_S24_LE:
  xfer_resolution = 0x04;
  break;
 case SNDRV_PCM_FORMAT_S32_LE:
  xfer_resolution = 0x05;
  break;
 default:
  return -EINVAL;
 }

 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  switch (dai->driver->id) {
  case I2S_BT_INSTANCE:
   reg_val = ACP_BTTDM_ITER;
   fmt_reg = ACP_BTTDM_TXFRMT;
   break;
  case I2S_SP_INSTANCE:
   reg_val = ACP_I2STDM_ITER;
   fmt_reg = ACP_I2STDM_TXFRMT;
   break;
  case I2S_HS_INSTANCE:
   reg_val = ACP_HSTDM_ITER;
   fmt_reg = ACP_HSTDM_TXFRMT;
   break;
  default:
   dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
   return -EINVAL;
  }
  chip->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution;
 } else {
  switch (dai->driver->id) {
  case I2S_BT_INSTANCE:
   reg_val = ACP_BTTDM_IRER;
   fmt_reg = ACP_BTTDM_RXFRMT;
   break;
  case I2S_SP_INSTANCE:
   reg_val = ACP_I2STDM_IRER;
   fmt_reg = ACP_I2STDM_RXFRMT;
   break;
  case I2S_HS_INSTANCE:
   reg_val = ACP_HSTDM_IRER;
   fmt_reg = ACP_HSTDM_RXFRMT;
   break;
  default:
   dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
   return -EINVAL;
  }
  chip->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution;
 }

 val = readl(chip->base + reg_val);
 val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
 val = val | (xfer_resolution  << 3);
 writel(val, chip->base + reg_val);

 if (chip->tdm_mode) {
  val = readl(chip->base + reg_val);
  writel(val | BIT(1), chip->base + reg_val);
  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
   tdm_fmt = chip->tdm_tx_fmt[dai->driver->id - 1];
  else
   tdm_fmt = chip->tdm_rx_fmt[dai->driver->id - 1];
  writel(tdm_fmt, chip->base + fmt_reg);
 }

 if (rsrc->soc_mclk) {
  switch (params_format(params)) {
  case SNDRV_PCM_FORMAT_S16_LE:
   switch (params_rate(params)) {
   case 8000:
    bclk_div_val = 768;
    break;
   case 16000:
    bclk_div_val = 384;
    break;
   case 24000:
    bclk_div_val = 256;
    break;
   case 32000:
    bclk_div_val = 192;
    break;
   case 44100:
   case 48000:
    bclk_div_val = 128;
    break;
   case 88200:
   case 96000:
    bclk_div_val = 64;
    break;
   case 192000:
    bclk_div_val = 32;
    break;
   default:
    return -EINVAL;
   }
   lrclk_div_val = 32;
   break;
  case SNDRV_PCM_FORMAT_S32_LE:
   switch (params_rate(params)) {
   case 8000:
    bclk_div_val = 384;
    break;
   case 16000:
    bclk_div_val = 192;
    break;
   case 24000:
    bclk_div_val = 128;
    break;
   case 32000:
    bclk_div_val = 96;
    break;
   case 44100:
   case 48000:
    bclk_div_val = 64;
    break;
   case 88200:
   case 96000:
    bclk_div_val = 32;
    break;
   case 192000:
    bclk_div_val = 16;
    break;
   default:
    return -EINVAL;
   }
   lrclk_div_val = 64;
   break;
  default:
   return -EINVAL;
  }

  switch (params_rate(params)) {
  case 8000:
  case 16000:
  case 24000:
  case 48000:
  case 96000:
  case 192000:
   switch (params_channels(params)) {
   case 2:
    break;
   case 4:
    bclk_div_val = bclk_div_val >> 1;
    lrclk_div_val = lrclk_div_val << 1;
    break;
   case 8:
    bclk_div_val = bclk_div_val >> 2;
    lrclk_div_val = lrclk_div_val << 2;
    break;
   case 16:
    bclk_div_val = bclk_div_val >> 3;
    lrclk_div_val = lrclk_div_val << 3;
    break;
   case 32:
    bclk_div_val = bclk_div_val >> 4;
    lrclk_div_val = lrclk_div_val << 4;
    break;
   default:
    dev_err(dev, "Unsupported channels %#x\n",
     params_channels(params));
   }
   break;
  default:
   break;
  }
  chip->lrclk_div = lrclk_div_val;
  chip->bclk_div = bclk_div_val;
 }
 return 0;
}

static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{
 struct acp_stream *stream = substream->runtime->private_data;
 struct device *dev = dai->component->dev;
 struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
 struct acp_resource *rsrc = chip->rsrc;
 u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;

 period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
 buf_size = frames_to_bytes(substream->runtime, substream->runtime->buffer_size);

 switch (cmd) {
 case SNDRV_PCM_TRIGGER_START:
 case SNDRV_PCM_TRIGGER_RESUME:
 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  stream->bytescount = acp_get_byte_count(chip, stream->dai_id, substream->stream);
  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
   switch (dai->driver->id) {
   case I2S_BT_INSTANCE:
    water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(chip);
    reg_val = ACP_BTTDM_ITER;
    ier_val = ACP_BTTDM_IER;
    buf_reg = ACP_BT_TX_RINGBUFSIZE(chip);
    break;
   case I2S_SP_INSTANCE:
    water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(chip);
    reg_val = ACP_I2STDM_ITER;
    ier_val = ACP_I2STDM_IER;
    buf_reg = ACP_I2S_TX_RINGBUFSIZE(chip);
    break;
   case I2S_HS_INSTANCE:
    water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
    reg_val = ACP_HSTDM_ITER;
    ier_val = ACP_HSTDM_IER;
    buf_reg = ACP_HS_TX_RINGBUFSIZE;
    break;
   default:
    dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
    return -EINVAL;
   }
  } else {
   switch (dai->driver->id) {
   case I2S_BT_INSTANCE:
    water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(chip);
    reg_val = ACP_BTTDM_IRER;
    ier_val = ACP_BTTDM_IER;
    buf_reg = ACP_BT_RX_RINGBUFSIZE(chip);
    break;
   case I2S_SP_INSTANCE:
    water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(chip);
    reg_val = ACP_I2STDM_IRER;
    ier_val = ACP_I2STDM_IER;
    buf_reg = ACP_I2S_RX_RINGBUFSIZE(chip);
    break;
   case I2S_HS_INSTANCE:
    water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
    reg_val = ACP_HSTDM_IRER;
    ier_val = ACP_HSTDM_IER;
    buf_reg = ACP_HS_RX_RINGBUFSIZE;
    break;
   default:
    dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
    return -EINVAL;
   }
  }

  writel(period_bytes, chip->base + water_val);
  writel(buf_size, chip->base + buf_reg);
  if (rsrc->soc_mclk)
   acp_set_i2s_clk(chip, dai->driver->id);
  val = readl(chip->base + reg_val);
  val = val | BIT(0);
  writel(val, chip->base + reg_val);
  writel(1, chip->base + ier_val);
  return 0;
 case SNDRV_PCM_TRIGGER_STOP:
 case SNDRV_PCM_TRIGGER_SUSPEND:
 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
   switch (dai->driver->id) {
   case I2S_BT_INSTANCE:
    reg_val = ACP_BTTDM_ITER;
    break;
   case I2S_SP_INSTANCE:
    reg_val = ACP_I2STDM_ITER;
    break;
   case I2S_HS_INSTANCE:
    reg_val = ACP_HSTDM_ITER;
    break;
   default:
    dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
    return -EINVAL;
   }

  } else {
   switch (dai->driver->id) {
   case I2S_BT_INSTANCE:
    reg_val = ACP_BTTDM_IRER;
    break;
   case I2S_SP_INSTANCE:
    reg_val = ACP_I2STDM_IRER;
    break;
   case I2S_HS_INSTANCE:
    reg_val = ACP_HSTDM_IRER;
    break;
   default:
    dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
    return -EINVAL;
   }
  }
  val = readl(chip->base + reg_val);
  val = val & ~BIT(0);
  writel(val, chip->base + reg_val);

  if (!(readl(chip->base + ACP_BTTDM_ITER) & BIT(0)) &&
      !(readl(chip->base + ACP_BTTDM_IRER) & BIT(0)))
   writel(0, chip->base + ACP_BTTDM_IER);
  if (!(readl(chip->base + ACP_I2STDM_ITER) & BIT(0)) &&
      !(readl(chip->base + ACP_I2STDM_IRER) & BIT(0)))
   writel(0, chip->base + ACP_I2STDM_IER);
  if (!(readl(chip->base + ACP_HSTDM_ITER) & BIT(0)) &&
      !(readl(chip->base + ACP_HSTDM_IRER) & BIT(0)))
   writel(0, chip->base + ACP_HSTDM_IER);
  return 0;
 default:
  return -EINVAL;
 }

 return 0;
}

static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
 struct device *dev = dai->component->dev;
 struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
 struct acp_resource *rsrc = chip->rsrc;
 struct acp_stream *stream = substream->runtime->private_data;
 u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;
 u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;
 unsigned int dir = substream->stream;

 switch (dai->driver->id) {
 case I2S_SP_INSTANCE:
  if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
   reg_dma_size = ACP_I2S_TX_DMA_SIZE(chip);
   acp_fifo_addr = rsrc->sram_pte_offset +
      SP_PB_FIFO_ADDR_OFFSET;
   reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip);
   reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip);

   if (chip->acp_rev >= ACP70_PCI_ID)
    phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START;
   else
    phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
   writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip));
  } else {
   reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip);
   acp_fifo_addr = rsrc->sram_pte_offset +
      SP_CAPT_FIFO_ADDR_OFFSET;
   reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip);
   reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip);

   if (chip->acp_rev >= ACP70_PCI_ID)
    phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START;
   else
    phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
   writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip));
  }
  break;
 case I2S_BT_INSTANCE:
  if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
   reg_dma_size = ACP_BT_TX_DMA_SIZE(chip);
   acp_fifo_addr = rsrc->sram_pte_offset +
      BT_PB_FIFO_ADDR_OFFSET;
   reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip);
   reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip);

   if (chip->acp_rev >= ACP70_PCI_ID)
    phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START;
   else
    phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
   writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip));
  } else {
   reg_dma_size = ACP_BT_RX_DMA_SIZE(chip);
   acp_fifo_addr = rsrc->sram_pte_offset +
      BT_CAPT_FIFO_ADDR_OFFSET;
   reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip);
   reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip);

   if (chip->acp_rev >= ACP70_PCI_ID)
    phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START;
   else
    phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
   writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip));
  }
  break;
 case I2S_HS_INSTANCE:
  if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
   reg_dma_size = ACP_HS_TX_DMA_SIZE;
   acp_fifo_addr = rsrc->sram_pte_offset +
    HS_PB_FIFO_ADDR_OFFSET;
   reg_fifo_addr = ACP_HS_TX_FIFOADDR;
   reg_fifo_size = ACP_HS_TX_FIFOSIZE;

   if (chip->acp_rev >= ACP70_PCI_ID)
    phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;
   else
    phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
   writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR);
  } else {
   reg_dma_size = ACP_HS_RX_DMA_SIZE;
   acp_fifo_addr = rsrc->sram_pte_offset +
     HS_CAPT_FIFO_ADDR_OFFSET;
   reg_fifo_addr = ACP_HS_RX_FIFOADDR;
   reg_fifo_size = ACP_HS_RX_FIFOSIZE;

   if (chip->acp_rev >= ACP70_PCI_ID)
    phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;
   else
    phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
   writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR);
  }
  break;
 default:
  dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
  return -EINVAL;
 }

 writel(DMA_SIZE, chip->base + reg_dma_size);
 writel(acp_fifo_addr, chip->base + reg_fifo_addr);
 writel(FIFO_SIZE, chip->base + reg_fifo_size);

 ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
 ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
   BIT(BT_RX_THRESHOLD(rsrc->offset)) |
   BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
   BIT(BT_TX_THRESHOLD(rsrc->offset)) |
   BIT(HS_RX_THRESHOLD(rsrc->offset)) |
   BIT(HS_TX_THRESHOLD(rsrc->offset));

 writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));

 return 0;
}

static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
 struct acp_stream *stream = substream->runtime->private_data;
 struct device *dev = dai->component->dev;
 struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
 struct acp_resource *rsrc = chip->rsrc;
 unsigned int dir = substream->stream;
 unsigned int irq_bit = 0;

 switch (dai->driver->id) {
 case I2S_SP_INSTANCE:
  if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
   irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset));
   stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET;
   stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET;
  } else {
   irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset));
   stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET;
   stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET;
  }
  break;
 case I2S_BT_INSTANCE:
  if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
   irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset));
   stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET;
   stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET;
  } else {
   irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset));
   stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET;
   stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
  }
  break;
 case I2S_HS_INSTANCE:
  if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
   irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));
   stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;
   stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;
  } else {
   irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));
   stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;
   stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;
  }
  break;
 default:
  dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
  return -EINVAL;
 }

 /* Save runtime dai configuration in stream */
 stream->id = dai->driver->id + dir;
 stream->dai_id = dai->driver->id;
 stream->irq_bit = irq_bit;
 stream->dir = substream->stream;

 return 0;
}

const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
 .startup = acp_i2s_startup,
 .hw_params = acp_i2s_hwparams,
 .prepare = acp_i2s_prepare,
 .trigger = acp_i2s_trigger,
 .set_fmt = acp_i2s_set_fmt,
 .set_tdm_slot = acp_i2s_set_tdm_slot,
};
EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON");

MODULE_DESCRIPTION("AMD ACP Audio I2S controller");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS(DRV_NAME);

Messung V0.5
C=97 H=97 G=96

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.