]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
adc: stm32mp13: add support of adc to stm32mp13
authorOlivier Moysan <olivier.moysan@foss.st.com>
Fri, 14 Nov 2025 16:08:52 +0000 (17:08 +0100)
committerTom Rini <trini@konsulko.com>
Mon, 17 Nov 2025 16:43:21 +0000 (10:43 -0600)
Add support of STM32 ADCs to STM32MP13x. This patch introduces
stm32_adc_regspec structure, as this is already done in kernel
driver, to manage smartly the differences in register set
between STMP32MP15 and STM32MP13 ADCs.

Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
drivers/adc/stm32-adc-core.c
drivers/adc/stm32-adc.c

index af340b8b273b0c13fea29b8817dc896576111a7a..3446e34fa4677422877adb9b0c57afd734f80b3c 100644 (file)
@@ -200,6 +200,7 @@ err_aclk_disable:
 static const struct udevice_id stm32_adc_core_ids[] = {
        { .compatible = "st,stm32h7-adc-core" },
        { .compatible = "st,stm32mp1-adc-core" },
+       { .compatible = "st,stm32mp13-adc-core" },
        {}
 };
 
index d50f00f1233e07cfdf8f9e2b26137b3bb7b4b408..b11f771b71c8d1092f4b2f8e5250cf77f1281b50 100644 (file)
 /* STM32H7_ADC_SQR1 - bit fields */
 #define STM32H7_SQ1_SHIFT              6
 
+/* STM32H7_ADC_DIFSEL - bit fields */
+#define STM32H7_DIFSEL_SHIFT   0
+#define STM32H7_DIFSEL_MASK            GENMASK(19, 0)
+
 /* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */
 #define STM32H7_BOOST_CLKRATE          20000000UL
 
+/* STM32MP13 - Registers for each ADC instance */
+#define STM32MP13_ADC_DIFSEL   0xB0
+
+/* STM32MP13_ADC_CFGR specific bit fields */
+#define STM32MP13_DMAEN                        BIT(0)
+#define STM32MP13_DMACFG               BIT(1)
+
+/* STM32MP13_ADC_DIFSEL - bit fields */
+#define STM32MP13_DIFSEL_SHIFT 0
+#define STM32MP13_DIFSEL_MASK  GENMASK(18, 0)
+
 #define STM32_ADC_CH_MAX               20      /* max number of channels */
 #define STM32_ADC_TIMEOUT_US           100000
 
+struct stm32_adc {
+       void __iomem *regs;
+       int active_channel;
+       const struct stm32_adc_cfg *cfg;
+};
+
+struct stm32_adc_regs {
+       int reg;
+       int mask;
+       int shift;
+};
+
+struct stm32_adc_regspec {
+       const struct stm32_adc_regs difsel;
+};
+
 struct stm32_adc_cfg {
+       const struct stm32_adc_regspec *regs;
        unsigned int max_channels;
        unsigned int num_bits;
        bool has_vregready;
+       bool has_boostmode;
+       bool has_linearcal;
+       bool has_presel;
 };
 
-struct stm32_adc {
-       void __iomem *regs;
-       int active_channel;
-       const struct stm32_adc_cfg *cfg;
+static const struct stm32_adc_regspec stm32h7_adc_regspec = {
+       .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK },
+};
+
+static const struct stm32_adc_regspec stm32mp13_adc_regspec = {
+       .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK },
 };
 
 static void stm32_adc_enter_pwr_down(struct udevice *dev)
 {
        struct stm32_adc *adc = dev_get_priv(dev);
 
-       clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
+       if (adc->cfg->has_boostmode)
+               clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
+
        /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
 }
@@ -90,8 +129,7 @@ static int stm32_adc_exit_pwr_down(struct udevice *dev)
        /* Exit deep power down, then enable ADC voltage regulator */
        clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN);
-
-       if (common->rate > STM32H7_BOOST_CLKRATE)
+       if (adc->cfg->has_boostmode && common->rate > STM32H7_BOOST_CLKRATE)
                setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
 
        /* Wait for startup time */
@@ -134,7 +172,7 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel)
                return ret;
 
        /* Only use single ended channels */
-       writel(0, adc->regs + STM32H7_ADC_DIFSEL);
+       clrbits_le32(adc->regs + adc->cfg->regs->difsel.reg, adc->cfg->regs->difsel.mask);
 
        /* Enable ADC, Poll for ADRDY to be set (after adc startup time) */
        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN);
@@ -147,7 +185,8 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel)
        }
 
        /* Preselect channels */
-       writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL);
+       if (adc->cfg->has_presel)
+               writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL);
 
        /* Set sampling time to max value by default */
        writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR1);
@@ -156,9 +195,11 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel)
        /* Program regular sequence: chan in SQ1 & len = 0 for one channel */
        writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1);
 
-       /* Trigger detection disabled (conversion can be launched in SW) */
-       clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN |
-                    STM32H7_DMNGT);
+       /*
+        * Trigger detection disabled (conversion can be launched in SW)
+        * STM32H7_DMNGT is equivalent to STM32MP13_DMAEN & STM32MP13_DMACFG
+        */
+       clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN | STM32H7_DMNGT);
        adc->active_channel = channel;
 
        return 0;
@@ -206,7 +247,7 @@ static int stm32_adc_selfcalib(struct udevice *dev)
 {
        struct stm32_adc *adc = dev_get_priv(dev);
        int ret;
-       u32 val;
+       u32 val, mask;
 
        /*
         * Select calibration mode:
@@ -231,7 +272,10 @@ static int stm32_adc_selfcalib(struct udevice *dev)
         * - Linearity calibration (needs to be done only once for single/diff)
         *   will run simultaneously with offset calibration.
         */
-       setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+       mask = STM32H7_ADCALDIF;
+       if (adc->cfg->has_linearcal)
+               mask |= STM32H7_ADCALLIN;
+       setbits_le32(adc->regs + STM32H7_ADC_CR, mask);
 
        /* Start calibration, then wait for completion */
        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL);
@@ -394,14 +438,28 @@ static const struct adc_ops stm32_adc_ops = {
 };
 
 static const struct stm32_adc_cfg stm32h7_adc_cfg = {
+       .regs = &stm32h7_adc_regspec,
        .num_bits = 16,
        .max_channels = STM32_ADC_CH_MAX,
+       .has_boostmode = true,
+       .has_linearcal = true,
+       .has_presel = true,
 };
 
 static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
+       .regs = &stm32h7_adc_regspec,
        .num_bits = 16,
        .max_channels = STM32_ADC_CH_MAX,
        .has_vregready = true,
+       .has_boostmode = true,
+       .has_linearcal = true,
+       .has_presel = true,
+};
+
+static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
+       .regs = &stm32mp13_adc_regspec,
+       .num_bits = 12,
+       .max_channels = STM32_ADC_CH_MAX - 1,
 };
 
 static const struct udevice_id stm32_adc_ids[] = {
@@ -409,6 +467,8 @@ static const struct udevice_id stm32_adc_ids[] = {
          .data = (ulong)&stm32h7_adc_cfg },
        { .compatible = "st,stm32mp1-adc",
          .data = (ulong)&stm32mp1_adc_cfg },
+       { .compatible = "st,stm32mp13-adc",
+         .data = (ulong)&stm32mp13_adc_cfg },
        {}
 };