* [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25
@ 2026-09-23 15:39 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 01/14] dt-bindings: iio: adc: stm32-adc: " Fabrice Gasnier
` (13 more replies)
0 siblings, 14 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Cheick Traore,
Olivier Moysan, Patrice Chotard, Cheick Traore
Add support for STM32MP23 and STM32MP25 Analog to Digital Converter.
It's a variant of other supported STM32MP ADCs. Add the DT bindings,
driver, SOC DTS and an example on stm32mp257f-ev1 board.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- dt-bindings: updates since discussion with Jonathan. Drop fallback
compatible and "st,adc-trigger-sel".
- driver: address Jonathan and Andy comments and overall:
- Split into several pieces to prepare the infrastructure without
functional change
- Add stm32mp23/25 support
- Then add vddgpu feature.
- Rebased on top of fixes sent separately, since pre-existing issues have
been reported by Sashiko on v1.
https://patch.msgid.link/20260916-adc-fix-intchan-v1-v3-1-b5f05b86bc60@foss.st.com
https://patch.msgid.link/20260916-adc-fix-div0-v3-1-bedf027a6e7e@foss.st.com
- Link to v1: https://patch.msgid.link/20260911-adc-stm32mp25-v1-v1-0-cef26eecdef2@foss.st.com
---
Cheick Traore (1):
arm64: dts: st: add ADC nodes on stm32mp231
Fabrice Gasnier (10):
dt-bindings: iio: adc: stm32-adc: add support for stm32mp23 and stm32mp25
iio: adc: stm32-adc: core: manage clock prescaler diversity
iio: adc: stm32-adc: core: configurable number of interrupts
iio: adc: stm32-adc: rework internal channels data
iio: adc: stm32-adc: add vreg enable option to manage diversity
iio: adc: stm32-adc: add support for stm32mp25
iio: adc: stm32-adc: add support for stm32mp23
iio: adc: stm32: add support for vddgpu on stm32mp23 and stm32mp25
arm64: dts: st: add ADC nodes on stm32mp251
arm64: dts: st: add ADC support on stm32mp257f-ev1 board
Olivier Moysan (1):
iio: adc: stm32-adc: manage characterization voltage diversity
Patrice Chotard (2):
arm64: dts: st: add vrefint calibration on stm32mp23
arm64: dts: st: add vrefint calibration on stm32mp25
.../devicetree/bindings/iio/adc/st,stm32-adc.yaml | 71 +++
arch/arm64/boot/dts/st/stm32mp231.dtsi | 116 +++++
arch/arm64/boot/dts/st/stm32mp251.dtsi | 116 +++++
arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 22 +
drivers/iio/adc/stm32-adc-core.c | 95 +++-
drivers/iio/adc/stm32-adc-core.h | 21 +
drivers/iio/adc/stm32-adc.c | 570 ++++++++++++++++++++-
7 files changed, 965 insertions(+), 46 deletions(-)
---
base-commit: 182c47735554925da9605dc9dd90a8c15a1bbae5
change-id: 20260911-adc-stm32mp25-v1-2ac7328559d9
Best regards,
--
Fabrice Gasnier <fabrice.gasnier@foss.st.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 01/14] dt-bindings: iio: adc: stm32-adc: add support for stm32mp23 and stm32mp25
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 02/14] iio: adc: stm32-adc: core: manage clock prescaler diversity Fabrice Gasnier
` (12 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Cheick Traore,
Olivier Moysan
Add stm32mp23 and stm32mp25 compatibles. Three ADCs can be found on
these SoCs, split into two blocks:
- ADC1 and ADC2 are tightly coupled (common registers).
- ADC3 is managed independently.
Each ADC has:
- 12-bits successive approximation analog-to-digital converter
- up to 20 single ended or differential multiplexed channels
- different trigger list, or internal channels interconnects, hence
add a dedicated compatible for each ADC1, ADC2 and ADC3.
The trigger list varies in between the two SoCs. So add a compatible for
each SoC/ADC child.
STM32 ADC may be in a power domain: allow a single 'power-domains'.
Restrict the last channel (19), as it is wired directly to ADC Vref+.
It's meaningless to have direct measurement. Internal Vref with
calibration data from bsec (nvmem) must be used instead e.g. vrefint.
Restrict deprecated properties (st,adc-channels, st,adc-diff-channels,
st,min-sample-time-nsecs).
Co-developed-by: Cheick Traore <cheick.traore-ext@st.com>
Signed-off-by: Cheick Traore <cheick.traore-ext@st.com>
Co-developed-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- Drop st,adc-trigger-sel: as discussed with Jonathan, better to
describe each ADC child with a dedicated compatible. It is robust
approach to distinguish variations in trigger list and internal
channels interconnects.
- Drop unused fallback compatible.
---
.../devicetree/bindings/iio/adc/st,stm32-adc.yaml | 71 ++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml
index c4c4575d3fa9..e7e92fd4959a 100644
--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml
@@ -28,6 +28,8 @@ properties:
- st,stm32h7-adc-core
- st,stm32mp1-adc-core
- st,stm32mp13-adc-core
+ - st,stm32mp23-adc-core
+ - st,stm32mp25-adc-core
reg:
maxItems: 1
@@ -78,6 +80,9 @@ properties:
Phandle to the vdd input voltage. It can be used to supply ADC analog
input switches on stm32mp1.
+ power-domains:
+ maxItems: 1
+
st,syscfg:
description:
Phandle to system configuration controller. It can be used to control the
@@ -215,6 +220,33 @@ allOf:
maximum: 75000000
default: 75000000
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - st,stm32mp23-adc-core
+ - st,stm32mp25-adc-core
+
+ then:
+ properties:
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: adc
+
+ interrupts:
+ items:
+ - description: interrupt line for ADC1 or ADC3
+ - description: interrupt line for ADC2
+ minItems: 1
+
+ st,max-clk-rate-hz:
+ minimum: 700000
+ maximum: 70000000
+ default: 70000000
+
additionalProperties: false
required:
@@ -244,6 +276,12 @@ patternProperties:
- st,stm32h7-adc
- st,stm32mp1-adc
- st,stm32mp13-adc
+ - st,stm32mp23-adc1
+ - st,stm32mp23-adc2
+ - st,stm32mp23-adc3
+ - st,stm32mp25-adc1
+ - st,stm32mp25-adc2
+ - st,stm32mp25-adc3
reg:
description: |
@@ -486,6 +524,39 @@ patternProperties:
maxItems: 19
items:
minimum: 40
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - st,stm32mp23-adc1
+ - st,stm32mp23-adc2
+ - st,stm32mp23-adc3
+ - st,stm32mp25-adc1
+ - st,stm32mp25-adc2
+ - st,stm32mp25-adc3
+
+ then:
+ properties:
+ reg:
+ enum:
+ - 0x0
+ - 0x100
+
+ interrupts:
+ minimum: 0
+ maximum: 1
+
+ assigned-resolution-bits:
+ enum: [6, 8, 10, 12]
+ default: 12
+
+ channel@19: false
+ st,adc-channels: false
+ st,adc-diff-channels: false
+ st,min-sample-time-nsecs: false
+
additionalProperties: false
required:
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 02/14] iio: adc: stm32-adc: core: manage clock prescaler diversity
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 01/14] dt-bindings: iio: adc: stm32-adc: " Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 03/14] iio: adc: stm32-adc: core: configurable number of interrupts Fabrice Gasnier
` (11 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier
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
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 03/14] iio: adc: stm32-adc: core: configurable number of interrupts
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 01/14] dt-bindings: iio: adc: stm32-adc: " Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 02/14] iio: adc: stm32-adc: core: manage clock prescaler diversity Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 04/14] iio: adc: stm32-adc: manage characterization voltage diversity Fabrice Gasnier
` (10 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Cheick Traore,
Olivier Moysan
Make the number of interrupts configurable to prepare stm32mp2
support. Read from the SoC compatible data, and add it to
private data struct.
No functional change intended.
Co-developed-by: Cheick Traore <cheick.traore-ext@st.com>
Signed-off-by: Cheick Traore <cheick.traore-ext@st.com>
Co-developed-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- new precursor patch as advised by Andy and Jonathan to render
num_irqs configurable
---
drivers/iio/adc/stm32-adc-core.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 14ed50bb3ab5..5845173e288c 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -94,6 +94,7 @@ struct stm32_adc_priv_cfg {
* struct stm32_adc_priv - stm32 ADC core private data
* @irq: irq(s) for ADC block
* @nb_adc_max: actual maximum number of instance per ADC block
+ * @nb_irqs: number of IRQs in the ADC block
* @domain: irq domain reference
* @aclk: clock reference for the analog circuitry
* @bclk: bus clock common for all ADCs, depends on part used
@@ -112,6 +113,7 @@ struct stm32_adc_priv_cfg {
struct stm32_adc_priv {
int irq[STM32_ADC_MAX_ADCS];
unsigned int nb_adc_max;
+ unsigned int nb_irqs;
struct irq_domain *domain;
struct clk *aclk;
struct clk *bclk;
@@ -424,7 +426,7 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
* - stm32f4/h7 shares a common interrupt line.
* - stm32mp1, has one line per ADC
*/
- for (i = 0; i < priv->cfg->num_irqs; i++) {
+ for (i = 0; i < priv->nb_irqs; i++) {
priv->irq[i] = platform_get_irq(pdev, i);
if (priv->irq[i] < 0)
return priv->irq[i];
@@ -439,7 +441,7 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
return -ENOMEM;
}
- for (i = 0; i < priv->cfg->num_irqs; i++)
+ for (i = 0; i < priv->nb_irqs; i++)
irq_set_chained_handler_and_data(priv->irq[i],
stm32_adc_irq_handler, priv);
@@ -456,7 +458,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq));
irq_domain_remove(priv->domain);
- for (i = 0; i < priv->cfg->num_irqs; i++)
+ for (i = 0; i < priv->nb_irqs; i++)
irq_set_chained_handler(priv->irq[i], NULL);
}
@@ -730,6 +732,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv->cfg = device_get_match_data(dev);
priv->nb_adc_max = priv->cfg->num_adcs;
+ priv->nb_irqs = priv->cfg->num_irqs;
spin_lock_init(&priv->common.lock);
priv->common.base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 04/14] iio: adc: stm32-adc: manage characterization voltage diversity
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (2 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 03/14] iio: adc: stm32-adc: core: configurable number of interrupts Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 05/14] iio: adc: stm32-adc: rework internal channels data Fabrice Gasnier
` (9 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Olivier Moysan
From: Olivier Moysan <olivier.moysan@foss.st.com>
The characterization voltage used to calibrate vrefint depends
on SoC family. Add vref_charac_mv field in stm32_adc_cfg structure
to store the characterization voltage for each SoC, and use it
in Vref computation formula.
Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- Andy's review comments: rename variable to vref_charac_mv (unit suffix).
Drop the const attribute.
---
drivers/iio/adc/stm32-adc.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 90f0e257e6d1..ddf74c674da6 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -43,7 +43,6 @@
#define STM32_ADC_TIMEOUT_US 100000
#define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
#define STM32_ADC_HW_STOP_DELAY_MS 100
-#define STM32_ADC_VREFINT_VOLTAGE 3300
#define STM32_DMA_BUFFER_SIZE PAGE_SIZE
@@ -211,6 +210,7 @@ struct stm32_adc;
* @set_ovs: routine to set oversampling configuration
* @smp_cycles: programmable sampling time (ADC clock cycles)
* @ts_int_ch: pointer to array of internal channels minimum sampling time in ns
+ * @vref_charac_mv: Vref characterization voltage used to measure vrefint calibration value
*/
struct stm32_adc_cfg {
const struct stm32_adc_regspec *regs;
@@ -230,6 +230,7 @@ struct stm32_adc_cfg {
void (*set_ovs)(struct iio_dev *indio_dev, u32 ovs_idx);
const unsigned int *smp_cycles;
const unsigned int *ts_int_ch;
+ int vref_charac_mv;
};
/**
@@ -1615,7 +1616,7 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
if (mask == IIO_CHAN_INFO_PROCESSED) {
if (*val == 0)
return -EINVAL;
- *val = STM32_ADC_VREFINT_VOLTAGE * adc->vrefint.vrefint_cal / *val;
+ *val = adc->cfg->vref_charac_mv * adc->vrefint.vrefint_cal / *val;
}
return ret;
@@ -2711,6 +2712,7 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = {
.stop_conv = stm32f4_adc_stop_conv,
.smp_cycles = stm32f4_adc_smp_cycles,
.irq_clear = stm32f4_adc_irq_clear,
+ .vref_charac_mv = 3300,
};
static const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 };
@@ -2732,6 +2734,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.irq_clear = stm32h7_adc_irq_clear,
.ts_int_ch = stm32_adc_min_ts_h7,
.set_ovs = stm32h7_adc_set_ovs,
+ .vref_charac_mv = 3300,
};
static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
@@ -2754,6 +2757,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.irq_clear = stm32h7_adc_irq_clear,
.ts_int_ch = stm32_adc_min_ts_mp1,
.set_ovs = stm32h7_adc_set_ovs,
+ .vref_charac_mv = 3300,
};
static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
@@ -2772,6 +2776,7 @@ static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
.irq_clear = stm32h7_adc_irq_clear,
.ts_int_ch = stm32_adc_min_ts_mp13,
.set_ovs = stm32mp13_adc_set_ovs,
+ .vref_charac_mv = 3300,
};
static const struct of_device_id stm32_adc_of_match[] = {
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 05/14] iio: adc: stm32-adc: rework internal channels data
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (3 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 04/14] iio: adc: stm32-adc: manage characterization voltage diversity Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-24 10:02 ` Fabrice Gasnier
2026-09-24 20:53 ` Andy Shevchenko
2026-09-23 15:39 ` [PATCH v2 06/14] iio: adc: stm32-adc: add vreg enable option to manage diversity Fabrice Gasnier
` (8 subsequent siblings)
13 siblings, 2 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier
Diversity in internal channels data array lead to have zeroed data.
To facilitate addition of new internal channels, without touching
all array initializers, only focus on exiting channels on each
supported ADC variant (e.g. each SoC).
This also allows to get rid of static_assert() checks.
No functional change intended.
Cosmetic update: remove comma on STM32_ADC_INT_CH_NB as it should
always be the last element.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- new precursor patch as suggested by Jonathan
---
drivers/iio/adc/stm32-adc.c | 51 +++++++++++++++++++++++----------------------
1 file changed, 26 insertions(+), 25 deletions(-)
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index ddf74c674da6..ac60c31de7a5 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -86,25 +86,16 @@ enum stm32_adc_int_ch {
STM32_ADC_INT_CH_VDDQ_DDR,
STM32_ADC_INT_CH_VREFINT,
STM32_ADC_INT_CH_VBAT,
- STM32_ADC_INT_CH_NB,
+ STM32_ADC_INT_CH_NB
};
-/**
- * struct stm32_adc_ic - ADC internal channels
- * @name: name of the internal channel
- * @idx: internal channel enum index
- */
-struct stm32_adc_ic {
- const char *name;
- u32 idx;
-};
-
-static const struct stm32_adc_ic stm32_adc_ic[STM32_ADC_INT_CH_NB] = {
- { "vddcore", STM32_ADC_INT_CH_VDDCORE },
- { "vddcpu", STM32_ADC_INT_CH_VDDCPU },
- { "vddq_ddr", STM32_ADC_INT_CH_VDDQ_DDR },
- { "vrefint", STM32_ADC_INT_CH_VREFINT },
- { "vbat", STM32_ADC_INT_CH_VBAT },
+/* STM32 ADC internal channel names */
+static const char stm32_adc_ic[STM32_ADC_INT_CH_NB][STM32_ADC_CH_SZ] = {
+ [STM32_ADC_INT_CH_VDDCORE] = "vddcore",
+ [STM32_ADC_INT_CH_VDDCPU] = "vddcpu",
+ [STM32_ADC_INT_CH_VDDQ_DDR] = "vddq_ddr",
+ [STM32_ADC_INT_CH_VREFINT] = "vrefint",
+ [STM32_ADC_INT_CH_VBAT] = "vbat",
};
/**
@@ -2268,7 +2259,7 @@ static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_n
int i, ret;
for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
- if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) {
+ if (!strncmp(stm32_adc_ic[i], ch_name, STM32_ADC_CH_SZ)) {
bool na;
/* Check internal channel availability */
@@ -2302,7 +2293,7 @@ static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_n
return 0;
}
- if (stm32_adc_ic[i].idx != STM32_ADC_INT_CH_VREFINT) {
+ if (i != STM32_ADC_INT_CH_VREFINT) {
adc->int_ch[i] = chan;
break;
}
@@ -2715,8 +2706,10 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = {
.vref_charac_mv = 3300,
};
-static const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 };
-static_assert(ARRAY_SIZE(stm32_adc_min_ts_h7) == STM32_ADC_INT_CH_NB);
+static const unsigned int stm32_adc_min_ts_h7[STM32_ADC_INT_CH_NB] = {
+ [STM32_ADC_INT_CH_VREFINT] = 4300,
+ [STM32_ADC_INT_CH_VBAT] = 9000
+};
static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.regs = &stm32h7_adc_regspec,
@@ -2737,8 +2730,11 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.vref_charac_mv = 3300,
};
-static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
-static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB);
+static const unsigned int stm32_adc_min_ts_mp1[STM32_ADC_INT_CH_NB] = {
+ [STM32_ADC_INT_CH_VDDCORE] = 100,
+ [STM32_ADC_INT_CH_VREFINT] = 4300,
+ [STM32_ADC_INT_CH_VBAT] = 9800
+};
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.regs = &stm32mp1_adc_regspec,
@@ -2760,8 +2756,13 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.vref_charac_mv = 3300,
};
-static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
-static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB);
+static const unsigned int stm32_adc_min_ts_mp13[STM32_ADC_INT_CH_NB] = {
+ [STM32_ADC_INT_CH_VDDCORE] = 1000,
+ [STM32_ADC_INT_CH_VDDCPU] = 1000,
+ [STM32_ADC_INT_CH_VDDQ_DDR] = 1000,
+ [STM32_ADC_INT_CH_VREFINT] = 4300,
+ [STM32_ADC_INT_CH_VBAT] = 9800
+};
static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
.regs = &stm32mp13_adc_regspec,
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 06/14] iio: adc: stm32-adc: add vreg enable option to manage diversity
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (4 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 05/14] iio: adc: stm32-adc: rework internal channels data Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 07/14] iio: adc: stm32-adc: add support for stm32mp25 Fabrice Gasnier
` (7 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Cheick Traore
Add a boolean (has_vregen) in adc configuration structure to prevent
setting the reserved bit (CR_ADVREGEN bit 28) on STM32MP2 SoCs.
This bit is present on earlier stm32h7, stm32mp13 and stm32mp15.
No functional change intended.
Co-developed-by: Cheick Traore <cheick.traore-ext@st.com>
Signed-off-by: Cheick Traore <cheick.traore-ext@st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- new precursor patch, e.g. split as suggested by Andy and Jonathan, to
prepare the infrastructure for stm32mp23/25 support.
---
drivers/iio/adc/stm32-adc.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index ac60c31de7a5..eecdc4cce1b4 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -193,6 +193,7 @@ struct stm32_adc;
* @has_linearcal: linear calibration support flag
* @has_presel: channel preselection support flag
* @has_oversampling: oversampling support flag
+ * @has_vregen: voltage regulator enable/disable flag
* @prepare: optional prepare routine (power-up, enable)
* @start_conv: routine to start conversions
* @stop_conv: routine to stop conversions
@@ -213,6 +214,7 @@ struct stm32_adc_cfg {
bool has_linearcal;
bool has_presel;
bool has_oversampling;
+ bool has_vregen;
int (*prepare)(struct iio_dev *);
void (*start_conv)(struct iio_dev *, bool dma);
void (*stop_conv)(struct iio_dev *);
@@ -961,7 +963,8 @@ static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
/* Exit deep power down, then enable ADC voltage regulator */
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
- stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN);
+ if (adc->cfg->has_vregen)
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN);
if (adc->cfg->has_boostmode &&
adc->common->rate > STM32H7_BOOST_CLKRATE)
@@ -2719,6 +2722,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.has_linearcal = true,
.has_presel = true,
.has_oversampling = true,
+ .has_vregen = true,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
@@ -2745,6 +2749,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.has_linearcal = true,
.has_presel = true,
.has_oversampling = true,
+ .has_vregen = true,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
@@ -2769,6 +2774,7 @@ static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
.adc_info = &stm32mp13_adc_info,
.trigs = stm32h7_adc_trigs,
.has_oversampling = true,
+ .has_vregen = true,
.start_conv = stm32mp13_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 07/14] iio: adc: stm32-adc: add support for stm32mp25
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (5 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 06/14] iio: adc: stm32-adc: add vreg enable option to manage diversity Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-24 21:01 ` Andy Shevchenko
2026-09-23 15:39 ` [PATCH v2 08/14] iio: adc: stm32-adc: add support for stm32mp23 Fabrice Gasnier
` (6 subsequent siblings)
13 siblings, 1 reply; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Cheick Traore,
Olivier Moysan
Add support for ADC on STM32MP25 SoC. It has 3 ADCs, split into two blocks:
- ADC1 & ADC2 are tightly coupled.
- ADC3 is managed independently.
Trigger list slightly changes between these blocks (ADC1 & ADC2). Other
differences are found on channels interconnects (similar between ADC2
and ADC3):
- ADC1 is connected to 18 external channels + 2 internal channels
- ADC2 is connected to 14 external channels + 6 internal channels
- ADC3 is connected to 14 external channels + 6 internal channels
Each ADC is a 12-bits successive approximation analog-to-digital converter,
with up to 20 multiplexed channels that can be configured as single ended
or differential. ADC resolution ranges from 6 to 12 bits.
It introduces diversity regarding IRQs, clocks, software calibration
procedure, internal voltage channels, sampling time (prescaler) and
trigger list. Most of the architecture, and the driver engine remains
similar. So, handle the differences w.r.t. other STM32 ADCs family with
a dedicated compatible and compatible data.
Co-developed-by: Cheick Traore <cheick.traore-ext@st.com>
Signed-off-by: Cheick Traore <cheick.traore-ext@st.com>
Co-developed-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- Split as advised by Jonathan and Andy. Added precursor patches to
prepare all the infrastructure. Keep only the new hardware support.
- Adopt separate compatible for ADC1, ADC2 and ADC3 to better describe
internal channels (split regs descriptions) and trigger list. Drop
"st,adc-trigger-sel".
- Cosmetic updates whilst at it: remove trailing comma
- Refactor calibration routine, to avoid twisted goto chain, as advised
by Andy
- One patch per new SoC
---
drivers/iio/adc/stm32-adc-core.c | 43 ++++-
drivers/iio/adc/stm32-adc-core.h | 20 +++
drivers/iio/adc/stm32-adc.c | 372 +++++++++++++++++++++++++++++++++++++++
3 files changed, 434 insertions(+), 1 deletion(-)
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 5845173e288c..7027d86f7457 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -138,6 +138,9 @@ static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com)
/* STM32F4 ADC internal common clock prescaler division ratios */
static unsigned int stm32f4_pclk_div[] = { 2, 4, 6, 8 };
+/* STM32MP25 ADC internal common clock prescaler division ratios */
+static unsigned int stm32mp25_presc_div[] = { 1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256 };
+
/**
* stm32_adc_clk_sel() - Select stm32f4 ADC common clock prescaler
* @pdev: platform device
@@ -348,6 +351,18 @@ static const struct stm32_adc_common_regs stm32mp13_adc_common_regs = {
.eocie_msk = STM32H7_EOCIE,
};
+/* STM32MP25 common registers definitions */
+static const struct stm32_adc_common_regs stm32mp25_adc_common_regs = {
+ .csr = STM32H7_ADC_CSR,
+ .ccr = STM32H7_ADC_CCR,
+ .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV},
+ .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV},
+ .ier = STM32H7_ADC_IER,
+ .eocie_msk = STM32H7_EOCIE,
+ .presc_msk = STM32H7_PRESC_MASK,
+ .presc_shift = STM32H7_PRESC_SHIFT,
+};
+
static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = {
0, STM32_ADC_OFFSET, STM32_ADC_OFFSET * 2,
};
@@ -425,6 +440,8 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
* Interrupt(s) must be provided, depending on the compatible:
* - stm32f4/h7 shares a common interrupt line.
* - stm32mp1, has one line per ADC
+ * - stm32mp25, has a dual ADC1/ADC2 and standalone ADC3. Each ADC has an IRQ
+ * (two for ADC1/ADC2, one for ADC3)
*/
for (i = 0; i < priv->nb_irqs; i++) {
priv->irq[i] = platform_get_irq(pdev, i);
@@ -705,6 +722,17 @@ static int stm32_adc_probe_identification(struct platform_device *pdev,
return -EINVAL;
}
+ if (priv->cfg->ipid == STM32MP25_IPIDR_NUMBER) {
+ /*
+ * ADC diversity on STM32MP25 is handled here. There may be:
+ * - 2 IRQs for ADC1/ADC2 block
+ * - 1 IRQ for ADC3 block.
+ * There cannot be more IRQs than the actual number of ADCs.
+ */
+ if (priv->nb_irqs > priv->nb_adc_max)
+ priv->nb_irqs = priv->nb_adc_max;
+ }
+
val = readl_relaxed(priv->common.base + STM32MP1_ADC_VERR);
dev_dbg(&pdev->dev, "ADC version: %lu.%lu\n",
FIELD_GET(STM32MP1_MAJREV_MASK, val),
@@ -897,6 +925,16 @@ static const struct stm32_adc_priv_cfg stm32mp13_adc_priv_cfg = {
.num_irqs = 1,
};
+static const struct stm32_adc_priv_cfg stm32mp25_adc_priv_cfg = {
+ .regs = &stm32mp25_adc_common_regs,
+ .clk_sel = stm32_adc_clk_sel,
+ .presc = stm32mp25_presc_div,
+ .num_presc = ARRAY_SIZE(stm32mp25_presc_div),
+ .max_clk_rate_hz = 70000000,
+ .ipid = STM32MP25_IPIDR_NUMBER,
+ .num_irqs = 2, /* 2 IRQs for ADC1/ADC2, 1 irq for ADC3 */
+};
+
static const struct of_device_id stm32_adc_of_match[] = {
{
.compatible = "st,stm32f4-adc-core",
@@ -911,7 +949,10 @@ static const struct of_device_id stm32_adc_of_match[] = {
.compatible = "st,stm32mp13-adc-core",
.data = (void *)&stm32mp13_adc_priv_cfg
}, {
- },
+ .compatible = "st,stm32mp25-adc-core",
+ .data = (void *)&stm32mp25_adc_priv_cfg
+ }, {
+ }
};
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index db50a9f3b922..68b937e3819f 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -121,6 +121,9 @@
#define STM32MP13_ADC_CALFACT 0xB4
#define STM32MP13_ADC2_OR 0xC8
+/* STM32MP25 - ADC2 and ADC3 option register */
+#define STM32MP25_ADC23_OR 0xD0
+
/* STM32H7 - common registers for all ADC instances */
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
@@ -257,8 +260,25 @@ enum stm32h7_adc_dmngt {
#define STM32MP13_OP1 BIT(1)
#define STM32MP13_OP0 BIT(0)
+/* STM32MP25 - Registers for each ADC instance */
+#define STM32MP25_ADC_CALFACT 0xC4
+
+/* STM32MP25_ADC_CALFACT - bit fields */
+#define STM32MP25_CALFACT_CALADDOS BIT(31)
+#define STM32MP25_CALFACT_D_MASK GENMASK(24, 16)
+#define STM32MP25_CALFACT_S_MASK GENMASK(8, 0)
+
+/* STM32MP25_ADC_CFGR specific bit fields */
+#define STM32MP25_RES_SHIFT 2
+#define STM32MP25_RES_MASK GENMASK(3, 2)
+
+/* STM32MP25_ADC23_OR - specific bit fields */
+#define STM32MP25_VDDCPUEN BIT(3)
+#define STM32MP25_VDDCOREEN BIT(2)
+
#define STM32MP15_IPIDR_NUMBER 0x00110005
#define STM32MP13_IPIDR_NUMBER 0x00110006
+#define STM32MP25_IPIDR_NUMBER 0x00110008
/**
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index eecdc4cce1b4..a5bffc09898b 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -33,6 +33,9 @@
/* Number of linear calibration shadow registers / LINCALRDYW control bits */
#define STM32H7_LINCALFACT_NUM 6
+/* Number of loops in the calibration procedure to average data on STM32MP25 */
+#define STM32MP25_CALIB_LOOP 8
+
/* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */
#define STM32H7_BOOST_CLKRATE 20000000UL
@@ -77,6 +80,14 @@ enum stm32_adc_extsel {
STM32_EXT18,
STM32_EXT19,
STM32_EXT20,
+ STM32_EXT21,
+ STM32_EXT22,
+ STM32_EXT23,
+ STM32_EXT24,
+ STM32_EXT25,
+ STM32_EXT26,
+ STM32_EXT27,
+ STM32_EXT28
};
enum stm32_adc_int_ch {
@@ -348,6 +359,20 @@ static const struct stm32_adc_info stm32mp13_adc_info = {
.num_ovs = ARRAY_SIZE(stm32mp13_adc_oversampling_avail),
};
+/*
+ * stm32mp25 can have up to 20 channels.
+ * Keep channel 19 (VREF+) hidden on STM32MP25: it is the ADC reference
+ * supply itself, so exposing it as a regular input is meaningless.
+ * Reference voltage must be derived from VREFINT with calibration data.
+ */
+static const struct stm32_adc_info stm32mp25_adc_info = {
+ .max_channels = STM32_ADC_CH_MAX - 1,
+ .resolutions = stm32f4_adc_resolutions,
+ .oversampling = stm32h7_adc_oversampling_avail,
+ .num_res = ARRAY_SIZE(stm32f4_adc_resolutions),
+ .num_ovs = ARRAY_SIZE(stm32h7_adc_oversampling_avail),
+};
+
/*
* stm32f4_sq - describe regular sequence registers
* - L: sequence len (register & bit field)
@@ -538,6 +563,114 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
.smp_bits = stm32h7_smp_bits,
};
+/* STM32MP25 external trigger sources for ADC1 and ADC2 */
+static struct stm32_adc_trig_info stm32mp25_adc1_adc2_trigs[] = {
+ { TIM1_TRGO, STM32_EXT0 },
+ { TIM1_TRGO2, STM32_EXT1 },
+ { TIM8_TRGO, STM32_EXT2 },
+ { TIM8_TRGO2, STM32_EXT3 },
+ { TIM20_TRGO, STM32_EXT4 },
+ { TIM20_TRGO2, STM32_EXT5 },
+ { TIM2_TRGO, STM32_EXT6 },
+ { TIM3_TRGO, STM32_EXT7 },
+ { TIM4_TRGO, STM32_EXT8 },
+ { TIM5_TRGO, STM32_EXT9 },
+ { TIM6_TRGO, STM32_EXT10 },
+ { TIM15_TRGO, STM32_EXT11 },
+ { TIM1_CH1, STM32_EXT12 },
+ { TIM1_CH2, STM32_EXT13 },
+ { TIM1_CH3, STM32_EXT14 },
+ { TIM20_OC1, STM32_EXT15 },
+ { TIM20_OC2, STM32_EXT16 },
+ { TIM20_OC3, STM32_EXT17 },
+ { TIM2_CH2, STM32_EXT18 },
+ { TIM3_CH4, STM32_EXT19 },
+ { TIM4_CH4, STM32_EXT20 },
+ { TIM5_CH1, STM32_EXT21 },
+ { TIM12_CH1, STM32_EXT22 },
+ { LPTIM1_CH1, STM32_EXT24 },
+ { LPTIM2_CH1, STM32_EXT25 },
+ { LPTIM3_CH1, STM32_EXT26 },
+ { LPTIM4_CH1, STM32_EXT27 },
+ { LPTIM5_OUT, STM32_EXT28 },
+ { }
+};
+
+/* STM32MP25 external trigger sources for ADC3 */
+static struct stm32_adc_trig_info stm32mp25_adc3_trigs[] = {
+ { TIM1_TRGO, STM32_EXT0 },
+ { TIM1_TRGO2, STM32_EXT1 },
+ { TIM8_TRGO, STM32_EXT2 },
+ { TIM8_TRGO2, STM32_EXT3 },
+ { TIM20_TRGO, STM32_EXT4 },
+ { TIM20_TRGO2, STM32_EXT5 },
+ { TIM2_TRGO, STM32_EXT6 },
+ { TIM3_TRGO, STM32_EXT7 },
+ { TIM4_TRGO, STM32_EXT8 },
+ { TIM5_TRGO, STM32_EXT9 },
+ { TIM6_TRGO, STM32_EXT10 },
+ { TIM7_TRGO, STM32_EXT11 },
+ { TIM15_TRGO, STM32_EXT12 },
+ { TIM17_OC1, STM32_EXT13 },
+ { TIM1_CH3, STM32_EXT14 },
+ { TIM8_CH1, STM32_EXT15 },
+ { TIM20_OC1, STM32_EXT16 },
+ { TIM2_CH1, STM32_EXT17 },
+ { TIM2_CH3, STM32_EXT18 },
+ { TIM3_CH1, STM32_EXT19 },
+ { TIM4_CH1, STM32_EXT20 },
+ { TIM5_CH3, STM32_EXT21 },
+ { TIM12_CH1, STM32_EXT22 },
+ { LPTIM1_CH1, STM32_EXT24 },
+ { LPTIM2_CH1, STM32_EXT25 },
+ { LPTIM3_CH1, STM32_EXT26 },
+ { LPTIM4_CH1, STM32_EXT27 },
+ { LPTIM5_OUT, STM32_EXT28 },
+ { }
+};
+
+/* STM32MP25 programmable sampling time (ADC clock cycles, rounded down) */
+static const unsigned int stm32mp25_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
+ 2, 3, 7, 12, 24, 47, 247, 1501,
+};
+
+static const struct stm32_adc_regspec stm32mp25_adc1_regspec = {
+ .dr = STM32H7_ADC_DR,
+ .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
+ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
+ .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
+ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
+ .sqr = stm32h7_sq,
+ .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
+ .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
+ STM32H7_EXTSEL_SHIFT },
+ .res = { STM32H7_ADC_CFGR, STM32MP25_RES_MASK, STM32MP25_RES_SHIFT },
+ .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK},
+ .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
+ .smp_bits = stm32h7_smp_bits,
+ .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
+};
+
+static const struct stm32_adc_regspec stm32mp25_adc2_adc3_regspec = {
+ .dr = STM32H7_ADC_DR,
+ .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
+ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
+ .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
+ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
+ .sqr = stm32h7_sq,
+ .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
+ .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
+ STM32H7_EXTSEL_SHIFT },
+ .res = { STM32H7_ADC_CFGR, STM32MP25_RES_MASK, STM32MP25_RES_SHIFT },
+ .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK},
+ .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
+ .smp_bits = stm32h7_smp_bits,
+ .or_vddcore = { STM32MP25_ADC23_OR, STM32MP25_VDDCOREEN },
+ .or_vddcpu = { STM32MP25_ADC23_OR, STM32MP25_VDDCPUEN },
+ .ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
+ .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
+};
+
/* STM32MP13 programmable sampling time (ADC clock cycles, rounded down) */
static const unsigned int stm32mp13_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
2, 6, 12, 24, 47, 92, 247, 640,
@@ -1304,6 +1437,184 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev)
stm32h7_adc_enter_pwr_down(adc);
}
+/*
+ * STM32MP25 offset calibration software procedure. Basically the calibration routine is
+ * expected to average (for example) 8 samples in calibration mode, for single-ended and
+ * differential channels, to calibrate the zero offset. In case offset is "negative", an
+ * additional offset can be added, to determine calibration factor. It must be kept later
+ * for all conversions.
+ */
+static int stm32mp25_adc_calib_get_average_data(struct iio_dev *indio_dev, u32 *average)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ const struct stm32_adc_regspec *regs = adc->cfg->regs;
+ u32 val, avg = 0;
+ int ret;
+
+ /* Repeat several conversions in calibration mode, average the results */
+ for (unsigned int i = 0; i < STM32MP25_CALIB_LOOP; i++) {
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTART);
+ ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val,
+ !(val & (STM32H7_ADSTART)),
+ 100, STM32_ADC_TIMEOUT_US);
+ if (ret) {
+ dev_err(&indio_dev->dev, "calibration average error %d\n", ret);
+ return ret;
+ }
+
+ val = stm32_adc_readl(adc, regs->dr);
+ dev_vdbg(&indio_dev->dev, "dr[%d]=0x%08x\n", i, val);
+ avg += val;
+ }
+
+ *average = DIV_ROUND_CLOSEST(avg, STM32MP25_CALIB_LOOP);
+ dev_vdbg(&indio_dev->dev, "average=0x%08x\n", *average);
+
+ return 0;
+}
+
+static int stm32mp25_adc_calib_single_ended_offset(struct iio_dev *indio_dev, bool *add_offset)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ u32 average;
+ int ret;
+
+ /* Select single ended input calibration */
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALDIF);
+
+retry:
+ /* Clears or set CALADDOS (also clear old calibration data if any) */
+ stm32_adc_writel(adc, STM32MP25_ADC_CALFACT,
+ FIELD_PREP(STM32MP25_CALFACT_CALADDOS, *add_offset));
+
+ ret = stm32mp25_adc_calib_get_average_data(indio_dev, &average);
+ if (ret)
+ return ret;
+
+ /* Add offset and retry single-ended calibration if the averaged data is zero */
+ if (!average && !*add_offset) {
+ *add_offset = true;
+ goto retry;
+ }
+
+ if (!average) {
+ /* If average data is still zero with additional offset, just warn about it */
+ dev_warn(&indio_dev->dev, "Single-ended calibration average: 0\n");
+ } else {
+ u32 calfact = stm32_adc_readl(adc, STM32MP25_ADC_CALFACT);
+
+ calfact |= FIELD_PREP(STM32MP25_CALFACT_S_MASK, average);
+ stm32_adc_writel(adc, STM32MP25_ADC_CALFACT, calfact);
+ }
+
+ return 0;
+}
+
+static int stm32mp25_adc_calib(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ bool add_offset = false;
+ bool diff_below_zero;
+ u32 average, calfact;
+ int ret;
+
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
+ /* Use default resolution (e.g. 12 bits) */
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32MP25_RES_MASK);
+
+retry:
+ /* Single ended input calibration */
+ ret = stm32mp25_adc_calib_single_ended_offset(indio_dev, &add_offset);
+ if (ret)
+ goto out;
+
+ /* Differential input calibration (keep previous CALADDOS value) */
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALDIF);
+ ret = stm32mp25_adc_calib_get_average_data(indio_dev, &average);
+ if (ret)
+ goto out;
+
+ /* Averaged diff data is below 0x800 (half value in 12-bits mode) */
+ diff_below_zero = average < BIT(adc->cfg->adc_info->resolutions[0] - 1);
+
+ if (diff_below_zero && !add_offset) {
+ /* Retry the whole calibration with additional offset */
+ add_offset = true;
+ goto retry;
+ }
+
+ calfact = stm32_adc_readl(adc, STM32MP25_ADC_CALFACT);
+
+ if (diff_below_zero) {
+ /*
+ * Averaged data is still below center value. It needs to be clamped to zero,
+ * so don't use the result here, warn about it.
+ */
+ dev_warn(&indio_dev->dev, "Differential calibration clamped(0): 0x%x\n", average);
+ } else {
+ calfact |= FIELD_PREP(STM32MP25_CALFACT_D_MASK, average);
+ stm32_adc_writel(adc, STM32MP25_ADC_CALFACT, calfact);
+ }
+
+ dev_dbg(&indio_dev->dev, "set calfact_s=0x%03lx, calfact_d=0x%03lx, calados=%ld\n",
+ FIELD_GET(STM32MP25_CALFACT_S_MASK, calfact),
+ FIELD_GET(STM32MP25_CALFACT_D_MASK, calfact),
+ FIELD_GET(STM32MP25_CALFACT_CALADDOS, calfact));
+out:
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
+ stm32_adc_set_res(adc);
+
+ return ret;
+}
+
+static int stm32mp25_adc_prepare(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ int ret;
+
+ ret = stm32h7_adc_exit_pwr_down(indio_dev);
+ if (ret)
+ return ret;
+
+ /* Must enable the ADC before running software-assisted calibration */
+ ret = stm32h7_adc_enable(indio_dev);
+ if (ret)
+ goto pwr_dwn;
+
+ /* Always run offset calibration */
+ ret = stm32mp25_adc_calib(indio_dev);
+ if (ret)
+ goto adc_dis;
+
+ stm32_adc_int_ch_enable(indio_dev);
+
+ stm32_adc_writel(adc, adc->cfg->regs->difsel.reg, adc->difsel);
+
+ if (adc->cfg->has_presel)
+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel);
+
+ return 0;
+
+adc_dis:
+ stm32h7_adc_disable(indio_dev);
+pwr_dwn:
+ stm32h7_adc_enter_pwr_down(adc);
+
+ return ret;
+}
+
+static void stm32mp25_adc_unprepare(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+
+ /* Undo things in the reverse order */
+ if (adc->cfg->has_presel)
+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
+ stm32_adc_int_ch_disable(adc);
+ stm32h7_adc_disable(indio_dev);
+ stm32h7_adc_enter_pwr_down(adc);
+}
+
/**
* stm32_adc_conf_scan_seq() - Build regular channels scan sequence
* @indio_dev: IIO device
@@ -2786,11 +3097,72 @@ static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
.vref_charac_mv = 3300,
};
+static const unsigned int stm32_adc_min_ts_mp25[STM32_ADC_INT_CH_NB] = {
+ [STM32_ADC_INT_CH_VDDCORE] = 34,
+ [STM32_ADC_INT_CH_VDDCPU] = 34,
+ [STM32_ADC_INT_CH_VREFINT] = 34,
+ [STM32_ADC_INT_CH_VBAT] = 34,
+};
+
+static const struct stm32_adc_cfg stm32mp25_adc1_cfg = {
+ .regs = &stm32mp25_adc1_regspec,
+ .adc_info = &stm32mp25_adc_info,
+ .trigs = stm32mp25_adc1_adc2_trigs,
+ .has_oversampling = true,
+ .has_presel = true,
+ .start_conv = stm32h7_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32mp25_adc_prepare,
+ .unprepare = stm32mp25_adc_unprepare,
+ .smp_cycles = stm32mp25_adc_smp_cycles,
+ .irq_clear = stm32h7_adc_irq_clear,
+ .set_ovs = stm32h7_adc_set_ovs,
+ .ts_int_ch = stm32_adc_min_ts_mp25,
+ .vref_charac_mv = 1800,
+};
+
+static const struct stm32_adc_cfg stm32mp25_adc2_cfg = {
+ .regs = &stm32mp25_adc2_adc3_regspec,
+ .adc_info = &stm32mp25_adc_info,
+ .trigs = stm32mp25_adc1_adc2_trigs,
+ .has_oversampling = true,
+ .has_presel = true,
+ .start_conv = stm32h7_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32mp25_adc_prepare,
+ .unprepare = stm32mp25_adc_unprepare,
+ .smp_cycles = stm32mp25_adc_smp_cycles,
+ .irq_clear = stm32h7_adc_irq_clear,
+ .set_ovs = stm32h7_adc_set_ovs,
+ .ts_int_ch = stm32_adc_min_ts_mp25,
+ .vref_charac_mv = 1800,
+};
+
+static const struct stm32_adc_cfg stm32mp25_adc3_cfg = {
+ .regs = &stm32mp25_adc2_adc3_regspec,
+ .adc_info = &stm32mp25_adc_info,
+ .trigs = stm32mp25_adc3_trigs,
+ .has_oversampling = true,
+ .has_presel = true,
+ .start_conv = stm32h7_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32mp25_adc_prepare,
+ .unprepare = stm32mp25_adc_unprepare,
+ .smp_cycles = stm32mp25_adc_smp_cycles,
+ .irq_clear = stm32h7_adc_irq_clear,
+ .set_ovs = stm32h7_adc_set_ovs,
+ .ts_int_ch = stm32_adc_min_ts_mp25,
+ .vref_charac_mv = 1800,
+};
+
static const struct of_device_id stm32_adc_of_match[] = {
{ .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg },
{ .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg },
{ .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg },
{ .compatible = "st,stm32mp13-adc", .data = (void *)&stm32mp13_adc_cfg },
+ { .compatible = "st,stm32mp25-adc1", .data = (void *)&stm32mp25_adc1_cfg },
+ { .compatible = "st,stm32mp25-adc2", .data = (void *)&stm32mp25_adc2_cfg },
+ { .compatible = "st,stm32mp25-adc3", .data = (void *)&stm32mp25_adc3_cfg },
{ }
};
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 08/14] iio: adc: stm32-adc: add support for stm32mp23
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (6 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 07/14] iio: adc: stm32-adc: add support for stm32mp25 Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 09/14] iio: adc: stm32: add support for vddgpu on stm32mp23 and stm32mp25 Fabrice Gasnier
` (5 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Cheick Traore,
Olivier Moysan
Add support for ADC on STM32MP23 SoC. It has 3 ADCs, split into two blocks:
- ADC1 & ADC2 are tightly coupled.
- ADC3 is managed independently.
It is quite similar to STM32MP25 ADC, except for the trigger list. TIM20
triggers have been removed. So, handle the differences with a dedicated
compatible and compatible data.
Co-developed-by: Cheick Traore <cheick.traore-ext@st.com>
Signed-off-by: Cheick Traore <cheick.traore-ext@st.com>
Co-developed-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- New patch, split as advised by Andy: one patch for this new SoC
---
drivers/iio/adc/stm32-adc-core.c | 3 ++
drivers/iio/adc/stm32-adc.c | 112 +++++++++++++++++++++++++++++++++++++++
2 files changed, 115 insertions(+)
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 7027d86f7457..418846f736ba 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -948,6 +948,9 @@ static const struct of_device_id stm32_adc_of_match[] = {
}, {
.compatible = "st,stm32mp13-adc-core",
.data = (void *)&stm32mp13_adc_priv_cfg
+ }, {
+ .compatible = "st,stm32mp23-adc-core",
+ .data = (void *)&stm32mp25_adc_priv_cfg
}, {
.compatible = "st,stm32mp25-adc-core",
.data = (void *)&stm32mp25_adc_priv_cfg
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index a5bffc09898b..a14f858299ae 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -563,6 +563,64 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
.smp_bits = stm32h7_smp_bits,
};
+/* STM32MP23 external trigger sources for ADC1 and ADC2 */
+static struct stm32_adc_trig_info stm32mp23_adc1_adc2_trigs[] = {
+ { TIM1_TRGO, STM32_EXT0 },
+ { TIM1_TRGO2, STM32_EXT1 },
+ { TIM8_TRGO, STM32_EXT2 },
+ { TIM8_TRGO2, STM32_EXT3 },
+ { TIM2_TRGO, STM32_EXT6 },
+ { TIM3_TRGO, STM32_EXT7 },
+ { TIM4_TRGO, STM32_EXT8 },
+ { TIM5_TRGO, STM32_EXT9 },
+ { TIM6_TRGO, STM32_EXT10 },
+ { TIM15_TRGO, STM32_EXT11 },
+ { TIM1_CH1, STM32_EXT12 },
+ { TIM1_CH2, STM32_EXT13 },
+ { TIM1_CH3, STM32_EXT14 },
+ { TIM2_CH2, STM32_EXT18 },
+ { TIM3_CH4, STM32_EXT19 },
+ { TIM4_CH4, STM32_EXT20 },
+ { TIM5_CH1, STM32_EXT21 },
+ { TIM12_CH1, STM32_EXT22 },
+ { LPTIM1_CH1, STM32_EXT24 },
+ { LPTIM2_CH1, STM32_EXT25 },
+ { LPTIM3_CH1, STM32_EXT26 },
+ { LPTIM4_CH1, STM32_EXT27 },
+ { LPTIM5_OUT, STM32_EXT28 },
+ { }
+};
+
+/* STM32MP23 external trigger sources for ADC3 */
+static struct stm32_adc_trig_info stm32mp23_adc3_trigs[] = {
+ { TIM1_TRGO, STM32_EXT0 },
+ { TIM1_TRGO2, STM32_EXT1 },
+ { TIM8_TRGO, STM32_EXT2 },
+ { TIM8_TRGO2, STM32_EXT3 },
+ { TIM2_TRGO, STM32_EXT6 },
+ { TIM3_TRGO, STM32_EXT7 },
+ { TIM4_TRGO, STM32_EXT8 },
+ { TIM5_TRGO, STM32_EXT9 },
+ { TIM6_TRGO, STM32_EXT10 },
+ { TIM7_TRGO, STM32_EXT11 },
+ { TIM15_TRGO, STM32_EXT12 },
+ { TIM17_OC1, STM32_EXT13 },
+ { TIM1_CH3, STM32_EXT14 },
+ { TIM8_CH1, STM32_EXT15 },
+ { TIM2_CH1, STM32_EXT17 },
+ { TIM2_CH3, STM32_EXT18 },
+ { TIM3_CH1, STM32_EXT19 },
+ { TIM4_CH1, STM32_EXT20 },
+ { TIM5_CH3, STM32_EXT21 },
+ { TIM12_CH1, STM32_EXT22 },
+ { LPTIM1_CH1, STM32_EXT24 },
+ { LPTIM2_CH1, STM32_EXT25 },
+ { LPTIM3_CH1, STM32_EXT26 },
+ { LPTIM4_CH1, STM32_EXT27 },
+ { LPTIM5_OUT, STM32_EXT28 },
+ { }
+};
+
/* STM32MP25 external trigger sources for ADC1 and ADC2 */
static struct stm32_adc_trig_info stm32mp25_adc1_adc2_trigs[] = {
{ TIM1_TRGO, STM32_EXT0 },
@@ -3104,6 +3162,57 @@ static const unsigned int stm32_adc_min_ts_mp25[STM32_ADC_INT_CH_NB] = {
[STM32_ADC_INT_CH_VBAT] = 34,
};
+static const struct stm32_adc_cfg stm32mp23_adc1_cfg = {
+ .regs = &stm32mp25_adc1_regspec,
+ .adc_info = &stm32mp25_adc_info,
+ .trigs = stm32mp23_adc1_adc2_trigs,
+ .has_oversampling = true,
+ .has_presel = true,
+ .start_conv = stm32h7_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32mp25_adc_prepare,
+ .unprepare = stm32mp25_adc_unprepare,
+ .smp_cycles = stm32mp25_adc_smp_cycles,
+ .irq_clear = stm32h7_adc_irq_clear,
+ .set_ovs = stm32h7_adc_set_ovs,
+ .ts_int_ch = stm32_adc_min_ts_mp25,
+ .vref_charac_mv = 1800,
+};
+
+static const struct stm32_adc_cfg stm32mp23_adc2_cfg = {
+ .regs = &stm32mp25_adc2_adc3_regspec,
+ .adc_info = &stm32mp25_adc_info,
+ .trigs = stm32mp23_adc1_adc2_trigs,
+ .has_oversampling = true,
+ .has_presel = true,
+ .start_conv = stm32h7_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32mp25_adc_prepare,
+ .unprepare = stm32mp25_adc_unprepare,
+ .smp_cycles = stm32mp25_adc_smp_cycles,
+ .irq_clear = stm32h7_adc_irq_clear,
+ .set_ovs = stm32h7_adc_set_ovs,
+ .ts_int_ch = stm32_adc_min_ts_mp25,
+ .vref_charac_mv = 1800,
+};
+
+static const struct stm32_adc_cfg stm32mp23_adc3_cfg = {
+ .regs = &stm32mp25_adc2_adc3_regspec,
+ .adc_info = &stm32mp25_adc_info,
+ .trigs = stm32mp23_adc3_trigs,
+ .has_oversampling = true,
+ .has_presel = true,
+ .start_conv = stm32h7_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32mp25_adc_prepare,
+ .unprepare = stm32mp25_adc_unprepare,
+ .smp_cycles = stm32mp25_adc_smp_cycles,
+ .irq_clear = stm32h7_adc_irq_clear,
+ .set_ovs = stm32h7_adc_set_ovs,
+ .ts_int_ch = stm32_adc_min_ts_mp25,
+ .vref_charac_mv = 1800,
+};
+
static const struct stm32_adc_cfg stm32mp25_adc1_cfg = {
.regs = &stm32mp25_adc1_regspec,
.adc_info = &stm32mp25_adc_info,
@@ -3160,6 +3269,9 @@ static const struct of_device_id stm32_adc_of_match[] = {
{ .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg },
{ .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg },
{ .compatible = "st,stm32mp13-adc", .data = (void *)&stm32mp13_adc_cfg },
+ { .compatible = "st,stm32mp23-adc1", .data = (void *)&stm32mp23_adc1_cfg },
+ { .compatible = "st,stm32mp23-adc2", .data = (void *)&stm32mp23_adc2_cfg },
+ { .compatible = "st,stm32mp23-adc3", .data = (void *)&stm32mp23_adc3_cfg },
{ .compatible = "st,stm32mp25-adc1", .data = (void *)&stm32mp25_adc1_cfg },
{ .compatible = "st,stm32mp25-adc2", .data = (void *)&stm32mp25_adc2_cfg },
{ .compatible = "st,stm32mp25-adc3", .data = (void *)&stm32mp25_adc3_cfg },
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 09/14] iio: adc: stm32: add support for vddgpu on stm32mp23 and stm32mp25
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (7 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 08/14] iio: adc: stm32-adc: add support for stm32mp23 Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 10/14] arm64: dts: st: add vrefint calibration on stm32mp23 Fabrice Gasnier
` (4 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier
Add support for the vddgpu internal channel available on stm32mp23 and
stm32mp25. It is enabled by using ADC2 and ADC3 option register. Add
VDDGPU to the list of supported internal channels. Add sampling time
information from the datasheet.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- New patch split from V1, to avoid mixing new SoC / feature.
---
drivers/iio/adc/stm32-adc-core.h | 1 +
drivers/iio/adc/stm32-adc.c | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index 68b937e3819f..330c6c30e4f5 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -273,6 +273,7 @@ enum stm32h7_adc_dmngt {
#define STM32MP25_RES_MASK GENMASK(3, 2)
/* STM32MP25_ADC23_OR - specific bit fields */
+#define STM32MP25_VDDGPUEN BIT(4)
#define STM32MP25_VDDCPUEN BIT(3)
#define STM32MP25_VDDCOREEN BIT(2)
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index a14f858299ae..a2ed3abffa58 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -97,6 +97,7 @@ enum stm32_adc_int_ch {
STM32_ADC_INT_CH_VDDQ_DDR,
STM32_ADC_INT_CH_VREFINT,
STM32_ADC_INT_CH_VBAT,
+ STM32_ADC_INT_CH_VDDGPU,
STM32_ADC_INT_CH_NB
};
@@ -107,6 +108,7 @@ static const char stm32_adc_ic[STM32_ADC_INT_CH_NB][STM32_ADC_CH_SZ] = {
[STM32_ADC_INT_CH_VDDQ_DDR] = "vddq_ddr",
[STM32_ADC_INT_CH_VREFINT] = "vrefint",
[STM32_ADC_INT_CH_VBAT] = "vbat",
+ [STM32_ADC_INT_CH_VDDGPU] = "vddgpu"
};
/**
@@ -167,6 +169,7 @@ struct stm32_adc_vrefint {
* @smp_bits: smpr1 & smpr2 index and bitfields
* @or_vddcore: option register & vddcore bitfield
* @or_vddcpu: option register & vddcpu bitfield
+ * @or_vddgpu: option register & vddgpu bitfield
* @or_vddq_ddr: option register & vddq_ddr bitfield
* @ccr_vbat: common register & vbat bitfield
* @ccr_vref: common register & vrefint bitfield
@@ -186,6 +189,7 @@ struct stm32_adc_regspec {
const struct stm32_adc_regs *smp_bits;
const struct stm32_adc_regs or_vddcore;
const struct stm32_adc_regs or_vddcpu;
+ const struct stm32_adc_regs or_vddgpu;
const struct stm32_adc_regs or_vddq_ddr;
const struct stm32_adc_regs ccr_vbat;
const struct stm32_adc_regs ccr_vref;
@@ -725,6 +729,7 @@ static const struct stm32_adc_regspec stm32mp25_adc2_adc3_regspec = {
.smp_bits = stm32h7_smp_bits,
.or_vddcore = { STM32MP25_ADC23_OR, STM32MP25_VDDCOREEN },
.or_vddcpu = { STM32MP25_ADC23_OR, STM32MP25_VDDCPUEN },
+ .or_vddgpu = { STM32MP25_ADC23_OR, STM32MP25_VDDGPUEN },
.ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
.ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
};
@@ -953,6 +958,11 @@ static void stm32_adc_int_ch_enable(struct iio_dev *indio_dev)
stm32_adc_set_bits_common(adc, adc->cfg->regs->ccr_vbat.reg,
adc->cfg->regs->ccr_vbat.mask);
break;
+ case STM32_ADC_INT_CH_VDDGPU:
+ dev_dbg(&indio_dev->dev, "Enable VDDGPU\n");
+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vddgpu.reg,
+ adc->cfg->regs->or_vddgpu.mask);
+ break;
}
}
}
@@ -986,6 +996,10 @@ static void stm32_adc_int_ch_disable(struct stm32_adc *adc)
stm32_adc_clr_bits_common(adc, adc->cfg->regs->ccr_vbat.reg,
adc->cfg->regs->ccr_vbat.mask);
break;
+ case STM32_ADC_INT_CH_VDDGPU:
+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vddgpu.reg,
+ adc->cfg->regs->or_vddgpu.mask);
+ break;
}
}
}
@@ -2651,6 +2665,9 @@ static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_n
case STM32_ADC_INT_CH_VBAT:
na = !adc->cfg->regs->ccr_vbat.reg;
break;
+ case STM32_ADC_INT_CH_VDDGPU:
+ na = !adc->cfg->regs->or_vddgpu.reg;
+ break;
default:
return -EINVAL;
}
@@ -3160,6 +3177,7 @@ static const unsigned int stm32_adc_min_ts_mp25[STM32_ADC_INT_CH_NB] = {
[STM32_ADC_INT_CH_VDDCPU] = 34,
[STM32_ADC_INT_CH_VREFINT] = 34,
[STM32_ADC_INT_CH_VBAT] = 34,
+ [STM32_ADC_INT_CH_VDDGPU] = 34
};
static const struct stm32_adc_cfg stm32mp23_adc1_cfg = {
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 10/14] arm64: dts: st: add vrefint calibration on stm32mp23
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (8 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 09/14] iio: adc: stm32: add support for vddgpu on stm32mp23 and stm32mp25 Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 11/14] arm64: dts: st: add vrefint calibration on stm32mp25 Fabrice Gasnier
` (3 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Patrice Chotard,
Olivier Moysan
From: Patrice Chotard <patrice.chotard@foss.st.com>
Describe vrefint calibration cell to be retrieved by ADCs through bsec,
on STM32MP23.
Co-developed-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp231.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp231.dtsi b/arch/arm64/boot/dts/st/stm32mp231.dtsi
index 9e1d240888ff..938d6f0098ac 100644
--- a/arch/arm64/boot/dts/st/stm32mp231.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp231.dtsi
@@ -790,6 +790,10 @@ part-number-otp@24 {
reg = <0x24 0x4>;
};
+ vrefint: vrefin-cal@1b8 {
+ reg = <0x1b8 0x2>;
+ };
+
package-otp@1e8 {
reg = <0x1e8 0x1>;
bits = <0 3>;
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 11/14] arm64: dts: st: add vrefint calibration on stm32mp25
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (9 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 10/14] arm64: dts: st: add vrefint calibration on stm32mp23 Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 12/14] arm64: dts: st: add ADC nodes on stm32mp231 Fabrice Gasnier
` (2 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Patrice Chotard,
Olivier Moysan
From: Patrice Chotard <patrice.chotard@foss.st.com>
Describe vrefint calibration cell to be retrieved by ADCs through bsec,
on STM32MP25.
Co-developed-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp251.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index 9c63fdb5a885..82a8a6f1f881 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -1777,6 +1777,10 @@ part-number-otp@24 {
reg = <0x24 0x4>;
};
+ vrefint: vrefin-cal@1b8 {
+ reg = <0x1b8 0x2>;
+ };
+
package-otp@1e8 {
reg = <0x1e8 0x1>;
bits = <0 3>;
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 12/14] arm64: dts: st: add ADC nodes on stm32mp231
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (10 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 11/14] arm64: dts: st: add vrefint calibration on stm32mp25 Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 13/14] arm64: dts: st: add ADC nodes on stm32mp251 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 14/14] arm64: dts: st: add ADC support on stm32mp257f-ev1 board Fabrice Gasnier
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier, Cheick Traore
From: Cheick Traore <cheick.traore@foss.st.com>
Add analog-to-digital converter support on STM32MP23 SoC. It has 3 ADCs,
split into two blocks:
- ADC1 & ADC2 are tightly coupled.
- ADC3 is managed independently.
Define internal voltage channels in the SOC dtsi file, exception made of
vbat/4 channel (to avoid undesired load on it, in case no conversion is
needed on this channel). Choice is let to board implementation (via DT)
to define it.
Signed-off-by: Cheick Traore <cheick.traore@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- Adopt dedicated compatible for each child ADC, drop "st,adc-trigger-sel"
- Drop fallback generic match (serve no purpose)
---
arch/arm64/boot/dts/st/stm32mp231.dtsi | 112 +++++++++++++++++++++++++++++++++
1 file changed, 112 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp231.dtsi b/arch/arm64/boot/dts/st/stm32mp231.dtsi
index 938d6f0098ac..578ab9d4cffc 100644
--- a/arch/arm64/boot/dts/st/stm32mp231.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp231.dtsi
@@ -646,6 +646,118 @@ uart7: serial@40370000 {
status = "disabled";
};
+ adc_12: adc@404e0000 {
+ compatible = "st,stm32mp23-adc-core";
+ reg = <0x404e0000 0x400>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc CK_KER_ADC12>;
+ clock-names = "adc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ access-controllers = <&rifsc 58>;
+ power-domains = <&cluster_pd>;
+ status = "disabled";
+
+ adc1: adc@0 {
+ compatible = "st,stm32mp23-adc1";
+ reg = <0x0>;
+ interrupt-parent = <&adc_12>;
+ interrupts = <0>;
+ dmas = <&hpdma 81 0x20 0x12>;
+ dma-names = "rx";
+ #io-channel-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nvmem-cells = <&vrefint>;
+ nvmem-cell-names = "vrefint";
+ status = "disabled";
+ channel@14 {
+ reg = <14>;
+ label = "vrefint";
+ };
+ };
+
+ adc2: adc@100 {
+ compatible = "st,stm32mp23-adc2";
+ reg = <0x100>;
+ interrupt-parent = <&adc_12>;
+ interrupts = <1>;
+ dmas = <&hpdma 82 0x20 0x12>;
+ dma-names = "rx";
+ #io-channel-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nvmem-cells = <&vrefint>;
+ nvmem-cell-names = "vrefint";
+ status = "disabled";
+ channel@14 {
+ reg = <14>;
+ label = "vrefint";
+ };
+ channel@15 {
+ reg = <15>;
+ label = "vddcore";
+ };
+ channel@17 {
+ reg = <17>;
+ label = "vddcpu";
+ };
+ channel@18 {
+ reg = <18>;
+ label = "vddgpu";
+ };
+ };
+ };
+
+ adc_3: adc@404f0000 {
+ compatible = "st,stm32mp23-adc-core";
+ reg = <0x404f0000 0x400>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc CK_KER_ADC3>;
+ clock-names = "adc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ access-controllers = <&rifsc 59>;
+ power-domains = <&cluster_pd>;
+ status = "disabled";
+
+ adc3: adc@0 {
+ compatible = "st,stm32mp23-adc3";
+ reg = <0x0>;
+ interrupt-parent = <&adc_3>;
+ interrupts = <0>;
+ dmas = <&hpdma 83 0x20 0x12>;
+ dma-names = "rx";
+ #io-channel-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nvmem-cells = <&vrefint>;
+ nvmem-cell-names = "vrefint";
+ status = "disabled";
+ channel@14 {
+ reg = <14>;
+ label = "vrefint";
+ };
+ channel@15 {
+ reg = <15>;
+ label = "vddcore";
+ };
+ channel@17 {
+ reg = <17>;
+ label = "vddcpu";
+ };
+ channel@18 {
+ reg = <18>;
+ label = "vddgpu";
+ };
+ };
+ };
+
rng: rng@42020000 {
compatible = "st,stm32mp25-rng";
reg = <0x42020000 0x400>;
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 13/14] arm64: dts: st: add ADC nodes on stm32mp251
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (11 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 12/14] arm64: dts: st: add ADC nodes on stm32mp231 Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 14/14] arm64: dts: st: add ADC support on stm32mp257f-ev1 board Fabrice Gasnier
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier
Add analog-to-digital converter support on STM32MP25 SoC. It has 3 ADCs,
split into two blocks:
- ADC1 and ADC2 are tightly coupled.
- ADC3 is managed independently.
Define internal voltage channels in the SOC dtsi file, exception made of
vbat/4 channel (to avoid undesired load on it, in case no conversion is
needed on this channel). Choice is let to board implementation (via DT)
to define it.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- Adopt dedicated compatible for each child ADC, drop "st,adc-trigger-sel"
- Drop fallback generic match (serve no purpose)
---
arch/arm64/boot/dts/st/stm32mp251.dtsi | 112 +++++++++++++++++++++++++++++++++
1 file changed, 112 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index 82a8a6f1f881..5834755194a1 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -1450,6 +1450,118 @@ uart8: serial@40380000 {
status = "disabled";
};
+ adc_12: adc@404e0000 {
+ compatible = "st,stm32mp25-adc-core";
+ reg = <0x404e0000 0x400>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc CK_KER_ADC12>;
+ clock-names = "adc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ power-domains = <&CLUSTER_PD>;
+ access-controllers = <&rifsc 58>;
+ status = "disabled";
+
+ adc1: adc@0 {
+ compatible = "st,stm32mp25-adc1";
+ reg = <0x0>;
+ interrupt-parent = <&adc_12>;
+ interrupts = <0>;
+ dmas = <&hpdma 81 0x20 0x12>;
+ dma-names = "rx";
+ #io-channel-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nvmem-cells = <&vrefint>;
+ nvmem-cell-names = "vrefint";
+ status = "disabled";
+ channel@14 {
+ reg = <14>;
+ label = "vrefint";
+ };
+ };
+
+ adc2: adc@100 {
+ compatible = "st,stm32mp25-adc2";
+ reg = <0x100>;
+ interrupt-parent = <&adc_12>;
+ interrupts = <1>;
+ dmas = <&hpdma 82 0x20 0x12>;
+ dma-names = "rx";
+ #io-channel-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nvmem-cells = <&vrefint>;
+ nvmem-cell-names = "vrefint";
+ status = "disabled";
+ channel@14 {
+ reg = <14>;
+ label = "vrefint";
+ };
+ channel@15 {
+ reg = <15>;
+ label = "vddcore";
+ };
+ channel@17 {
+ reg = <17>;
+ label = "vddcpu";
+ };
+ channel@18 {
+ reg = <18>;
+ label = "vddgpu";
+ };
+ };
+ };
+
+ adc_3: adc@404f0000 {
+ compatible = "st,stm32mp25-adc-core";
+ reg = <0x404f0000 0x400>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc CK_KER_ADC3>;
+ clock-names = "adc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ access-controllers = <&rifsc 59>;
+ power-domains = <&CLUSTER_PD>;
+ status = "disabled";
+
+ adc3: adc@0 {
+ compatible = "st,stm32mp25-adc3";
+ reg = <0x0>;
+ interrupt-parent = <&adc_3>;
+ interrupts = <0>;
+ dmas = <&hpdma 83 0x20 0x12>;
+ dma-names = "rx";
+ #io-channel-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ nvmem-cells = <&vrefint>;
+ nvmem-cell-names = "vrefint";
+ status = "disabled";
+ channel@14 {
+ reg = <14>;
+ label = "vrefint";
+ };
+ channel@15 {
+ reg = <15>;
+ label = "vddcore";
+ };
+ channel@17 {
+ reg = <17>;
+ label = "vddcpu";
+ };
+ channel@18 {
+ reg = <18>;
+ label = "vddgpu";
+ };
+ };
+ };
+
rng: rng@42020000 {
compatible = "st,stm32mp25-rng";
reg = <0x42020000 0x400>;
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 14/14] arm64: dts: st: add ADC support on stm32mp257f-ev1 board
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
` (12 preceding siblings ...)
2026-09-23 15:39 ` [PATCH v2 13/14] arm64: dts: st: add ADC nodes on stm32mp251 Fabrice Gasnier
@ 2026-09-23 15:39 ` Fabrice Gasnier
13 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-23 15:39 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue
Cc: Marek Vasut, linux-iio, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, Fabrice Gasnier
Add ADC support on stm32mp257f-ev1 board. ANA0 dedicated pin is wired on
mikroBUS connector, through a resistor divided and operational amplifier.
Configure adc1 channel0, and voltage divider in the DT. Keep it disabled
by default, to allow ADC to be used freely for other purpose.
--> | 470K | -+-- > | OpAmp (gain = 1) | --> ANA0 (to ADC1, ADC2 or ADC3)
|
v
| 560K |
|
v
---
GND
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index b5db62a0a550..ed61ff70c0de 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -160,6 +160,28 @@ mm_ospi1: mm-ospi@60000000 {
no-map;
};
};
+
+ vdiv_ana0: voltage-divider-ana0 {
+ compatible = "voltage-divider";
+ io-channels = <&adc1 0>;
+ output-ohms = <560000>;
+ full-ohms = <1030000>;
+ status = "disabled";
+ };
+};
+
+&adc_12 {
+ /* Don't need a pinctrl for ANA0 dedicated pin e.g. Channel@0 */
+ vdda-supply = <&scmi_vdda18adc>;
+ vref-supply = <&scmi_v1v8>;
+ status = "disabled";
+ adc1: adc@0 {
+ status = "okay";
+ channel@0 {
+ reg = <0>;
+ st,min-sample-time-ns = <400>;
+ };
+ };
};
&arm_wdt {
--
2.43.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 05/14] iio: adc: stm32-adc: rework internal channels data
2026-09-23 15:39 ` [PATCH v2 05/14] iio: adc: stm32-adc: rework internal channels data Fabrice Gasnier
@ 2026-09-24 10:02 ` Fabrice Gasnier
2026-09-24 20:53 ` Andy Shevchenko
1 sibling, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2026-09-24 10:02 UTC (permalink / raw)
To: Jonathan Cameron, Andy Shevchenko
Cc: Marek Vasut, linux-iio, devicetree, Conor Dooley, linux-stm32,
linux-arm-kernel, linux-kernel, Alexandre Torgue,
Krzysztof Kozlowski, Rob Herring, David Lechner, Nuno Sá,
Maxime Coquelin
On 9/23/26 17:39, Fabrice Gasnier wrote:
> Diversity in internal channels data array lead to have zeroed data.
> To facilitate addition of new internal channels, without touching
> all array initializers, only focus on exiting channels on each
> supported ADC variant (e.g. each SoC).
>
> This also allows to get rid of static_assert() checks.
>
> No functional change intended.
[ snip ]
> -static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
> -static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB);
> +static const unsigned int stm32_adc_min_ts_mp1[STM32_ADC_INT_CH_NB] = {
> + [STM32_ADC_INT_CH_VDDCORE] = 100,
> + [STM32_ADC_INT_CH_VREFINT] = 4300,
> + [STM32_ADC_INT_CH_VBAT] = 9800
> +};
Hi all,
Oops, I just figured out I've mixed changes with a fix here. So, I just
have sent a separate fix for that [1].
It's been noticed by sashiko [2].
I'll wait a bit before sending a V3, to leave time to review other patches.
>
> static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
> .regs = &stm32mp1_adc_regspec,
> @@ -2760,8 +2756,13 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
> .vref_charac_mv = 3300,
> };
>
> -static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
> -static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB);
> +static const unsigned int stm32_adc_min_ts_mp13[STM32_ADC_INT_CH_NB] = {
> + [STM32_ADC_INT_CH_VDDCORE] = 1000,
> + [STM32_ADC_INT_CH_VDDCPU] = 1000,
> + [STM32_ADC_INT_CH_VDDQ_DDR] = 1000,
> + [STM32_ADC_INT_CH_VREFINT] = 4300,
> + [STM32_ADC_INT_CH_VBAT] = 9800
> +};
Same here.
[1]
https://lore.kernel.org/linux-iio/20260924-adc-fix-sampling-v1-1-13814954d8d7@foss.st.com/
[2]
https://sashiko.dev/#/message/20260923155115.20E4E1F00893%40smtp.kernel.org
BR,
Fabrice
>
> static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
> .regs = &stm32mp13_adc_regspec,
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 05/14] iio: adc: stm32-adc: rework internal channels data
2026-09-23 15:39 ` [PATCH v2 05/14] iio: adc: stm32-adc: rework internal channels data Fabrice Gasnier
2026-09-24 10:02 ` Fabrice Gasnier
@ 2026-09-24 20:53 ` Andy Shevchenko
1 sibling, 0 replies; 18+ messages in thread
From: Andy Shevchenko @ 2026-09-24 20:53 UTC (permalink / raw)
To: Fabrice Gasnier
Cc: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue, Marek Vasut, linux-iio,
devicetree, linux-stm32, linux-arm-kernel, linux-kernel
On Wed, Sep 23, 2026 at 05:39:08PM +0200, Fabrice Gasnier wrote:
> Diversity in internal channels data array lead to have zeroed data.
> To facilitate addition of new internal channels, without touching
> all array initializers, only focus on exiting channels on each
> supported ADC variant (e.g. each SoC).
>
> This also allows to get rid of static_assert() checks.
>
> No functional change intended.
> Cosmetic update: remove comma on STM32_ADC_INT_CH_NB as it should
> always be the last element.
Yes, but...
> -static const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 };
> -static_assert(ARRAY_SIZE(stm32_adc_min_ts_h7) == STM32_ADC_INT_CH_NB);
> +static const unsigned int stm32_adc_min_ts_h7[STM32_ADC_INT_CH_NB] = {
> + [STM32_ADC_INT_CH_VREFINT] = 4300,
> + [STM32_ADC_INT_CH_VBAT] = 9000
...you should have it when it's not a terminator entry. Here is the case when
it's not a terminator, neither in other similar cases below.
> +};
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 07/14] iio: adc: stm32-adc: add support for stm32mp25
2026-09-23 15:39 ` [PATCH v2 07/14] iio: adc: stm32-adc: add support for stm32mp25 Fabrice Gasnier
@ 2026-09-24 21:01 ` Andy Shevchenko
0 siblings, 0 replies; 18+ messages in thread
From: Andy Shevchenko @ 2026-09-24 21:01 UTC (permalink / raw)
To: Fabrice Gasnier
Cc: Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Maxime Coquelin, Alexandre Torgue, Marek Vasut, linux-iio,
devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
Cheick Traore, Olivier Moysan
On Wed, Sep 23, 2026 at 05:39:10PM +0200, Fabrice Gasnier wrote:
> Add support for ADC on STM32MP25 SoC. It has 3 ADCs, split into two blocks:
> - ADC1 & ADC2 are tightly coupled.
> - ADC3 is managed independently.
>
> Trigger list slightly changes between these blocks (ADC1 & ADC2). Other
> differences are found on channels interconnects (similar between ADC2
> and ADC3):
> - ADC1 is connected to 18 external channels + 2 internal channels
> - ADC2 is connected to 14 external channels + 6 internal channels
> - ADC3 is connected to 14 external channels + 6 internal channels
>
> Each ADC is a 12-bits successive approximation analog-to-digital converter,
> with up to 20 multiplexed channels that can be configured as single ended
> or differential. ADC resolution ranges from 6 to 12 bits.
>
> It introduces diversity regarding IRQs, clocks, software calibration
> procedure, internal voltage channels, sampling time (prescaler) and
> trigger list. Most of the architecture, and the driver engine remains
> similar. So, handle the differences w.r.t. other STM32 ADCs family with
> a dedicated compatible and compatible data.
...
> .compatible = "st,stm32mp13-adc-core",
> .data = (void *)&stm32mp13_adc_priv_cfg
> }, {
> - },
> + .compatible = "st,stm32mp25-adc-core",
> + .data = (void *)&stm32mp25_adc_priv_cfg
> + }, {
> + }
Same issue and now it's a regression from maintenance perspective: you added an
unnedeed churn that has to be handled from now on... TL;DR: do add trailing
commas to the non-terminator entries and remove trailing commas in the
terminator entries.
> };
...
> + STM32_EXT23,
> + STM32_EXT24,
> + STM32_EXT25,
> + STM32_EXT26,
> + STM32_EXT27,
> + STM32_EXT28
Same issue and so on...
> };
...
Are you doing patches with an assistance? LLMs might have a problem with the
style issues.
...
> +retry:
> + /* Clears or set CALADDOS (also clear old calibration data if any) */
> + stm32_adc_writel(adc, STM32MP25_ADC_CALFACT,
> + FIELD_PREP(STM32MP25_CALFACT_CALADDOS, *add_offset));
> +
> + ret = stm32mp25_adc_calib_get_average_data(indio_dev, &average);
> + if (ret)
> + return ret;
> +
> + /* Add offset and retry single-ended calibration if the averaged data is zero */
> + if (!average && !*add_offset) {
> + *add_offset = true;
> + goto retry;
> + }
Refactor to avoid a label. It's possible to achieve.
> + if (!average) {
Why not positive conditional?
> + /* If average data is still zero with additional offset, just warn about it */
> + dev_warn(&indio_dev->dev, "Single-ended calibration average: 0\n");
> + } else {
> + u32 calfact = stm32_adc_readl(adc, STM32MP25_ADC_CALFACT);
> +
> + calfact |= FIELD_PREP(STM32MP25_CALFACT_S_MASK, average);
> + stm32_adc_writel(adc, STM32MP25_ADC_CALFACT, calfact);
> + }
...
> +static int stm32mp25_adc_calib(struct iio_dev *indio_dev)
> + struct stm32_adc *adc = iio_priv(indio_dev);
> + bool add_offset = false;
> + bool diff_below_zero;
> + u32 average, calfact;
> + int ret;
> +
> + stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
> + /* Use default resolution (e.g. 12 bits) */
> + stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32MP25_RES_MASK);
> +
> +retry:
> + /* Single ended input calibration */
> + ret = stm32mp25_adc_calib_single_ended_offset(indio_dev, &add_offset);
> + if (ret)
> + goto out;
> +
> + /* Differential input calibration (keep previous CALADDOS value) */
> + stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALDIF);
> + ret = stm32mp25_adc_calib_get_average_data(indio_dev, &average);
> + if (ret)
> + goto out;
> +
> + /* Averaged diff data is below 0x800 (half value in 12-bits mode) */
> + diff_below_zero = average < BIT(adc->cfg->adc_info->resolutions[0] - 1);
> +
> + if (diff_below_zero && !add_offset) {
> + /* Retry the whole calibration with additional offset */
> + add_offset = true;
> + goto retry;
> + }
Same comment, refactor to avoid label.
> + calfact = stm32_adc_readl(adc, STM32MP25_ADC_CALFACT);
> +
> + if (diff_below_zero) {
> + /*
> + * Averaged data is still below center value. It needs to be clamped to zero,
> + * so don't use the result here, warn about it.
> + */
> + dev_warn(&indio_dev->dev, "Differential calibration clamped(0): 0x%x\n", average);
> + } else {
> + calfact |= FIELD_PREP(STM32MP25_CALFACT_D_MASK, average);
> + stm32_adc_writel(adc, STM32MP25_ADC_CALFACT, calfact);
> + }
> +
> + dev_dbg(&indio_dev->dev, "set calfact_s=0x%03lx, calfact_d=0x%03lx, calados=%ld\n",
> + FIELD_GET(STM32MP25_CALFACT_S_MASK, calfact),
> + FIELD_GET(STM32MP25_CALFACT_D_MASK, calfact),
> + FIELD_GET(STM32MP25_CALFACT_CALADDOS, calfact));
> +out:
In any case if you ever have a label in the code, name it as an answer to the Q:
"What will be done if I goto *this* label?"
Here it is something like 'out_calibration_stop_and_reset'
(I haven't checked the real code and datasheet, just used below short context).
> + stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCAL);
> + stm32_adc_set_res(adc);
> +
> + return ret;
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-09-24 21:01 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 15:39 [PATCH v2 00/14] iio: adc: stm32: add support for stm32mp23 and stm32mp25 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 01/14] dt-bindings: iio: adc: stm32-adc: " Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 02/14] iio: adc: stm32-adc: core: manage clock prescaler diversity Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 03/14] iio: adc: stm32-adc: core: configurable number of interrupts Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 04/14] iio: adc: stm32-adc: manage characterization voltage diversity Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 05/14] iio: adc: stm32-adc: rework internal channels data Fabrice Gasnier
2026-09-24 10:02 ` Fabrice Gasnier
2026-09-24 20:53 ` Andy Shevchenko
2026-09-23 15:39 ` [PATCH v2 06/14] iio: adc: stm32-adc: add vreg enable option to manage diversity Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 07/14] iio: adc: stm32-adc: add support for stm32mp25 Fabrice Gasnier
2026-09-24 21:01 ` Andy Shevchenko
2026-09-23 15:39 ` [PATCH v2 08/14] iio: adc: stm32-adc: add support for stm32mp23 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 09/14] iio: adc: stm32: add support for vddgpu on stm32mp23 and stm32mp25 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 10/14] arm64: dts: st: add vrefint calibration on stm32mp23 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 11/14] arm64: dts: st: add vrefint calibration on stm32mp25 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 12/14] arm64: dts: st: add ADC nodes on stm32mp231 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 13/14] arm64: dts: st: add ADC nodes on stm32mp251 Fabrice Gasnier
2026-09-23 15:39 ` [PATCH v2 14/14] arm64: dts: st: add ADC support on stm32mp257f-ev1 board Fabrice Gasnier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®