Skip to content

Commit

Permalink
ASoC: dwc: add DMA handshake control
Browse files Browse the repository at this point in the history
DMA mode uses hardware handshake signals. DMACR register is used to enable
the DMA Controller interface operation. So add DMA enable/disable to
i2s_start()/i2s_stop() functions if using DMA mode.

Signed-off-by: Maxim Kochetkov <fido_max@inbox.ru>
Link: https://lore.kernel.org/r/20230613191910.725049-1-fido_max@inbox.ru
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Maxim Kochetkov authored and Mark Brown committed Jun 19, 2023
1 parent 0247488 commit a42e988
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
39 changes: 37 additions & 2 deletions sound/soc/dwc/dwc-i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,19 +150,51 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}

static void i2s_enable_dma(struct dw_i2s_dev *dev, u32 stream)
{
u32 dma_reg = i2s_read_reg(dev->i2s_base, I2S_DMACR);

/* Enable DMA handshake for stream */
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_reg |= I2S_DMAEN_TXBLOCK;
else
dma_reg |= I2S_DMAEN_RXBLOCK;

i2s_write_reg(dev->i2s_base, I2S_DMACR, dma_reg);
}

static void i2s_disable_dma(struct dw_i2s_dev *dev, u32 stream)
{
u32 dma_reg = i2s_read_reg(dev->i2s_base, I2S_DMACR);

/* Disable DMA handshake for stream */
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
dma_reg &= ~I2S_DMAEN_TXBLOCK;
i2s_write_reg(dev->i2s_base, I2S_RTXDMA, 1);
} else {
dma_reg &= ~I2S_DMAEN_RXBLOCK;
i2s_write_reg(dev->i2s_base, I2S_RRXDMA, 1);
}
i2s_write_reg(dev->i2s_base, I2S_DMACR, dma_reg);
}

static void i2s_start(struct dw_i2s_dev *dev,
struct snd_pcm_substream *substream)
{
struct i2s_clk_config_data *config = &dev->config;

i2s_write_reg(dev->i2s_base, IER, 1);
i2s_enable_irqs(dev, substream->stream, config->chan_nr);

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
i2s_write_reg(dev->i2s_base, ITER, 1);
else
i2s_write_reg(dev->i2s_base, IRER, 1);

if (dev->use_pio)
i2s_enable_irqs(dev, substream->stream, config->chan_nr);
else
i2s_enable_dma(dev, substream->stream);

i2s_write_reg(dev->i2s_base, CER, 1);
}

Expand All @@ -176,7 +208,10 @@ static void i2s_stop(struct dw_i2s_dev *dev,
else
i2s_write_reg(dev->i2s_base, IRER, 0);

i2s_disable_irqs(dev, substream->stream, 8);
if (dev->use_pio)
i2s_disable_irqs(dev, substream->stream, 8);
else
i2s_disable_dma(dev, substream->stream);

if (!dev->active) {
i2s_write_reg(dev->i2s_base, CER, 0);
Expand Down
6 changes: 6 additions & 0 deletions sound/soc/dwc/local.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
#define I2S_COMP_VERSION 0x01F8
#define I2S_COMP_TYPE 0x01FC

#define I2S_RRXDMA 0x01C4
#define I2S_RTXDMA 0x01CC
#define I2S_DMACR 0x0200
#define I2S_DMAEN_RXBLOCK (1 << 16)
#define I2S_DMAEN_TXBLOCK (1 << 17)

/*
* Component parameter register fields - define the I2S block's
* configuration.
Expand Down

0 comments on commit a42e988

Please sign in to comment.