[PATCH v2 02/14] iio: adc: stm32-adc: core: manage clock prescaler diversity
Fabrice Gasnier
fabrice.gasnier at foss.st.com
Wed Sep 23 08:39:05 PDT 2026
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 at 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
More information about the linux-arm-kernel
mailing list