[PATCH v2 02/14] iio: adc: stm32-adc: core: manage clock prescaler diversity
From: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Date: 2026-09-23 15:41:09
Also in:
linux-devicetree, linux-iio, lkml
Subsystem:
iio subsystem and drivers, the rest · Maintainers:
Jonathan Cameron, Linus Torvalds
Make the clock prescaler selection configurable, to prepare stm32mp2 support. Reuse existing stm32f4_adc_clk_sel(). Rename it so it's no longer specific to stm32f4. Add configuration data to handle upcoming differences on: - registers and bits - division ratio No functional change intended. Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com> --- Changes in v2: - new precursor patch as advised by Andy and Jonathan - unsigned prescaler array as advised by Andy - cosmetic: spaces before and after braces --- drivers/iio/adc/stm32-adc-core.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-)
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index a42d82d61cb8..14ed50bb3ab5 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c@@ -50,6 +50,8 @@ * @ovr_msk: array of ovr (overrun flag) masks in csr for adc1..n * @ier: interrupt enable register offset for each adc * @eocie_msk: end of conversion interrupt enable mask in @ier + * @presc_msk: prescaler mask in ccr + * @presc_shift: prescaler bit shift in ccr */ struct stm32_adc_common_regs { u32 csr;
@@ -58,6 +60,8 @@ struct stm32_adc_common_regs { u32 ovr_msk[STM32_ADC_MAX_ADCS]; u32 ier; u32 eocie_msk; + u32 presc_msk; + u32 presc_shift; }; struct stm32_adc_priv;
@@ -66,6 +70,8 @@ struct stm32_adc_priv; * struct stm32_adc_priv_cfg - stm32 core compatible configuration data * @regs: common registers for all instances * @clk_sel: clock selection routine + * @presc: clock prescaler array + * @num_presc: number of clock prescalers in presc array * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) * @ipid: adc identification number * @has_syscfg: SYSCFG capability flags
@@ -75,6 +81,8 @@ struct stm32_adc_priv; struct stm32_adc_priv_cfg { const struct stm32_adc_common_regs *regs; int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); + unsigned int *presc; + unsigned int num_presc; u32 max_clk_rate_hz; u32 ipid; unsigned int has_syscfg;
@@ -126,22 +134,22 @@ static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com) } /* STM32F4 ADC internal common clock prescaler division ratios */ -static int stm32f4_pclk_div[] = {2, 4, 6, 8}; +static unsigned int stm32f4_pclk_div[] = { 2, 4, 6, 8 }; /** - * stm32f4_adc_clk_sel() - Select stm32f4 ADC common clock prescaler + * stm32_adc_clk_sel() - Select stm32f4 ADC common clock prescaler * @pdev: platform device * @priv: stm32 ADC core private data * Select clock prescaler used for analog conversions, before using ADC. */ -static int stm32f4_adc_clk_sel(struct platform_device *pdev, - struct stm32_adc_priv *priv) +static int stm32_adc_clk_sel(struct platform_device *pdev, + struct stm32_adc_priv *priv) { unsigned long rate; u32 val; int i; - /* stm32f4 has one clk input for analog (mandatory), enforce it here */ + /* This ADC has one clk input for analog (mandatory), enforce it here */ if (!priv->aclk) { dev_err(&pdev->dev, "No 'adc' clock found\n"); return -ENOENT;
@@ -153,20 +161,20 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, return -EINVAL; } - for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { - if ((rate / stm32f4_pclk_div[i]) <= priv->max_clk_rate) + for (i = 0; i < priv->cfg->num_presc; i++) { + if ((rate / priv->cfg->presc[i]) <= priv->max_clk_rate) break; } - if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { + if (i >= priv->cfg->num_presc) { dev_err(&pdev->dev, "adc clk selection failed\n"); return -EINVAL; } - priv->common.rate = rate / stm32f4_pclk_div[i]; - val = readl_relaxed(priv->common.base + STM32F4_ADC_CCR); - val &= ~STM32F4_ADC_ADCPRE_MASK; - val |= i << STM32F4_ADC_ADCPRE_SHIFT; - writel_relaxed(val, priv->common.base + STM32F4_ADC_CCR); + priv->common.rate = rate / priv->cfg->presc[i]; + val = readl_relaxed(priv->common.base + priv->cfg->regs->ccr); + val &= ~priv->cfg->regs->presc_msk; + val |= i << priv->cfg->regs->presc_shift; + writel_relaxed(val, priv->common.base + priv->cfg->regs->ccr); dev_dbg(&pdev->dev, "Using analog clock source at %ld kHz\n", priv->common.rate / 1000);
@@ -314,6 +322,8 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3 }, .ier = STM32F4_ADC_CR1, .eocie_msk = STM32F4_EOCIE, + .presc_msk = STM32F4_ADC_ADCPRE_MASK, + .presc_shift = STM32F4_ADC_ADCPRE_SHIFT, }; /* STM32H7 common registers definitions */
@@ -850,7 +860,9 @@ static DEFINE_RUNTIME_DEV_PM_OPS(stm32_adc_core_pm_ops, static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { .regs = &stm32f4_adc_common_regs, - .clk_sel = stm32f4_adc_clk_sel, + .clk_sel = stm32_adc_clk_sel, + .presc = stm32f4_pclk_div, + .num_presc = ARRAY_SIZE(stm32f4_pclk_div), .max_clk_rate_hz = 36000000, .num_irqs = 1, .num_adcs = 3,
--
2.43.0