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@xxxxxxxx> --- sound/soc/dwc/dwc-i2s.c | 39 +++++++++++++++++++++++++++++++++++++-- sound/soc/dwc/local.h | 6 ++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 9e7065dd854c..02b9894e99a7 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -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); } @@ -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); diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h index d64bd4f8fd34..ba4e397099be 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -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. -- 2.40.1