]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: renesas: rz-ssi: Add support for 24 bits sample width
authorBiju Das <biju.das.jz@bp.renesas.com>
Fri, 14 Nov 2025 07:58:51 +0000 (07:58 +0000)
committerMark Brown <broonie@kernel.org>
Sun, 14 Dec 2025 10:33:01 +0000 (19:33 +0900)
Add support for 24 bits sample format width for RZ/G2L SoCs.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://patch.msgid.link/20251114075856.4751-5-biju.das.jz@bp.renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/renesas/rz-ssi.c

index 55aefff8857d287a0a8cf73a55b0dabbe4093043..3ec7c9875b431b34a804fc671bb88c9b58613414 100644 (file)
@@ -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,7 @@
 #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)
 #define SSI_CHAN_MIN           2
 #define SSI_CHAN_MAX           2
 #define SSI_FIFO_DEPTH         32
@@ -294,11 +295,24 @@ 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} 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;
+       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 +469,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 +503,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 +537,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 +565,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;
+
+               for (i = 0; i < samples; i++)
+                       rz_ssi_reg_writel(ssi, SSIFTDR, ((u32)(*buf++) << 16));
+       } else {
+               u32 *buf;
 
-       /* Note, only supports 16-bit samples */
-       for (i = 0; i < samples; i++)
-               rz_ssi_reg_writel(ssi, SSIFTDR, ((u32)(*buf++) << 16));
+               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 +692,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);
 }
@@ -977,7 +1016,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)) {
                dev_err(ssi->dev, "Unsupported sample width: %d\n",
                        sample_bits);
                return -EINVAL;