@@ -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);
@@ -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.
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> --- sound/soc/dwc/dwc-i2s.c | 39 +++++++++++++++++++++++++++++++++++++-- sound/soc/dwc/local.h | 6 ++++++ 2 files changed, 43 insertions(+), 2 deletions(-)