Unverified Commit 34bf40c2 authored by Mark Brown's avatar Mark Brown
Browse files

Add {24,32}-bit sample width support for RZ/G2L SSI

Merge series from Biju <biju.das.au@gmail.com>:

Add support for 24 and 32-bit sample format width for RZ/G2L SoCs. Apart
from this, the patch series includes some code cleanups.
parents c5224b8a 124f6155
Loading
Loading
Loading
Loading
+77 −42
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#define SSICR_MST		BIT(14)
#define SSICR_BCKP		BIT(13)
#define SSICR_LRCKP		BIT(12)
#define SSICR_PDTA		BIT(9)
#define SSICR_CKDV(x)		(((x) & 0xf) << 4)
#define SSICR_TEN		BIT(1)
#define SSICR_REN		BIT(0)
@@ -74,7 +75,8 @@
#define PREALLOC_BUFFER_MAX	(SZ_32K)

#define SSI_RATES		SNDRV_PCM_RATE_8000_48000 /* 8k-48kHz */
#define SSI_FMTS		SNDRV_PCM_FMTBIT_S16_LE
#define SSI_FMTS		(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
				 SNDRV_PCM_FMTBIT_S32_LE)
#define SSI_CHAN_MIN		2
#define SSI_CHAN_MAX		2
#define SSI_FIFO_DEPTH		32
@@ -294,11 +296,27 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate,
	}

	/*
	 * DWL: Data Word Length = 16 bits
	 * DWL: Data Word Length = {16, 24, 32} bits
	 * SWL: System Word Length = 32 bits
	 */
	ssicr |= SSICR_CKDV(clk_ckdv);
	ssicr |= SSICR_DWL(1) | SSICR_SWL(3);
	switch (ssi->hw_params_cache.sample_width) {
	case 16:
		ssicr |= SSICR_DWL(1);
		break;
	case 24:
		ssicr |= SSICR_DWL(5) | SSICR_PDTA;
		break;
	case 32:
		ssicr |= SSICR_DWL(6);
		break;
	default:
		dev_err(ssi->dev, "Not support %u data width",
			ssi->hw_params_cache.sample_width);
		return -EINVAL;
	}

	ssicr |= SSICR_SWL(3);
	rz_ssi_reg_writel(ssi, SSICR, ssicr);
	rz_ssi_reg_writel(ssi, SSIFCR, SSIFCR_AUCKE | SSIFCR_FIFO_RST);

@@ -455,7 +473,6 @@ static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
{
	struct snd_pcm_substream *substream = strm->substream;
	struct snd_pcm_runtime *runtime;
	u16 *buf;
	int fifo_samples;
	int frames_left;
	int samples;
@@ -490,12 +507,23 @@ static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
			break;

		/* calculate new buffer index */
		if (ssi->hw_params_cache.sample_width == 16) {
			u16 *buf;

			buf = (u16 *)runtime->dma_area;
			buf += strm->buffer_pos * runtime->channels;

		/* Note, only supports 16-bit samples */
			for (i = 0; i < samples; i++)
				*buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16);
		} else {
			u32 *buf;

			buf = (u32 *)runtime->dma_area;
			buf += strm->buffer_pos * runtime->channels;

			for (i = 0; i < samples; i++)
				*buf++ = rz_ssi_reg_readl(ssi, SSIFRDR);
		}

		rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
		rz_ssi_pointer_update(strm, samples / runtime->channels);
@@ -513,7 +541,6 @@ static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
	int frames_left;
	int i;
	u32 ssifsr;
	u16 *buf;

	if (!rz_ssi_stream_is_valid(ssi, strm))
		return -EINVAL;
@@ -542,12 +569,23 @@ static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
		return 0;

	/* calculate new buffer index */
	if (ssi->hw_params_cache.sample_width == 16) {
		u16 *buf;

		buf = (u16 *)(runtime->dma_area);
		buf += strm->buffer_pos * runtime->channels;

	/* Note, only supports 16-bit samples */
		for (i = 0; i < samples; i++)
			rz_ssi_reg_writel(ssi, SSIFTDR, ((u32)(*buf++) << 16));
	} else {
		u32 *buf;

		buf = (u32 *)(runtime->dma_area);
		buf += strm->buffer_pos * runtime->channels;

		for (i = 0; i < samples; i++)
			rz_ssi_reg_writel(ssi, SSIFTDR, *buf++);
	}

	rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_TDE, 0);
	rz_ssi_pointer_update(strm, samples / runtime->channels);
