Unverified Commit a42e988b authored by Maxim Kochetkov's avatar Maxim Kochetkov Committed by Mark Brown
Browse files

ASoC: dwc: add DMA handshake control



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: default avatarMaxim Kochetkov <fido_max@inbox.ru>
Link: https://lore.kernel.org/r/20230613191910.725049-1-fido_max@inbox.ru


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 02474880
Loading
Loading
Loading
Loading
+37 −2
Original line number Diff line number Diff line
@@ -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);

	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);
+6 −0
Original line number Diff line number Diff line
@@ -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.