summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2025-12-15 10:10:21 +0900
committerMark Brown <broonie@kernel.org>2025-12-15 10:10:21 +0900
commit34bf40c2755636309cbf6bba01ecd390ba6ede97 (patch)
tree70561b43a389cb0d04efc6fcb333728d19e2a906
parentc5224b8a1ba52d70b3fc2548109bd04bbbc0c8a6 (diff)
parent124f6155f3d97b0e33f178c10a5138a42c8fd207 (diff)
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.
-rw-r--r--sound/soc/renesas/rz-ssi.c119
1 files changed, 77 insertions, 42 deletions
diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c
index f4dc2f68dead..5909778a6a70 100644
--- a/sound/soc/renesas/rz-ssi.c
+++ b/sound/soc/renesas/rz-ssi.c
@@ -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 */
- buf = (u16 *)runtime->dma_area;
- buf += strm->buffer_pos * runtime->channels;
+ if (ssi->hw_params_cache.sample_width == 16) {
+ u16 *buf;
- /* Note, only supports 16-bit samples */
- for (i = 0; i < samples; i++)
- *buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16);
+ buf = (u16 *)runtime->dma_area;
+ buf += strm->buffer_pos * runtime->channels;
+
+ 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 */
- buf = (u16 *)(runtime->dma_area);
- buf += strm->buffer_pos * runtime->channels;
+ 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));
+ 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;
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ 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,24 +864,27 @@ 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);
+
+ 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);
- is_playback = rz_ssi_stream_is_play(substream);
- ret = rz_ssi_dma_slave_config(ssi, ssi->playback.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 */
+ num_transfer = 4;
}
}
- /* 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);
if (ret)
@@ -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);