@@ -658,8 +696,13 @@ static int rz_ssi_dma_slave_config(struct rz_ssi_priv *ssi,
	cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
	cfg.dst_addr = ssi->phys + SSIFTDR;
	cfg.src_addr = ssi->phys + SSIFRDR;
	if (ssi->hw_params_cache.sample_width == 16) {
		cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
		cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
	} else {
		cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
		cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
	}

	return dmaengine_slave_config(dma_ch, &cfg);
}
@@ -774,14 +817,6 @@ static int rz_ssi_dma_request(struct rz_ssi_priv *ssi, struct device *dev)
	if (!rz_ssi_is_dma_enabled(ssi))
		goto no_dma;

	if (ssi->playback.dma_ch &&
	    (rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, true) < 0))
		goto no_dma;

	if (ssi->capture.dma_ch &&
	    (rz_ssi_dma_slave_config(ssi, ssi->capture.dma_ch, false) < 0))
		goto no_dma;

	return 0;

no_dma:
@@ -829,23 +864,26 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
		if (cmd == SNDRV_PCM_TRIGGER_START)
			rz_ssi_stream_init(strm, substream);

		if (ssi->dma_rt) {
			bool is_playback;
		if (rz_ssi_is_dma_enabled(ssi)) {
			bool is_playback = rz_ssi_stream_is_play(substream);

			is_playback = rz_ssi_stream_is_play(substream);
			if (ssi->dma_rt)
				ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch,
							      is_playback);
			else
				ret = rz_ssi_dma_slave_config(ssi, strm->dma_ch,
							      is_playback);

			/* Fallback to pio */
			if (ret < 0) {
				ssi->playback.transfer = rz_ssi_pio_send;
				ssi->capture.transfer = rz_ssi_pio_recv;
				rz_ssi_release_dma_channels(ssi);
			}
		}

			} else {
				/* For DMA, queue up multiple DMA descriptors */
		if (rz_ssi_is_dma_enabled(ssi))
				num_transfer = 4;
			}
		}

		for (i = 0; i < num_transfer; i++) {
			ret = strm->transfer(ssi, strm);
@@ -982,7 +1020,7 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
	unsigned int rate = params_rate(params);
	int ret;

	if (sample_bits != 16) {
	if (!(sample_bits == 16 || sample_bits == 24 || sample_bits == 32)) {
		dev_err(ssi->dev, "Unsupported sample width: %d\n",
			sample_bits);
		return -EINVAL;
@@ -1119,19 +1157,16 @@ static int rz_ssi_probe(struct platform_device *pdev)

	audio_clk = devm_clk_get(dev, "audio_clk1");
	if (IS_ERR(audio_clk))
		return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk),
				     "no audio clk1");
		return dev_err_probe(dev, PTR_ERR(audio_clk), "no audio clk1");

	ssi->audio_clk_1 = clk_get_rate(audio_clk);
	audio_clk = devm_clk_get(dev, "audio_clk2");
	if (IS_ERR(audio_clk))
		return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk),
				     "no audio clk2");
		return dev_err_probe(dev, PTR_ERR(audio_clk), "no audio clk2");

	ssi->audio_clk_2 = clk_get_rate(audio_clk);
	if (!(ssi->audio_clk_1 || ssi->audio_clk_2))
		return dev_err_probe(&pdev->dev, -EINVAL,
				     "no audio clk1 or audio clk2");
		return dev_err_probe(dev, -EINVAL, "no audio clk1 or audio clk2");

	ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2;

@@ -1247,7 +1282,7 @@ static void rz_ssi_remove(struct platform_device *pdev)

static const struct of_device_id rz_ssi_of_match[] = {
	{ .compatible = "renesas,rz-ssi", },
	{/* Sentinel */},
	{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, rz_ssi_of_match);