]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: fsl_micfil: Add decimation filter bypass mode support
authorShengjiu Wang <shengjiu.wang@nxp.com>
Thu, 6 Feb 2025 03:03:06 +0000 (11:03 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 11 Feb 2025 13:36:18 +0000 (13:36 +0000)
When decimation filter bypass mode is enabled, PDM data can be
written into FIFO directly without any processing.

The interface of this mode is DSD big endian format, when
user needs this format, then this mode is enabled.

This mode is only for the i.MX943 platform currently.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Link: https://patch.msgid.link/20250206030306.2618620-1-shengjiu.wang@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/fsl/fsl_micfil.c
sound/soc/fsl/fsl_micfil.h

index fa41366833920ddf529c13df81603e1043802dcb..73d8910a61887430dcc646e8e0d858b163362fd2 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/dma/imx-dma.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
 #include <sound/core.h>
@@ -78,6 +79,7 @@ struct fsl_micfil {
        struct fsl_micfil_verid verid;
        struct fsl_micfil_param param;
        bool mclk_flag;  /* mclk enable flag */
+       bool dec_bypass;
 };
 
 struct fsl_micfil_soc_data {
@@ -129,7 +131,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx943 = {
        .fifos = 8,
        .fifo_depth = 32,
        .dataline =  0xf,
-       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_BE,
        .use_edma = true,
        .use_verid = true,
        .volume_sx = false,
@@ -724,14 +726,14 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
                if (ret)
                        return ret;
 
-               if (micfil->vad_enabled)
+               if (micfil->vad_enabled && !micfil->dec_bypass)
                        fsl_micfil_hwvad_enable(micfil);
 
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (micfil->vad_enabled)
+               if (micfil->vad_enabled && !micfil->dec_bypass)
                        fsl_micfil_hwvad_disable(micfil);
 
                /* Disable the module */
@@ -778,8 +780,9 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
 {
        struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai);
        unsigned int channels = params_channels(params);
+       snd_pcm_format_t format = params_format(params);
        unsigned int rate = params_rate(params);
-       int clk_div = 8;
+       int clk_div = 8, mclk_rate, div_multiply_k;
        int osr = MICFIL_OSR_DEFAULT;
        int ret;
 
@@ -801,7 +804,39 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
 
        micfil->mclk_flag = true;
 
-       ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8);
+       /* floor(K * CLKDIV) */
+       switch (micfil->quality) {
+       case QUALITY_HIGH:
+               div_multiply_k = clk_div >> 1;
+               break;
+       case QUALITY_LOW:
+       case QUALITY_VLOW1:
+               div_multiply_k = clk_div << 1;
+               break;
+       case QUALITY_VLOW2:
+               div_multiply_k = clk_div << 2;
+               break;
+       case QUALITY_MEDIUM:
+       case QUALITY_VLOW0:
+       default:
+               div_multiply_k = clk_div;
+               break;
+       }
+
+       if (format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
+               micfil->dec_bypass = true;
+               /*
+                * According to equation 29 in RM:
+                * MCLK_CLK_ROOT = PDM CLK rate * 2 * floor(K * CLKDIV)
+                * PDM CLK rate = rate * physical bit width (32)
+                */
+               mclk_rate = rate * div_multiply_k * 32 * 2;
+       } else {
+               micfil->dec_bypass = false;
+               mclk_rate = rate * clk_div * osr * 8;
+       }
+
+       ret = clk_set_rate(micfil->mclk, mclk_rate);
        if (ret)
                return ret;
 
@@ -809,6 +844,10 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
        if (ret)
                return ret;
 
+       regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
+                          MICFIL_CTRL2_DEC_BYPASS,
+                          micfil->dec_bypass ? MICFIL_CTRL2_DEC_BYPASS : 0);
+
        ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
                                 MICFIL_CTRL2_CLKDIV | MICFIL_CTRL2_CICOSR,
                                 FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) |
index aa3661ea4ffc11ae283ca29a1b6bcbda7fe47881..fdfe4e7125bc513abe5aacedc0d881935a92cafa 100644 (file)
@@ -53,6 +53,7 @@
 #define MICFIL_CTRL1_CHEN(ch)          BIT(ch)
 
 /* MICFIL Control Register 2 -- REG_MICFILL_CTRL2 0x04 */
+#define MICFIL_CTRL2_DEC_BYPASS                BIT(31)
 #define MICFIL_CTRL2_QSEL_SHIFT                25
 #define MICFIL_CTRL2_QSEL              GENMASK(27, 25)
 #define MICFIL_QSEL_MEDIUM_QUALITY     0