]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: mxs-saif: support usage with simple-audio-card
authorDario Binacchi <dario.binacchi@amarulasolutions.com>
Wed, 24 Sep 2025 13:07:44 +0000 (15:07 +0200)
committerMark Brown <broonie@kernel.org>
Thu, 16 Oct 2025 13:25:41 +0000 (14:25 +0100)
Add support for enabling MCLK output when using the simple-audio-card
driver. In the sound/soc/mxs/mxs-sgtl5000.c use case, that driver
handles MCLK enable/disable by calling mxs_saif_get_mclk() and
mxs_saif_put_mclk() at probe/remove. This does not happen when the
simple-audio-card driver is used. Extend the mxs-saif driver to enable
MCLK output in that scenario.

Co-developed-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Link: https://patch.msgid.link/20250924130749.3012071-1-dario.binacchi@amarulasolutions.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/mxs/mxs-saif.c

index 3e3a62df3d7e39cddb7492aa94b16662e9c00ba4..a01a680ad4d71f0b9507b6e0201891f5a7f10b74 100644 (file)
 #define MXS_SET_ADDR   0x4
 #define MXS_CLR_ADDR   0x8
 
+#define MXS_SAIF_BUSY_TIMEOUT_US 10000
+
 static struct mxs_saif *mxs_saif[2];
 
+/*
+ * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
+ * is provided by other SAIF, we provide a interface here to get its master
+ * from its master_id.
+ * Note that the master could be itself.
+ */
+static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif *saif)
+{
+       return mxs_saif[saif->master_id];
+}
+
+static int __mxs_saif_put_mclk(struct mxs_saif *saif)
+{
+       u32 stat;
+       int ret;
+
+       ret = readx_poll_timeout(__raw_readl, saif->base + SAIF_STAT, stat,
+                                (stat & BM_SAIF_STAT_BUSY) == 0,
+                                MXS_SAIF_BUSY_TIMEOUT_US,
+                                USEC_PER_SEC);
+       if (ret) {
+               dev_err(saif->dev, "error: busy\n");
+               return -EBUSY;
+       }
+
+       /* disable MCLK output */
+       __raw_writel(BM_SAIF_CTRL_CLKGATE,
+               saif->base + SAIF_CTRL + MXS_SET_ADDR);
+       __raw_writel(BM_SAIF_CTRL_RUN,
+               saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+       saif->mclk_in_use = 0;
+
+       return 0;
+}
+
+static int __mxs_saif_get_mclk(struct mxs_saif *saif)
+{
+       u32 stat;
+       struct mxs_saif *master_saif;
+
+       if (!saif)
+               return -EINVAL;
+
+       /* Clear Reset */
+       __raw_writel(BM_SAIF_CTRL_SFTRST,
+               saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+       /* FIXME: need clear clk gate for register r/w */
+       __raw_writel(BM_SAIF_CTRL_CLKGATE,
+               saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+       master_saif = mxs_saif_get_master(saif);
+       if (saif != master_saif) {
+               dev_err(saif->dev, "can not get mclk from a non-master saif\n");
+               return -EINVAL;
+       }
+
+       stat = __raw_readl(saif->base + SAIF_STAT);
+       if (stat & BM_SAIF_STAT_BUSY) {
+               dev_err(saif->dev, "error: busy\n");
+               return -EBUSY;
+       }
+
+       saif->mclk_in_use = 1;
+
+       return 0;
+}
+
 /*
  * SAIF is a little different with other normal SOC DAIs on clock using.
  *
@@ -48,6 +119,7 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                        int clk_id, unsigned int freq, int dir)
 {
        struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret;
 
        switch (clk_id) {
        case MXS_SAIF_MCLK:
@@ -56,18 +128,22 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        default:
                return -EINVAL;
        }
-       return 0;
-}
 
-/*
- * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
- * is provided by other SAIF, we provide a interface here to get its master
- * from its master_id.
- * Note that the master could be itself.
- */
-static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif)
-{
-       return mxs_saif[saif->master_id];
+       if (!saif->mclk_in_use && freq) {
+               ret = __mxs_saif_get_mclk(saif);
+               if (ret)
+                       return ret;
+
+               /* enable MCLK output */
+               __raw_writel(BM_SAIF_CTRL_RUN,
+               saif->base + SAIF_CTRL + MXS_SET_ADDR);
+       } else if (saif->mclk_in_use && freq == 0) {
+               ret = __mxs_saif_put_mclk(saif);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 /*
@@ -238,34 +314,15 @@ int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk,
                                        unsigned int rate)
 {
        struct mxs_saif *saif = mxs_saif[saif_id];
-       u32 stat;
        int ret;
-       struct mxs_saif *master_saif;
 
        if (!saif)
                return -EINVAL;
 
-       /* Clear Reset */
-       __raw_writel(BM_SAIF_CTRL_SFTRST,
-               saif->base + SAIF_CTRL + MXS_CLR_ADDR);
-
-       /* FIXME: need clear clk gate for register r/w */
-       __raw_writel(BM_SAIF_CTRL_CLKGATE,
-               saif->base + SAIF_CTRL + MXS_CLR_ADDR);
-
-       master_saif = mxs_saif_get_master(saif);
-       if (saif != master_saif) {
-               dev_err(saif->dev, "can not get mclk from a non-master saif\n");
-               return -EINVAL;
-       }
-
-       stat = __raw_readl(saif->base + SAIF_STAT);
-       if (stat & BM_SAIF_STAT_BUSY) {
-               dev_err(saif->dev, "error: busy\n");
-               return -EBUSY;
-       }
+       ret = __mxs_saif_get_mclk(saif);
+       if (ret)
+               return ret;
 
-       saif->mclk_in_use = 1;
        ret = mxs_saif_set_clk(saif, mclk, rate);
        if (ret)
                return ret;