linux-pwm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource
@ 2025-03-14 17:14 Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 1/8] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25 Fabrice Gasnier
                   ` (7 more replies)
  0 siblings, 8 replies; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

This series adds support for STM32MP25 to MFD PWM, IIO, counter and
clocksource low-power timer (LPTIM) drivers.
This new variant is managed by using a new DT compatible string, hardware
configuration and version registers.
It comes with a slightly updated register set, some new features and new
interconnect signals inside the SoC.
Same feature list as on STM32MP1x is supported currently.
The device tree files add all instances in stm32mp251 dtsi file.

Changes in V4
---
- Simplify IIO trigger driver as per Jonathan's comments.
- Rework clocksource driver: encapsulate mp25 changes in separate function
  after Daniel's suggestion.
- Add some definitions to MFD header.

Changes in V3
---
- Yaml indentation issue fixed, reported by Rob's bot

Changes in V2
---
- Review comments from Krzysztof
  - Adopt compatible fallback in dt-bindings and driver
  - drivers: drop "st,stm32mp25-..." compatibles when unused (e.g. no .data)
  - counter driver: no update (patch dropped)
  - defconfig: only enable the necessary config for upstream board
  - add lptimer DT node in stm32mp257f-ev1 board
- Add missing management of IER access for stm32mp25

Fabrice Gasnier (7):
  dt-bindings: mfd: stm32-lptimer: add support for stm32mp25
  mfd: stm32-lptimer: add support for stm32mp25
  clocksource: stm32-lptimer: add support for stm32mp25
  pwm: stm32-lp: add support for stm32mp25
  arm64: defconfig: enable STM32 LP timer clockevent driver
  arm64: dts: st: add low-power timer nodes on stm32mp251
  arm64: dts: st: use lptimer3 as tick broadcast source on
    stm32mp257f-ev1

Olivier Moysan (1):
  iio: trigger: stm32-lptimer: add support for stm32mp25

 .../bindings/mfd/st,stm32-lptimer.yaml        |  40 +++-
 arch/arm64/boot/dts/st/stm32mp251.dtsi        | 177 ++++++++++++++
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts    |   8 +
 arch/arm64/configs/defconfig                  |   2 +
 drivers/clocksource/timer-stm32-lp.c          |  51 +++-
 drivers/iio/trigger/stm32-lptimer-trigger.c   |  75 ++++--
 drivers/mfd/stm32-lptimer.c                   |  33 ++-
 drivers/pwm/pwm-stm32-lp.c                    | 219 +++++++++++++++---
 include/linux/iio/timer/stm32-lptim-trigger.h |   9 +
 include/linux/mfd/stm32-lptimer.h             |  37 ++-
 10 files changed, 594 insertions(+), 57 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 1/8] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25
  2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
@ 2025-03-14 17:14 ` Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 2/8] " Fabrice Gasnier
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

Add a new stm32mp25 compatible to stm32-lptimer dt-bindings, to support
STM32MP25 SoC. Some features has been updated or added to the low-power
timer:
- new capture compare channels
- up to two PWM channels
- PWM input capture
- peripheral interconnect in stm32mp25 has been updated (new triggers).
- registers/bits has been added or revisited (IER access).
So introduce a new compatible to handle this diversity.

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in V4:
- Add Rob's Reviewed-by tag
Changes in V3:
- Fix yaml indentation issue found by Rob's bot
Changes in V2:
- Use fallback compatibles, along with stm32mp25 specific compatible
- trigger identifier can be up to 4 (e.g. from LPTIM1..5)
---
 .../bindings/mfd/st,stm32-lptimer.yaml        | 40 ++++++++++++++++---
 1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml b/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
index d41308856408..4eabafb8079d 100644
--- a/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
+++ b/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
@@ -21,7 +21,12 @@ maintainers:
 
 properties:
   compatible:
-    const: st,stm32-lptimer
+    oneOf:
+      - items:
+          - const: st,stm32mp25-lptimer
+          - const: st,stm32-lptimer
+      - items:
+          - const: st,stm32-lptimer
 
   reg:
     maxItems: 1
@@ -48,13 +53,21 @@ properties:
     minItems: 1
     maxItems: 2
 
+  power-domains:
+    maxItems: 1
+
   pwm:
     type: object
     additionalProperties: false
 
     properties:
       compatible:
-        const: st,stm32-pwm-lp
+        oneOf:
+          - items:
+              - const: st,stm32mp25-pwm-lp
+              - const: st,stm32-pwm-lp
+          - items:
+              - const: st,stm32-pwm-lp
 
       "#pwm-cells":
         const: 3
@@ -69,7 +82,12 @@ properties:
 
     properties:
       compatible:
-        const: st,stm32-lptimer-counter
+        oneOf:
+          - items:
+              - const: st,stm32mp25-lptimer-counter
+              - const: st,stm32-lptimer-counter
+          - items:
+              - const: st,stm32-lptimer-counter
 
     required:
       - compatible
@@ -80,7 +98,12 @@ properties:
 
     properties:
       compatible:
-        const: st,stm32-lptimer-timer
+        oneOf:
+          - items:
+              - const: st,stm32mp25-lptimer-timer
+              - const: st,stm32-lptimer-timer
+          - items:
+              - const: st,stm32-lptimer-timer
 
     required:
       - compatible
@@ -92,13 +115,18 @@ patternProperties:
 
     properties:
       compatible:
-        const: st,stm32-lptimer-trigger
+        oneOf:
+          - items:
+              - const: st,stm32mp25-lptimer-trigger
+              - const: st,stm32-lptimer-trigger
+          - items:
+              - const: st,stm32-lptimer-trigger
 
       reg:
         description: Identify trigger hardware block.
         items:
           minimum: 0
-          maximum: 2
+          maximum: 4
 
     required:
       - compatible
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 2/8] mfd: stm32-lptimer: add support for stm32mp25
  2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 1/8] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25 Fabrice Gasnier
@ 2025-03-14 17:14 ` Fabrice Gasnier
  2025-04-04 14:40   ` Lee Jones
  2025-03-14 17:14 ` [PATCH v4 3/8] iio: trigger: " Fabrice Gasnier
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

Add support for STM32MP25 SoC.
A new hardware configuration register (HWCFGR2) has been added, to gather
number of capture/compare channels, autonomous mode and input capture
capability. The full feature set is implemented in LPTIM1/2/3/4. LPTIM5
supports a smaller set of features. This can now be read from HWCFGR
registers.

Add new registers to the stm32-lptimer.h: CCMR1, CCR2, HWCFGR1/2 and VERR.
Update the stm32_lptimer data struct so signal the number of
capture/compare channels to the child devices.
Also Remove some unused bit masks (CMPOK_ARROK / CMPOKCF_ARROKCF).

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in V4:
- Add DIEROK, ARROK status flags, and their clear flags.
Changes in V2:
- rely on fallback compatible as no specific .data is associated to the
  driver. Compatibility is added by reading hardware configuration
  registers.
- read version register, to be used by clockevent child driver
- rename register/bits definitions
---
 drivers/mfd/stm32-lptimer.c       | 33 ++++++++++++++++++++++++++-
 include/linux/mfd/stm32-lptimer.h | 37 ++++++++++++++++++++++++++++---
 2 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c
index b2704a9809c7..09073dbc9c80 100644
--- a/drivers/mfd/stm32-lptimer.c
+++ b/drivers/mfd/stm32-lptimer.c
@@ -6,6 +6,7 @@
  * Inspired by Benjamin Gaignard's stm32-timers driver
  */
 
+#include <linux/bitfield.h>
 #include <linux/mfd/stm32-lptimer.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
@@ -49,6 +50,36 @@ static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata)
 	return 0;
 }
 
+static int stm32_lptimer_detect_hwcfgr(struct stm32_lptimer *ddata)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(ddata->regmap, STM32_LPTIM_VERR, &ddata->version);
+	if (ret)
+		return ret;
+
+	/* Try to guess parameters from HWCFGR: e.g. encoder mode (STM32MP15) */
+	ret = regmap_read(ddata->regmap, STM32_LPTIM_HWCFGR1, &val);
+	if (ret)
+		return ret;
+
+	/* Fallback to legacy init if HWCFGR isn't present */
+	if (!val)
+		return stm32_lptimer_detect_encoder(ddata);
+
+	ddata->has_encoder = FIELD_GET(STM32_LPTIM_HWCFGR1_ENCODER, val);
+
+	ret = regmap_read(ddata->regmap, STM32_LPTIM_HWCFGR2, &val);
+	if (ret)
+		return ret;
+
+	/* Number of capture/compare channels */
+	ddata->num_cc_chans = FIELD_GET(STM32_LPTIM_HWCFGR2_CHAN_NUM, val);
+
+	return 0;
+}
+
 static int stm32_lptimer_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -73,7 +104,7 @@ static int stm32_lptimer_probe(struct platform_device *pdev)
 	if (IS_ERR(ddata->clk))
 		return PTR_ERR(ddata->clk);
 
-	ret = stm32_lptimer_detect_encoder(ddata);
+	ret = stm32_lptimer_detect_hwcfgr(ddata);
 	if (ret)
 		return ret;
 
diff --git a/include/linux/mfd/stm32-lptimer.h b/include/linux/mfd/stm32-lptimer.h
index 06d3f11dc3c9..a592c8dc716d 100644
--- a/include/linux/mfd/stm32-lptimer.h
+++ b/include/linux/mfd/stm32-lptimer.h
@@ -17,20 +17,30 @@
 #define STM32_LPTIM_IER		0x08	/* Interrupt Enable Reg      */
 #define STM32_LPTIM_CFGR	0x0C	/* Configuration Reg         */
 #define STM32_LPTIM_CR		0x10	/* Control Reg               */
-#define STM32_LPTIM_CMP		0x14	/* Compare Reg               */
+#define STM32_LPTIM_CMP		0x14	/* Compare Reg (MP25 CCR1)   */
 #define STM32_LPTIM_ARR		0x18	/* Autoreload Reg            */
 #define STM32_LPTIM_CNT		0x1C	/* Counter Reg               */
+#define STM32_LPTIM_CCMR1	0x2C	/* Capture/Compare Mode MP25 */
+#define STM32_LPTIM_CCR2	0x34	/* Compare Reg2 MP25         */
+
+#define STM32_LPTIM_HWCFGR2	0x3EC	/* Hardware configuration register 2 - MP25 */
+#define STM32_LPTIM_HWCFGR1	0x3F0	/* Hardware configuration register 1 - MP15 */
+#define STM32_LPTIM_VERR	0x3F4	/* Version identification register - MP15 */
 
 /* STM32_LPTIM_ISR - bit fields */
+#define STM32_LPTIM_DIEROK_ARROK	(BIT(24) | BIT(4)) /* MP25 */
+#define STM32_LPTIM_CMP2_ARROK		(BIT(19) | BIT(4))
 #define STM32_LPTIM_CMPOK_ARROK		GENMASK(4, 3)
 #define STM32_LPTIM_ARROK		BIT(4)
 #define STM32_LPTIM_CMPOK		BIT(3)
 
 /* STM32_LPTIM_ICR - bit fields */
-#define STM32_LPTIM_ARRMCF		BIT(1)
+#define STM32_LPTIM_DIEROKCF_ARROKCF	(BIT(24) | BIT(4)) /* MP25 */
+#define STM32_LPTIM_CMP2OKCF_ARROKCF	(BIT(19) | BIT(4))
 #define STM32_LPTIM_CMPOKCF_ARROKCF	GENMASK(4, 3)
+#define STM32_LPTIM_ARRMCF		BIT(1)
 
-/* STM32_LPTIM_IER - bit flieds */
+/* STM32_LPTIM_IER - bit fields */
 #define STM32_LPTIM_ARRMIE	BIT(1)
 
 /* STM32_LPTIM_CR - bit fields */
@@ -53,16 +63,37 @@
 /* STM32_LPTIM_ARR */
 #define STM32_LPTIM_MAX_ARR	0xFFFF
 
+/* STM32_LPTIM_CCMR1 */
+#define STM32_LPTIM_CC2P	GENMASK(19, 18)
+#define STM32_LPTIM_CC2E	BIT(17)
+#define STM32_LPTIM_CC2SEL	BIT(16)
+#define STM32_LPTIM_CC1P	GENMASK(3, 2)
+#define STM32_LPTIM_CC1E	BIT(1)
+#define STM32_LPTIM_CC1SEL	BIT(0)
+
+/* STM32_LPTIM_HWCFGR1 */
+#define STM32_LPTIM_HWCFGR1_ENCODER	BIT(16)
+
+/* STM32_LPTIM_HWCFGR2 */
+#define STM32_LPTIM_HWCFGR2_CHAN_NUM	GENMASK(3, 0)
+
+/* STM32_LPTIM_VERR */
+#define STM32_LPTIM_VERR_23	0x23	/* STM32MP25 */
+
 /**
  * struct stm32_lptimer - STM32 Low-Power Timer data assigned by parent device
  * @clk: clock reference for this instance
  * @regmap: register map reference for this instance
  * @has_encoder: indicates this Low-Power Timer supports encoder mode
+ * @num_cc_chans: indicates the number of capture/compare channels
+ * @version: indicates the major and minor revision of the controller
  */
 struct stm32_lptimer {
 	struct clk *clk;
 	struct regmap *regmap;
 	bool has_encoder;
+	unsigned int num_cc_chans;
+	u32 version;
 };
 
 #endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 3/8] iio: trigger: stm32-lptimer: add support for stm32mp25
  2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 1/8] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25 Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 2/8] " Fabrice Gasnier
@ 2025-03-14 17:14 ` Fabrice Gasnier
  2025-03-15 12:56   ` Jonathan Cameron
  2025-03-14 17:14 ` [PATCH v4 4/8] clocksource: " Fabrice Gasnier
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

From: Olivier Moysan <olivier.moysan@foss.st.com>

Add support for STM32MP25 SoC. Use newly introduced compatible to handle
this new HW variant. Add new trigger definitions that can be used by the
stm32 analog-to-digital converter. Use compatible data to identify them.

Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v4:
- Jonathan's comment: simplify infrastructure by keeping
  devm_iio_trigger_register. Don't need to cast compatible data.
---
 drivers/iio/trigger/stm32-lptimer-trigger.c   | 75 ++++++++++++++-----
 include/linux/iio/timer/stm32-lptim-trigger.h |  9 +++
 2 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c
index f1e18913236a..3dcc8d2fe093 100644
--- a/drivers/iio/trigger/stm32-lptimer-trigger.c
+++ b/drivers/iio/trigger/stm32-lptimer-trigger.c
@@ -16,16 +16,43 @@
 #include <linux/platform_device.h>
 #include <linux/property.h>
 
-/* List Low-Power Timer triggers */
-static const char * const stm32_lptim_triggers[] = {
-	LPTIM1_OUT,
-	LPTIM2_OUT,
-	LPTIM3_OUT,
+/* Maximum triggers + one trailing null entry to indicate the end of array */
+#define MAX_TRIGGERS 3
+
+struct stm32_lptim_cfg {
+	const char * const (*triggers)[MAX_TRIGGERS];
+	unsigned int nb_triggers;
+};
+
+/* List Low-Power Timer triggers for H7, MP13, MP15 */
+static const char * const stm32_lptim_triggers[][MAX_TRIGGERS] = {
+	{ LPTIM1_OUT,},
+	{ LPTIM2_OUT,},
+	{ LPTIM3_OUT,},
+};
+
+/* List Low-Power Timer triggers for STM32MP25 */
+static const char * const stm32mp25_lptim_triggers[][MAX_TRIGGERS] = {
+	{ LPTIM1_CH1, LPTIM1_CH2, },
+	{ LPTIM2_CH1, LPTIM2_CH2, },
+	{ LPTIM3_CH1,},
+	{ LPTIM4_CH1,},
+	{ LPTIM5_OUT,},
+};
+
+static const struct stm32_lptim_cfg stm32mp15_lptim_cfg = {
+	.triggers = stm32_lptim_triggers,
+	.nb_triggers = ARRAY_SIZE(stm32_lptim_triggers),
+};
+
+static const struct stm32_lptim_cfg stm32mp25_lptim_cfg = {
+	.triggers = stm32mp25_lptim_triggers,
+	.nb_triggers = ARRAY_SIZE(stm32mp25_lptim_triggers),
 };
 
 struct stm32_lptim_trigger {
 	struct device *dev;
-	const char *trg;
+	const char * const *triggers;
 };
 
 static int stm32_lptim_validate_device(struct iio_trigger *trig,
@@ -56,22 +83,33 @@ EXPORT_SYMBOL(is_stm32_lptim_trigger);
 
 static int stm32_lptim_setup_trig(struct stm32_lptim_trigger *priv)
 {
-	struct iio_trigger *trig;
+	const char * const *cur = priv->triggers;
+	int ret;
 
-	trig = devm_iio_trigger_alloc(priv->dev, "%s", priv->trg);
-	if  (!trig)
-		return -ENOMEM;
+	while (cur && *cur) {
+		struct iio_trigger *trig;
 
-	trig->dev.parent = priv->dev->parent;
-	trig->ops = &stm32_lptim_trigger_ops;
-	iio_trigger_set_drvdata(trig, priv);
+		trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
+		if  (!trig)
+			return -ENOMEM;
 
-	return devm_iio_trigger_register(priv->dev, trig);
+		trig->dev.parent = priv->dev->parent;
+		trig->ops = &stm32_lptim_trigger_ops;
+		iio_trigger_set_drvdata(trig, priv);
+
+		ret = devm_iio_trigger_register(priv->dev, trig);
+		if (ret)
+			return ret;
+		cur++;
+	}
+
+	return 0;
 }
 
 static int stm32_lptim_trigger_probe(struct platform_device *pdev)
 {
 	struct stm32_lptim_trigger *priv;
+	struct stm32_lptim_cfg const *lptim_cfg;
 	u32 index;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -81,17 +119,20 @@ static int stm32_lptim_trigger_probe(struct platform_device *pdev)
 	if (device_property_read_u32(&pdev->dev, "reg", &index))
 		return -EINVAL;
 
-	if (index >= ARRAY_SIZE(stm32_lptim_triggers))
+	lptim_cfg = device_get_match_data(&pdev->dev);
+
+	if (index >= lptim_cfg->nb_triggers)
 		return -EINVAL;
 
 	priv->dev = &pdev->dev;
-	priv->trg = stm32_lptim_triggers[index];
+	priv->triggers = lptim_cfg->triggers[index];
 
 	return stm32_lptim_setup_trig(priv);
 }
 
 static const struct of_device_id stm32_lptim_trig_of_match[] = {
-	{ .compatible = "st,stm32-lptimer-trigger", },
+	{ .compatible = "st,stm32-lptimer-trigger", .data = &stm32mp15_lptim_cfg },
+	{ .compatible = "st,stm32mp25-lptimer-trigger", .data = &stm32mp25_lptim_cfg},
 	{},
 };
 MODULE_DEVICE_TABLE(of, stm32_lptim_trig_of_match);
diff --git a/include/linux/iio/timer/stm32-lptim-trigger.h b/include/linux/iio/timer/stm32-lptim-trigger.h
index a34dcf6a6001..ce3cf0addb2e 100644
--- a/include/linux/iio/timer/stm32-lptim-trigger.h
+++ b/include/linux/iio/timer/stm32-lptim-trigger.h
@@ -14,6 +14,15 @@
 #define LPTIM1_OUT	"lptim1_out"
 #define LPTIM2_OUT	"lptim2_out"
 #define LPTIM3_OUT	"lptim3_out"
+#define LPTIM4_OUT	"lptim4_out"
+#define LPTIM5_OUT	"lptim5_out"
+
+#define LPTIM1_CH1	"lptim1_ch1"
+#define LPTIM1_CH2	"lptim1_ch2"
+#define LPTIM2_CH1	"lptim2_ch1"
+#define LPTIM2_CH2	"lptim2_ch2"
+#define LPTIM3_CH1	"lptim3_ch1"
+#define LPTIM4_CH1	"lptim4_ch1"
 
 #if IS_REACHABLE(CONFIG_IIO_STM32_LPTIMER_TRIGGER)
 bool is_stm32_lptim_trigger(struct iio_trigger *trig);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 4/8] clocksource: stm32-lptimer: add support for stm32mp25
  2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
                   ` (2 preceding siblings ...)
  2025-03-14 17:14 ` [PATCH v4 3/8] iio: trigger: " Fabrice Gasnier
@ 2025-03-14 17:14 ` Fabrice Gasnier
  2025-04-08 14:48   ` Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 5/8] pwm: stm32-lp: " Fabrice Gasnier
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

On stm32mp25, DIER (former IER) must only be modified when the lptimer
is enabled. On earlier SoCs, it must be only be modified when it is
disabled. There's also a new DIEROK flag, to ensure register access
has completed.
Add a new "set_evt" routine to be used on stm32mp25, called depending
on the version register, read by the MFD core (LPTIM_VERR).

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in V4:
- Daniel suggests to encapsulate IER write into a separate function
  that manages the enabling/disabling of the LP timer. In addition,
  DIEROK and ARROK flags checks have been added. So adopt a new routine
  to set the event into ARR register and enable the interrupt.
Changes in V2:
- rely on fallback compatible as no specific .data is associated to the
  driver. Use version data from MFD core.
- Added interrupt enable register access update in (missed in V1)
---
 drivers/clocksource/timer-stm32-lp.c | 51 +++++++++++++++++++++++++---
 1 file changed, 47 insertions(+), 4 deletions(-)

diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c
index 928da2f6de69..e58932300fb4 100644
--- a/drivers/clocksource/timer-stm32-lp.c
+++ b/drivers/clocksource/timer-stm32-lp.c
@@ -27,6 +27,7 @@ struct stm32_lp_private {
 	u32 psc;
 	struct device *dev;
 	struct clk *clk;
+	u32 version;
 };
 
 static struct stm32_lp_private*
@@ -47,12 +48,37 @@ static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt)
 	return 0;
 }
 
-static int stm32_clkevent_lp_set_timer(unsigned long evt,
-				       struct clock_event_device *clkevt,
-				       int is_periodic)
+static int stm32mp25_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt)
 {
-	struct stm32_lp_private *priv = to_priv(clkevt);
+	int ret;
+	u32 val;
+
+	/* Enable LPTIMER to be able to write into IER and ARR registers */
+	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
+	/* set next event counter */
+	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
+	/* enable ARR interrupt */
+	regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
+
+	/* Poll DIEROK and ARROK to ensure register access has completed */
+	ret = regmap_read_poll_timeout_atomic(priv->reg, STM32_LPTIM_ISR, val,
+					      (val & STM32_LPTIM_DIEROK_ARROK) ==
+					      STM32_LPTIM_DIEROK_ARROK,
+					      10, 500);
+	if (ret) {
+		dev_err(priv->dev, "access to LPTIM timed out\n");
+		/* Disable LPTIMER */
+		regmap_write(priv->reg, STM32_LPTIM_CR, 0);
+		return ret;
+	}
+	/* Clear DIEROK and ARROK flags */
+	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_DIEROKCF_ARROKCF);
+
+	return 0;
+}
 
+static void stm32_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt)
+{
 	/* disable LPTIMER to be able to write into IER register*/
 	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
 	/* enable ARR interrupt */
@@ -61,6 +87,22 @@ static int stm32_clkevent_lp_set_timer(unsigned long evt,
 	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
 	/* set next event counter */
 	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
+}
+
+static int stm32_clkevent_lp_set_timer(unsigned long evt,
+				       struct clock_event_device *clkevt,
+				       int is_periodic)
+{
+	struct stm32_lp_private *priv = to_priv(clkevt);
+	int ret;
+
+	if (priv->version == STM32_LPTIM_VERR_23) {
+		ret = stm32mp25_clkevent_lp_set_evt(priv, evt);
+		if (ret)
+			return ret;
+	} else {
+		stm32_clkevent_lp_set_evt(priv, evt);
+	}
 
 	/* start counter */
 	if (is_periodic)
@@ -176,6 +218,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	priv->reg = ddata->regmap;
+	priv->version = ddata->version;
 	priv->clk = ddata->clk;
 	ret = clk_prepare_enable(priv->clk);
 	if (ret)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 5/8] pwm: stm32-lp: add support for stm32mp25
  2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
                   ` (3 preceding siblings ...)
  2025-03-14 17:14 ` [PATCH v4 4/8] clocksource: " Fabrice Gasnier
@ 2025-03-14 17:14 ` Fabrice Gasnier
  2025-04-04 15:07   ` Uwe Kleine-König
  2025-03-14 17:14 ` [PATCH v4 6/8] arm64: defconfig: enable STM32 LP timer clockevent driver Fabrice Gasnier
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

Add support for STM32MP25 SoC. A new compatible has been added to the
dt-bindings. It represents handle new features, registers and bits
diversity.
It isn't used currently in the driver, as matching is done by retrieving
MFD parent data.

New dedicated capture/compare channels has been added: e.g. a new compare
register for channel 2. Some controls (polarity / cc channel enable) are
handled in CCMR register on this new variant (instead of wavepol bit).

So, Low-power timer can now have up to two PWM outputs. Use device data
from the MFD parent to configure the number of PWM channels e.g. 'npwm'.

Update current get_state() and apply() ops to support either:
- one PWM channel (as on older revision, or LPTIM5 on STM32MP25)
- two PWM channels (e.g. LPTIM1/2/3/4 on STM32MP25 that has the full
  feature set)
Introduce new routines to manage common prescaler, reload register and
global enable bit.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in V2:
- rely on fallback compatible as no specific .data is associated to the
  driver. Matching is achieved by using MFD parent data.
- renamed registers/bits defintions
---
 drivers/pwm/pwm-stm32-lp.c | 219 ++++++++++++++++++++++++++++++++-----
 1 file changed, 193 insertions(+), 26 deletions(-)

diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index 5832dce8ed9d..4789eafb8bac 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -20,6 +20,7 @@
 struct stm32_pwm_lp {
 	struct clk *clk;
 	struct regmap *regmap;
+	unsigned int num_cc_chans;
 };
 
 static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip)
@@ -30,13 +31,101 @@ static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip)
 /* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */
 #define STM32_LPTIM_MAX_PRESCALER	128
 
+static int stm32_pwm_lp_update_allowed(struct stm32_pwm_lp *priv, int channel)
+{
+	int ret;
+	u32 ccmr1;
+	unsigned long ccmr;
+
+	/* Only one PWM on this LPTIMER: enable, prescaler and reload value can be changed */
+	if (!priv->num_cc_chans)
+		return true;
+
+	ret = regmap_read(priv->regmap, STM32_LPTIM_CCMR1, &ccmr1);
+	if (ret)
+		return ret;
+	ccmr = ccmr1 & (STM32_LPTIM_CC1E | STM32_LPTIM_CC2E);
+
+	/* More than one channel enabled: enable, prescaler or ARR value can't be changed */
+	if (bitmap_weight(&ccmr, sizeof(u32) * BITS_PER_BYTE) > 1)
+		return false;
+
+	/*
+	 * Only one channel is enabled (or none): check status on the other channel, to
+	 * report if enable, prescaler or ARR value can be changed.
+	 */
+	if (channel)
+		return !(ccmr1 & STM32_LPTIM_CC1E);
+	else
+		return !(ccmr1 & STM32_LPTIM_CC2E);
+}
+
+static int stm32_pwm_lp_compare_channel_apply(struct stm32_pwm_lp *priv, int channel,
+					      bool enable, enum pwm_polarity polarity)
+{
+	u32 ccmr1, val, mask;
+	bool reenable;
+	int ret;
+
+	/* No dedicated CC channel: nothing to do */
+	if (!priv->num_cc_chans)
+		return 0;
+
+	ret = regmap_read(priv->regmap, STM32_LPTIM_CCMR1, &ccmr1);
+	if (ret)
+		return ret;
+
+	if (channel) {
+		/* Must disable CC channel (CCxE) to modify polarity (CCxP), then re-enable */
+		reenable = (enable && FIELD_GET(STM32_LPTIM_CC2E, ccmr1)) &&
+			(polarity != FIELD_GET(STM32_LPTIM_CC2P, ccmr1));
+
+		mask = STM32_LPTIM_CC2SEL | STM32_LPTIM_CC2E | STM32_LPTIM_CC2P;
+		val = FIELD_PREP(STM32_LPTIM_CC2P, polarity);
+		val |= FIELD_PREP(STM32_LPTIM_CC2E, enable);
+	} else {
+		reenable = (enable && FIELD_GET(STM32_LPTIM_CC1E, ccmr1)) &&
+			(polarity != FIELD_GET(STM32_LPTIM_CC1P, ccmr1));
+
+		mask = STM32_LPTIM_CC1SEL | STM32_LPTIM_CC1E | STM32_LPTIM_CC1P;
+		val = FIELD_PREP(STM32_LPTIM_CC1P, polarity);
+		val |= FIELD_PREP(STM32_LPTIM_CC1E, enable);
+	}
+
+	if (reenable) {
+		u32 cfgr, presc;
+		unsigned long rate;
+		unsigned int delay_us;
+
+		ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CCMR1,
+					 channel ? STM32_LPTIM_CC2E : STM32_LPTIM_CC1E, 0);
+		if (ret)
+			return ret;
+		/*
+		 * After a write to the LPTIM_CCMRx register, a new write operation can only be
+		 * performed after a delay of at least (PRESC × 3) clock cycles
+		 */
+		ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr);
+		if (ret)
+			return ret;
+		presc = FIELD_GET(STM32_LPTIM_PRESC, cfgr);
+		rate = clk_get_rate(priv->clk) >> presc;
+		if (!rate)
+			return -EINVAL;
+		delay_us = 3 * DIV_ROUND_UP(USEC_PER_SEC, rate);
+		usleep_range(delay_us, delay_us * 2);
+	}
+
+	return regmap_update_bits(priv->regmap, STM32_LPTIM_CCMR1, mask, val);
+}
+
 static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 			      const struct pwm_state *state)
 {
 	struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip);
 	unsigned long long prd, div, dty;
 	struct pwm_state cstate;
-	u32 val, mask, cfgr, presc = 0;
+	u32 arr, val, mask, cfgr, presc = 0;
 	bool reenable;
 	int ret;
 
@@ -45,10 +134,28 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	if (!state->enabled) {
 		if (cstate.enabled) {
-			/* Disable LP timer */
-			ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
+			/* Disable CC channel if any */
+			ret = stm32_pwm_lp_compare_channel_apply(priv, pwm->hwpwm, false,
+								 state->polarity);
 			if (ret)
 				return ret;
+			ret = regmap_write(priv->regmap, pwm->hwpwm ?
+					   STM32_LPTIM_CCR2 : STM32_LPTIM_CMP, 0);
+			if (ret)
+				return ret;
+
+			/* Check if the timer can be disabled */
+			ret = stm32_pwm_lp_update_allowed(priv, pwm->hwpwm);
+			if (ret < 0)
+				return ret;
+
+			if (ret) {
+				/* Disable LP timer */
+				ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
+				if (ret)
+					return ret;
+			}
+
 			/* disable clock to PWM counter */
 			clk_disable(priv->clk);
 		}
@@ -79,6 +186,23 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	dty = prd * state->duty_cycle;
 	do_div(dty, state->period);
 
+	ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr);
+	if (ret)
+		return ret;
+
+	/*
+	 * When there are several channels, they share the same prescaler and reload value.
+	 * Check if this can be changed, or the values are the same for all channels.
+	 */
+	if (!stm32_pwm_lp_update_allowed(priv, pwm->hwpwm)) {
+		ret = regmap_read(priv->regmap, STM32_LPTIM_ARR, &arr);
+		if (ret)
+			return ret;
+
+		if ((FIELD_GET(STM32_LPTIM_PRESC, cfgr) != presc) || (arr != prd - 1))
+			return -EBUSY;
+	}
+
 	if (!cstate.enabled) {
 		/* enable clock to drive PWM counter */
 		ret = clk_enable(priv->clk);
@@ -86,15 +210,20 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 			return ret;
 	}
 
-	ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr);
-	if (ret)
-		goto err;
-
 	if ((FIELD_GET(STM32_LPTIM_PRESC, cfgr) != presc) ||
-	    (FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity)) {
+	    ((FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity) && !priv->num_cc_chans)) {
 		val = FIELD_PREP(STM32_LPTIM_PRESC, presc);
-		val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity);
-		mask = STM32_LPTIM_PRESC | STM32_LPTIM_WAVPOL;
+		mask = STM32_LPTIM_PRESC;
+
+		if (!priv->num_cc_chans) {
+			/*
+			 * WAVPOL bit is only available when no capature compare channel is used,
+			 * e.g. on LPTIMER instances that have only one output channel. CCMR1 is
+			 * used otherwise.
+			 */
+			val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity);
+			mask |= STM32_LPTIM_WAVPOL;
+		}
 
 		/* Must disable LP timer to modify CFGR */
 		reenable = true;
@@ -120,20 +249,27 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (ret)
 		goto err;
 
-	ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, prd - (1 + dty));
+	/* Write CMP/CCRx register and ensure it's been properly written */
+	ret = regmap_write(priv->regmap, pwm->hwpwm ? STM32_LPTIM_CCR2 : STM32_LPTIM_CMP,
+			   prd - (1 + dty));
 	if (ret)
 		goto err;
 
-	/* ensure CMP & ARR registers are properly written */
-	ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val,
+	/* ensure ARR and CMP/CCRx registers are properly written */
+	ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, pwm->hwpwm ?
+				       (val & STM32_LPTIM_CMP2_ARROK) == STM32_LPTIM_CMP2_ARROK :
 				       (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK,
 				       100, 1000);
 	if (ret) {
 		dev_err(pwmchip_parent(chip), "ARR/CMP registers write issue\n");
 		goto err;
 	}
-	ret = regmap_write(priv->regmap, STM32_LPTIM_ICR,
-			   STM32_LPTIM_CMPOKCF_ARROKCF);
+	ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, pwm->hwpwm ?
+			   STM32_LPTIM_CMP2OKCF_ARROKCF : STM32_LPTIM_CMPOKCF_ARROKCF);
+	if (ret)
+		goto err;
+
+	ret = stm32_pwm_lp_compare_channel_apply(priv, pwm->hwpwm, true, state->polarity);
 	if (ret)
 		goto err;
 
@@ -161,11 +297,22 @@ static int stm32_pwm_lp_get_state(struct pwm_chip *chip,
 {
 	struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip);
 	unsigned long rate = clk_get_rate(priv->clk);
-	u32 val, presc, prd;
+	u32 val, presc, prd, ccmr1;
+	bool enabled;
 	u64 tmp;
 
 	regmap_read(priv->regmap, STM32_LPTIM_CR, &val);
-	state->enabled = !!FIELD_GET(STM32_LPTIM_ENABLE, val);
+	enabled = !!FIELD_GET(STM32_LPTIM_ENABLE, val);
+	if (priv->num_cc_chans) {
+		/* There's a CC chan, need to also check if it's enabled */
+		regmap_read(priv->regmap, STM32_LPTIM_CCMR1, &ccmr1);
+		if (pwm->hwpwm)
+			enabled &= !!FIELD_GET(STM32_LPTIM_CC2E, ccmr1);
+		else
+			enabled &= !!FIELD_GET(STM32_LPTIM_CC1E, ccmr1);
+	}
+	state->enabled = enabled;
+
 	/* Keep PWM counter clock refcount in sync with PWM initial state */
 	if (state->enabled) {
 		int ret = clk_enable(priv->clk);
@@ -176,14 +323,21 @@ static int stm32_pwm_lp_get_state(struct pwm_chip *chip,
 
 	regmap_read(priv->regmap, STM32_LPTIM_CFGR, &val);
 	presc = FIELD_GET(STM32_LPTIM_PRESC, val);
-	state->polarity = FIELD_GET(STM32_LPTIM_WAVPOL, val);
+	if (priv->num_cc_chans) {
+		if (pwm->hwpwm)
+			state->polarity = FIELD_GET(STM32_LPTIM_CC2P, ccmr1);
+		else
+			state->polarity = FIELD_GET(STM32_LPTIM_CC1P, ccmr1);
+	} else {
+		state->polarity = FIELD_GET(STM32_LPTIM_WAVPOL, val);
+	}
 
 	regmap_read(priv->regmap, STM32_LPTIM_ARR, &prd);
 	tmp = prd + 1;
 	tmp = (tmp << presc) * NSEC_PER_SEC;
 	state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate);
 
-	regmap_read(priv->regmap, STM32_LPTIM_CMP, &val);
+	regmap_read(priv->regmap, pwm->hwpwm ? STM32_LPTIM_CCR2 : STM32_LPTIM_CMP, &val);
 	tmp = prd - val;
 	tmp = (tmp << presc) * NSEC_PER_SEC;
 	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate);
@@ -201,15 +355,25 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
 	struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
 	struct stm32_pwm_lp *priv;
 	struct pwm_chip *chip;
+	unsigned int npwm;
 	int ret;
 
-	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));
+	if (!ddata->num_cc_chans) {
+		/* No dedicated CC channel, so there's only one PWM channel */
+		npwm = 1;
+	} else {
+		/* There are dedicated CC channels, each with one PWM output */
+		npwm = ddata->num_cc_chans;
+	}
+
+	chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*priv));
 	if (IS_ERR(chip))
 		return PTR_ERR(chip);
 	priv = to_stm32_pwm_lp(chip);
 
 	priv->regmap = ddata->regmap;
 	priv->clk = ddata->clk;
+	priv->num_cc_chans = ddata->num_cc_chans;
 	chip->ops = &stm32_pwm_lp_ops;
 
 	ret = devm_pwmchip_add(&pdev->dev, chip);
@@ -225,12 +389,15 @@ static int stm32_pwm_lp_suspend(struct device *dev)
 {
 	struct pwm_chip *chip = dev_get_drvdata(dev);
 	struct pwm_state state;
-
-	pwm_get_state(&chip->pwms[0], &state);
-	if (state.enabled) {
-		dev_err(dev, "The consumer didn't stop us (%s)\n",
-			chip->pwms[0].label);
-		return -EBUSY;
+	unsigned int i;
+
+	for (i = 0; i < chip->npwm; i++) {
+		pwm_get_state(&chip->pwms[i], &state);
+		if (state.enabled) {
+			dev_err(dev, "The consumer didn't stop us (%s)\n",
+				chip->pwms[i].label);
+			return -EBUSY;
+		}
 	}
 
 	return pinctrl_pm_select_sleep_state(dev);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 6/8] arm64: defconfig: enable STM32 LP timer clockevent driver
  2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
                   ` (4 preceding siblings ...)
  2025-03-14 17:14 ` [PATCH v4 5/8] pwm: stm32-lp: " Fabrice Gasnier
@ 2025-03-14 17:14 ` Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 7/8] arm64: dts: st: add low-power timer nodes on stm32mp251 Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 8/8] arm64: dts: st: use lptimer3 as tick broadcast source on stm32mp257f-ev1 Fabrice Gasnier
  7 siblings, 0 replies; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

Enable the STM32 LP timer MFD core and clockevent drivers used on
STM32MP257F-EV1 board, for PSCI OSI.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in v2:
- dropped unused IIO trigger, PWM and counter driver unused on upstream
board currently, as advised by Krzysztof
---
 arch/arm64/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 1f25423de383..b29b2350ae27 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -775,6 +775,7 @@ CONFIG_MFD_TI_LP873X=m
 CONFIG_MFD_TPS65219=y
 CONFIG_MFD_TPS6594_I2C=m
 CONFIG_MFD_ROHM_BD718XX=y
+CONFIG_MFD_STM32_LPTIMER=m
 CONFIG_MFD_WCD934X=m
 CONFIG_MFD_KHADAS_MCU=m
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -1401,6 +1402,7 @@ CONFIG_CLK_RENESAS_VBATTB=m
 CONFIG_HWSPINLOCK=y
 CONFIG_HWSPINLOCK_QCOM=y
 CONFIG_TEGRA186_TIMER=y
+CONFIG_CLKSRC_STM32_LP=y
 CONFIG_RENESAS_OSTM=y
 CONFIG_ARM_MHU=y
 CONFIG_IMX_MBOX=y
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 7/8] arm64: dts: st: add low-power timer nodes on stm32mp251
  2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
                   ` (5 preceding siblings ...)
  2025-03-14 17:14 ` [PATCH v4 6/8] arm64: defconfig: enable STM32 LP timer clockevent driver Fabrice Gasnier
@ 2025-03-14 17:14 ` Fabrice Gasnier
  2025-03-14 17:14 ` [PATCH v4 8/8] arm64: dts: st: use lptimer3 as tick broadcast source on stm32mp257f-ev1 Fabrice Gasnier
  7 siblings, 0 replies; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

Add low-power timer (LPTimer) support on STM32MP25 SoC.
The full feature set is implemented in LPTIM1/2/3/4. LPTIM5 supports a
smaller set of features (no capture/compare) channel. Still, LPTIM5 can
be used as single PWM, counter, trigger or timer.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in V2:
- Adopt two compatibles: newly introduced "st,stm32mp25-..." compatible,
  and fallback "st,stm32-...".
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 177 +++++++++++++++++++++++++
 1 file changed, 177 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index f3c6cdfd7008..505176276e72 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -238,6 +238,78 @@ rifsc: bus@42080000 {
 			#access-controller-cells = <1>;
 			ranges;
 
+			lptimer1: timer@40090000 {
+				compatible = "st,stm32mp25-lptimer", "st,stm32-lptimer";
+				reg = <0x40090000 0x400>;
+				interrupts-extended = <&exti1 47 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&rcc CK_KER_LPTIM1>;
+				clock-names = "mux";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				access-controllers = <&rifsc 17>;
+				power-domains = <&RET_PD>;
+				wakeup-source;
+				status = "disabled";
+
+				counter {
+					compatible = "st,stm32mp25-lptimer-counter", "st,stm32-lptimer-counter";
+					status = "disabled";
+				};
+
+				pwm {
+					compatible = "st,stm32mp25-pwm-lp", "st,stm32-pwm-lp";
+					#pwm-cells = <3>;
+					status = "disabled";
+				};
+
+				timer {
+					compatible = "st,stm32mp25-lptimer-timer", "st,stm32-lptimer-timer";
+					status = "disabled";
+				};
+
+				trigger@0 {
+					compatible = "st,stm32mp25-lptimer-trigger", "st,stm32-lptimer-trigger";
+					reg = <0>;
+					status = "disabled";
+				};
+			};
+
+			lptimer2: timer@400a0000 {
+				compatible = "st,stm32mp25-lptimer", "st,stm32-lptimer";
+				reg = <0x400a0000 0x400>;
+				interrupts-extended = <&exti1 48 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&rcc CK_KER_LPTIM2>;
+				clock-names = "mux";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				access-controllers = <&rifsc 18>;
+				power-domains = <&RET_PD>;
+				wakeup-source;
+				status = "disabled";
+
+				counter {
+					compatible = "st,stm32mp25-lptimer-counter", "st,stm32-lptimer-counter";
+					status = "disabled";
+				};
+
+				pwm {
+					compatible = "st,stm32mp25-pwm-lp", "st,stm32-pwm-lp";
+					#pwm-cells = <3>;
+					status = "disabled";
+				};
+
+				timer {
+					compatible = "st,stm32mp25-lptimer-timer", "st,stm32-lptimer-timer";
+					status = "disabled";
+				};
+
+				trigger@1 {
+					compatible = "st,stm32mp25-lptimer-trigger", "st,stm32-lptimer-trigger";
+					reg = <1>;
+					status = "disabled";
+				};
+			};
+
 			i2s2: audio-controller@400b0000 {
 				compatible = "st,stm32mp25-i2s";
 				reg = <0x400b0000 0x400>;
@@ -799,6 +871,111 @@ i2c8: i2c@46040000 {
 				status = "disabled";
 			};
 
+			lptimer3: timer@46050000 {
+				compatible = "st,stm32mp25-lptimer", "st,stm32-lptimer";
+				reg = <0x46050000 0x400>;
+				interrupts-extended = <&exti2 29 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&rcc CK_KER_LPTIM3>;
+				clock-names = "mux";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				access-controllers = <&rifsc 19>;
+				wakeup-source;
+				status = "disabled";
+
+				counter {
+					compatible = "st,stm32mp25-lptimer-counter", "st,stm32-lptimer-counter";
+					status = "disabled";
+				};
+
+				pwm {
+					compatible = "st,stm32mp25-pwm-lp", "st,stm32-pwm-lp";
+					#pwm-cells = <3>;
+					status = "disabled";
+				};
+
+				timer {
+					compatible = "st,stm32mp25-lptimer-timer", "st,stm32-lptimer-timer";
+					status = "disabled";
+				};
+
+				trigger@2 {
+					compatible = "st,stm32mp25-lptimer-trigger", "st,stm32-lptimer-trigger";
+					reg = <2>;
+					status = "disabled";
+				};
+			};
+
+			lptimer4: timer@46060000 {
+				compatible = "st,stm32mp25-lptimer", "st,stm32-lptimer";
+				reg = <0x46060000 0x400>;
+				interrupts-extended = <&exti2 30 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&rcc CK_KER_LPTIM4>;
+				clock-names = "mux";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				access-controllers = <&rifsc 20>;
+				wakeup-source;
+				status = "disabled";
+
+				counter {
+					compatible = "st,stm32mp25-lptimer-counter", "st,stm32-lptimer-counter";
+					status = "disabled";
+				};
+
+				pwm {
+					compatible = "st,stm32mp25-pwm-lp", "st,stm32-pwm-lp";
+					#pwm-cells = <3>;
+					status = "disabled";
+				};
+
+				timer {
+					compatible = "st,stm32mp25-lptimer-timer", "st,stm32-lptimer-timer";
+					status = "disabled";
+				};
+
+				trigger@3 {
+					compatible = "st,stm32mp25-lptimer-trigger", "st,stm32-lptimer-trigger";
+					reg = <3>;
+					status = "disabled";
+				};
+			};
+
+			lptimer5: timer@46070000 {
+				compatible = "st,stm32mp25-lptimer", "st,stm32-lptimer";
+				reg = <0x46070000 0x400>;
+				interrupts-extended = <&exti2 31 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&rcc CK_KER_LPTIM5>;
+				clock-names = "mux";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				access-controllers = <&rifsc 21>;
+				wakeup-source;
+				status = "disabled";
+
+				counter {
+					compatible = "st,stm32mp25-lptimer-counter", "st,stm32-lptimer-counter";
+					status = "disabled";
+				};
+
+				pwm {
+					compatible = "st,stm32mp25-pwm-lp", "st,stm32-pwm-lp";
+					#pwm-cells = <3>;
+					status = "disabled";
+				};
+
+				timer {
+					compatible = "st,stm32mp25-lptimer-timer", "st,stm32-lptimer-timer";
+					status = "disabled";
+				};
+
+				trigger@4 {
+					compatible = "st,stm32mp25-lptimer-trigger", "st,stm32-lptimer-trigger";
+					reg = <4>;
+					status = "disabled";
+				};
+			};
+
 			csi: csi@48020000 {
 				compatible = "st,stm32mp25-csi";
 				reg = <0x48020000 0x2000>;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 8/8] arm64: dts: st: use lptimer3 as tick broadcast source on stm32mp257f-ev1
  2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
                   ` (6 preceding siblings ...)
  2025-03-14 17:14 ` [PATCH v4 7/8] arm64: dts: st: add low-power timer nodes on stm32mp251 Fabrice Gasnier
@ 2025-03-14 17:14 ` Fabrice Gasnier
  7 siblings, 0 replies; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-14 17:14 UTC (permalink / raw)
  To: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx
  Cc: robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan, fabrice.gasnier

During the low power modes the generic ARM timer is deactivated, so the
the tick broadcast is used, based on LPTIMER3 which is clocked by LSE on
STMicroelectronics boards.

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index 1b88485a62a1..242115863ab4 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -190,6 +190,14 @@ &i2c8 {
 	status = "disabled";
 };
 
+/* use LPTIMER with tick broadcast for suspend mode */
+&lptimer3 {
+	status = "okay";
+	timer {
+		status = "okay";
+	};
+};
+
 &rtc {
 	status = "okay";
 };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 3/8] iio: trigger: stm32-lptimer: add support for stm32mp25
  2025-03-14 17:14 ` [PATCH v4 3/8] iio: trigger: " Fabrice Gasnier
@ 2025-03-15 12:56   ` Jonathan Cameron
  2025-03-27 16:36     ` Fabrice Gasnier
  0 siblings, 1 reply; 17+ messages in thread
From: Jonathan Cameron @ 2025-03-15 12:56 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt,
	daniel.lezcano, tglx, robh, catalin.marinas, will, devicetree,
	wbg, linux-stm32, linux-arm-kernel, linux-kernel, linux-iio,
	linux-pwm, olivier.moysan

On Fri, 14 Mar 2025 18:14:46 +0100
Fabrice Gasnier <fabrice.gasnier@foss.st.com> wrote:

> From: Olivier Moysan <olivier.moysan@foss.st.com>
> 
> Add support for STM32MP25 SoC. Use newly introduced compatible to handle
> this new HW variant. Add new trigger definitions that can be used by the
> stm32 analog-to-digital converter. Use compatible data to identify them.
> 
> Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>

How do you want this to merge?   If it's going through mfd because
of dependencies, then
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

I haven't checked if there are any dependencies so shout if I should
pick this up directly for next cycle.

Thanks,

Jonathan


> ---
> Changes in v4:
> - Jonathan's comment: simplify infrastructure by keeping
>   devm_iio_trigger_register. Don't need to cast compatible data.
> ---
>  drivers/iio/trigger/stm32-lptimer-trigger.c   | 75 ++++++++++++++-----
>  include/linux/iio/timer/stm32-lptim-trigger.h |  9 +++
>  2 files changed, 67 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c
> index f1e18913236a..3dcc8d2fe093 100644
> --- a/drivers/iio/trigger/stm32-lptimer-trigger.c
> +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c
> @@ -16,16 +16,43 @@
>  #include <linux/platform_device.h>
>  #include <linux/property.h>
>  
> -/* List Low-Power Timer triggers */
> -static const char * const stm32_lptim_triggers[] = {
> -	LPTIM1_OUT,
> -	LPTIM2_OUT,
> -	LPTIM3_OUT,
> +/* Maximum triggers + one trailing null entry to indicate the end of array */
> +#define MAX_TRIGGERS 3
> +
> +struct stm32_lptim_cfg {
> +	const char * const (*triggers)[MAX_TRIGGERS];
> +	unsigned int nb_triggers;
> +};
> +
> +/* List Low-Power Timer triggers for H7, MP13, MP15 */
> +static const char * const stm32_lptim_triggers[][MAX_TRIGGERS] = {
> +	{ LPTIM1_OUT,},
> +	{ LPTIM2_OUT,},
> +	{ LPTIM3_OUT,},
> +};
> +
> +/* List Low-Power Timer triggers for STM32MP25 */
> +static const char * const stm32mp25_lptim_triggers[][MAX_TRIGGERS] = {
> +	{ LPTIM1_CH1, LPTIM1_CH2, },
> +	{ LPTIM2_CH1, LPTIM2_CH2, },
> +	{ LPTIM3_CH1,},
> +	{ LPTIM4_CH1,},
> +	{ LPTIM5_OUT,},
> +};
> +
> +static const struct stm32_lptim_cfg stm32mp15_lptim_cfg = {
> +	.triggers = stm32_lptim_triggers,
> +	.nb_triggers = ARRAY_SIZE(stm32_lptim_triggers),
> +};
> +
> +static const struct stm32_lptim_cfg stm32mp25_lptim_cfg = {
> +	.triggers = stm32mp25_lptim_triggers,
> +	.nb_triggers = ARRAY_SIZE(stm32mp25_lptim_triggers),
>  };
>  
>  struct stm32_lptim_trigger {
>  	struct device *dev;
> -	const char *trg;
> +	const char * const *triggers;
>  };
>  
>  static int stm32_lptim_validate_device(struct iio_trigger *trig,
> @@ -56,22 +83,33 @@ EXPORT_SYMBOL(is_stm32_lptim_trigger);
>  
>  static int stm32_lptim_setup_trig(struct stm32_lptim_trigger *priv)
>  {
> -	struct iio_trigger *trig;
> +	const char * const *cur = priv->triggers;
> +	int ret;
>  
> -	trig = devm_iio_trigger_alloc(priv->dev, "%s", priv->trg);
> -	if  (!trig)
> -		return -ENOMEM;
> +	while (cur && *cur) {
> +		struct iio_trigger *trig;
>  
> -	trig->dev.parent = priv->dev->parent;
> -	trig->ops = &stm32_lptim_trigger_ops;
> -	iio_trigger_set_drvdata(trig, priv);
> +		trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
> +		if  (!trig)
> +			return -ENOMEM;
>  
> -	return devm_iio_trigger_register(priv->dev, trig);
> +		trig->dev.parent = priv->dev->parent;
> +		trig->ops = &stm32_lptim_trigger_ops;
> +		iio_trigger_set_drvdata(trig, priv);
> +
> +		ret = devm_iio_trigger_register(priv->dev, trig);
> +		if (ret)
> +			return ret;
> +		cur++;
> +	}
> +
> +	return 0;
>  }
>  
>  static int stm32_lptim_trigger_probe(struct platform_device *pdev)
>  {
>  	struct stm32_lptim_trigger *priv;
> +	struct stm32_lptim_cfg const *lptim_cfg;
>  	u32 index;
>  
>  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> @@ -81,17 +119,20 @@ static int stm32_lptim_trigger_probe(struct platform_device *pdev)
>  	if (device_property_read_u32(&pdev->dev, "reg", &index))
>  		return -EINVAL;
>  
> -	if (index >= ARRAY_SIZE(stm32_lptim_triggers))
> +	lptim_cfg = device_get_match_data(&pdev->dev);
> +
> +	if (index >= lptim_cfg->nb_triggers)
>  		return -EINVAL;
>  
>  	priv->dev = &pdev->dev;
> -	priv->trg = stm32_lptim_triggers[index];
> +	priv->triggers = lptim_cfg->triggers[index];
>  
>  	return stm32_lptim_setup_trig(priv);
>  }
>  
>  static const struct of_device_id stm32_lptim_trig_of_match[] = {
> -	{ .compatible = "st,stm32-lptimer-trigger", },
> +	{ .compatible = "st,stm32-lptimer-trigger", .data = &stm32mp15_lptim_cfg },
> +	{ .compatible = "st,stm32mp25-lptimer-trigger", .data = &stm32mp25_lptim_cfg},
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, stm32_lptim_trig_of_match);
> diff --git a/include/linux/iio/timer/stm32-lptim-trigger.h b/include/linux/iio/timer/stm32-lptim-trigger.h
> index a34dcf6a6001..ce3cf0addb2e 100644
> --- a/include/linux/iio/timer/stm32-lptim-trigger.h
> +++ b/include/linux/iio/timer/stm32-lptim-trigger.h
> @@ -14,6 +14,15 @@
>  #define LPTIM1_OUT	"lptim1_out"
>  #define LPTIM2_OUT	"lptim2_out"
>  #define LPTIM3_OUT	"lptim3_out"
> +#define LPTIM4_OUT	"lptim4_out"
> +#define LPTIM5_OUT	"lptim5_out"
> +
> +#define LPTIM1_CH1	"lptim1_ch1"
> +#define LPTIM1_CH2	"lptim1_ch2"
> +#define LPTIM2_CH1	"lptim2_ch1"
> +#define LPTIM2_CH2	"lptim2_ch2"
> +#define LPTIM3_CH1	"lptim3_ch1"
> +#define LPTIM4_CH1	"lptim4_ch1"
>  
>  #if IS_REACHABLE(CONFIG_IIO_STM32_LPTIMER_TRIGGER)
>  bool is_stm32_lptim_trigger(struct iio_trigger *trig);


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 3/8] iio: trigger: stm32-lptimer: add support for stm32mp25
  2025-03-15 12:56   ` Jonathan Cameron
@ 2025-03-27 16:36     ` Fabrice Gasnier
  2025-03-31 10:04       ` Jonathan Cameron
  0 siblings, 1 reply; 17+ messages in thread
From: Fabrice Gasnier @ 2025-03-27 16:36 UTC (permalink / raw)
  To: Jonathan Cameron, lee
  Cc: ukleinek, alexandre.torgue, krzk+dt, conor+dt, daniel.lezcano,
	tglx, robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan

On 3/15/25 13:56, Jonathan Cameron wrote:
> On Fri, 14 Mar 2025 18:14:46 +0100
> Fabrice Gasnier <fabrice.gasnier@foss.st.com> wrote:
> 
>> From: Olivier Moysan <olivier.moysan@foss.st.com>
>>
>> Add support for STM32MP25 SoC. Use newly introduced compatible to handle
>> this new HW variant. Add new trigger definitions that can be used by the
>> stm32 analog-to-digital converter. Use compatible data to identify them.
>>
>> Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> 
> How do you want this to merge?   If it's going through mfd because
> of dependencies, then
> Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> 
> I haven't checked if there are any dependencies so shout if I should
> pick this up directly for next cycle.

Hi Jonathan, Lee,

There's no build dependency, but the dt-bindings that adds the
compatible string.

Perhaps Lee can pick it up along with the mfd bindings and driver ?

I'm not sure what the most suitable option is.

Best Regards,
Fabrice
> 
> Thanks,
> 
> Jonathan
> 
> 
>> ---
>> Changes in v4:
>> - Jonathan's comment: simplify infrastructure by keeping
>>   devm_iio_trigger_register. Don't need to cast compatible data.
>> ---
>>  drivers/iio/trigger/stm32-lptimer-trigger.c   | 75 ++++++++++++++-----
>>  include/linux/iio/timer/stm32-lptim-trigger.h |  9 +++
>>  2 files changed, 67 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c
>> index f1e18913236a..3dcc8d2fe093 100644
>> --- a/drivers/iio/trigger/stm32-lptimer-trigger.c
>> +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c
>> @@ -16,16 +16,43 @@
>>  #include <linux/platform_device.h>
>>  #include <linux/property.h>
>>  
>> -/* List Low-Power Timer triggers */
>> -static const char * const stm32_lptim_triggers[] = {
>> -	LPTIM1_OUT,
>> -	LPTIM2_OUT,
>> -	LPTIM3_OUT,
>> +/* Maximum triggers + one trailing null entry to indicate the end of array */
>> +#define MAX_TRIGGERS 3
>> +
>> +struct stm32_lptim_cfg {
>> +	const char * const (*triggers)[MAX_TRIGGERS];
>> +	unsigned int nb_triggers;
>> +};
>> +
>> +/* List Low-Power Timer triggers for H7, MP13, MP15 */
>> +static const char * const stm32_lptim_triggers[][MAX_TRIGGERS] = {
>> +	{ LPTIM1_OUT,},
>> +	{ LPTIM2_OUT,},
>> +	{ LPTIM3_OUT,},
>> +};
>> +
>> +/* List Low-Power Timer triggers for STM32MP25 */
>> +static const char * const stm32mp25_lptim_triggers[][MAX_TRIGGERS] = {
>> +	{ LPTIM1_CH1, LPTIM1_CH2, },
>> +	{ LPTIM2_CH1, LPTIM2_CH2, },
>> +	{ LPTIM3_CH1,},
>> +	{ LPTIM4_CH1,},
>> +	{ LPTIM5_OUT,},
>> +};
>> +
>> +static const struct stm32_lptim_cfg stm32mp15_lptim_cfg = {
>> +	.triggers = stm32_lptim_triggers,
>> +	.nb_triggers = ARRAY_SIZE(stm32_lptim_triggers),
>> +};
>> +
>> +static const struct stm32_lptim_cfg stm32mp25_lptim_cfg = {
>> +	.triggers = stm32mp25_lptim_triggers,
>> +	.nb_triggers = ARRAY_SIZE(stm32mp25_lptim_triggers),
>>  };
>>  
>>  struct stm32_lptim_trigger {
>>  	struct device *dev;
>> -	const char *trg;
>> +	const char * const *triggers;
>>  };
>>  
>>  static int stm32_lptim_validate_device(struct iio_trigger *trig,
>> @@ -56,22 +83,33 @@ EXPORT_SYMBOL(is_stm32_lptim_trigger);
>>  
>>  static int stm32_lptim_setup_trig(struct stm32_lptim_trigger *priv)
>>  {
>> -	struct iio_trigger *trig;
>> +	const char * const *cur = priv->triggers;
>> +	int ret;
>>  
>> -	trig = devm_iio_trigger_alloc(priv->dev, "%s", priv->trg);
>> -	if  (!trig)
>> -		return -ENOMEM;
>> +	while (cur && *cur) {
>> +		struct iio_trigger *trig;
>>  
>> -	trig->dev.parent = priv->dev->parent;
>> -	trig->ops = &stm32_lptim_trigger_ops;
>> -	iio_trigger_set_drvdata(trig, priv);
>> +		trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
>> +		if  (!trig)
>> +			return -ENOMEM;
>>  
>> -	return devm_iio_trigger_register(priv->dev, trig);
>> +		trig->dev.parent = priv->dev->parent;
>> +		trig->ops = &stm32_lptim_trigger_ops;
>> +		iio_trigger_set_drvdata(trig, priv);
>> +
>> +		ret = devm_iio_trigger_register(priv->dev, trig);
>> +		if (ret)
>> +			return ret;
>> +		cur++;
>> +	}
>> +
>> +	return 0;
>>  }
>>  
>>  static int stm32_lptim_trigger_probe(struct platform_device *pdev)
>>  {
>>  	struct stm32_lptim_trigger *priv;
>> +	struct stm32_lptim_cfg const *lptim_cfg;
>>  	u32 index;
>>  
>>  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>> @@ -81,17 +119,20 @@ static int stm32_lptim_trigger_probe(struct platform_device *pdev)
>>  	if (device_property_read_u32(&pdev->dev, "reg", &index))
>>  		return -EINVAL;
>>  
>> -	if (index >= ARRAY_SIZE(stm32_lptim_triggers))
>> +	lptim_cfg = device_get_match_data(&pdev->dev);
>> +
>> +	if (index >= lptim_cfg->nb_triggers)
>>  		return -EINVAL;
>>  
>>  	priv->dev = &pdev->dev;
>> -	priv->trg = stm32_lptim_triggers[index];
>> +	priv->triggers = lptim_cfg->triggers[index];
>>  
>>  	return stm32_lptim_setup_trig(priv);
>>  }
>>  
>>  static const struct of_device_id stm32_lptim_trig_of_match[] = {
>> -	{ .compatible = "st,stm32-lptimer-trigger", },
>> +	{ .compatible = "st,stm32-lptimer-trigger", .data = &stm32mp15_lptim_cfg },
>> +	{ .compatible = "st,stm32mp25-lptimer-trigger", .data = &stm32mp25_lptim_cfg},
>>  	{},
>>  };
>>  MODULE_DEVICE_TABLE(of, stm32_lptim_trig_of_match);
>> diff --git a/include/linux/iio/timer/stm32-lptim-trigger.h b/include/linux/iio/timer/stm32-lptim-trigger.h
>> index a34dcf6a6001..ce3cf0addb2e 100644
>> --- a/include/linux/iio/timer/stm32-lptim-trigger.h
>> +++ b/include/linux/iio/timer/stm32-lptim-trigger.h
>> @@ -14,6 +14,15 @@
>>  #define LPTIM1_OUT	"lptim1_out"
>>  #define LPTIM2_OUT	"lptim2_out"
>>  #define LPTIM3_OUT	"lptim3_out"
>> +#define LPTIM4_OUT	"lptim4_out"
>> +#define LPTIM5_OUT	"lptim5_out"
>> +
>> +#define LPTIM1_CH1	"lptim1_ch1"
>> +#define LPTIM1_CH2	"lptim1_ch2"
>> +#define LPTIM2_CH1	"lptim2_ch1"
>> +#define LPTIM2_CH2	"lptim2_ch2"
>> +#define LPTIM3_CH1	"lptim3_ch1"
>> +#define LPTIM4_CH1	"lptim4_ch1"
>>  
>>  #if IS_REACHABLE(CONFIG_IIO_STM32_LPTIMER_TRIGGER)
>>  bool is_stm32_lptim_trigger(struct iio_trigger *trig);
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 3/8] iio: trigger: stm32-lptimer: add support for stm32mp25
  2025-03-27 16:36     ` Fabrice Gasnier
@ 2025-03-31 10:04       ` Jonathan Cameron
  0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Cameron @ 2025-03-31 10:04 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: lee, ukleinek, alexandre.torgue, krzk+dt, conor+dt,
	daniel.lezcano, tglx, robh, catalin.marinas, will, devicetree,
	wbg, linux-stm32, linux-arm-kernel, linux-kernel, linux-iio,
	linux-pwm, olivier.moysan

On Thu, 27 Mar 2025 17:36:00 +0100
Fabrice Gasnier <fabrice.gasnier@foss.st.com> wrote:

> On 3/15/25 13:56, Jonathan Cameron wrote:
> > On Fri, 14 Mar 2025 18:14:46 +0100
> > Fabrice Gasnier <fabrice.gasnier@foss.st.com> wrote:
> >   
> >> From: Olivier Moysan <olivier.moysan@foss.st.com>
> >>
> >> Add support for STM32MP25 SoC. Use newly introduced compatible to handle
> >> this new HW variant. Add new trigger definitions that can be used by the
> >> stm32 analog-to-digital converter. Use compatible data to identify them.
> >>
> >> Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
> >> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>  
> > 
> > How do you want this to merge?   If it's going through mfd because
> > of dependencies, then
> > Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > 
> > I haven't checked if there are any dependencies so shout if I should
> > pick this up directly for next cycle.  
> 
> Hi Jonathan, Lee,
> 
> There's no build dependency, but the dt-bindings that adds the
> compatible string.
> 
> Perhaps Lee can pick it up along with the mfd bindings and driver ?
> 
> I'm not sure what the most suitable option is.
We don't normally worry if bindings and driver end up going through different
trees.  Applied this patch to the testing branch of iio.git. I'll rebase
on rc1 once available and push out as normal togreg branch.

Thanks,

Jonathan
> 
> Best Regards,
> Fabrice
> > 
> > Thanks,
> > 
> > Jonathan
> > 
> >   
> >> ---
> >> Changes in v4:
> >> - Jonathan's comment: simplify infrastructure by keeping
> >>   devm_iio_trigger_register. Don't need to cast compatible data.
> >> ---
> >>  drivers/iio/trigger/stm32-lptimer-trigger.c   | 75 ++++++++++++++-----
> >>  include/linux/iio/timer/stm32-lptim-trigger.h |  9 +++
> >>  2 files changed, 67 insertions(+), 17 deletions(-)
> >>
> >> diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c
> >> index f1e18913236a..3dcc8d2fe093 100644
> >> --- a/drivers/iio/trigger/stm32-lptimer-trigger.c
> >> +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c
> >> @@ -16,16 +16,43 @@
> >>  #include <linux/platform_device.h>
> >>  #include <linux/property.h>
> >>  
> >> -/* List Low-Power Timer triggers */
> >> -static const char * const stm32_lptim_triggers[] = {
> >> -	LPTIM1_OUT,
> >> -	LPTIM2_OUT,
> >> -	LPTIM3_OUT,
> >> +/* Maximum triggers + one trailing null entry to indicate the end of array */
> >> +#define MAX_TRIGGERS 3
> >> +
> >> +struct stm32_lptim_cfg {
> >> +	const char * const (*triggers)[MAX_TRIGGERS];
> >> +	unsigned int nb_triggers;
> >> +};
> >> +
> >> +/* List Low-Power Timer triggers for H7, MP13, MP15 */
> >> +static const char * const stm32_lptim_triggers[][MAX_TRIGGERS] = {
> >> +	{ LPTIM1_OUT,},
> >> +	{ LPTIM2_OUT,},
> >> +	{ LPTIM3_OUT,},
> >> +};
> >> +
> >> +/* List Low-Power Timer triggers for STM32MP25 */
> >> +static const char * const stm32mp25_lptim_triggers[][MAX_TRIGGERS] = {
> >> +	{ LPTIM1_CH1, LPTIM1_CH2, },
> >> +	{ LPTIM2_CH1, LPTIM2_CH2, },
> >> +	{ LPTIM3_CH1,},
> >> +	{ LPTIM4_CH1,},
> >> +	{ LPTIM5_OUT,},
> >> +};
> >> +
> >> +static const struct stm32_lptim_cfg stm32mp15_lptim_cfg = {
> >> +	.triggers = stm32_lptim_triggers,
> >> +	.nb_triggers = ARRAY_SIZE(stm32_lptim_triggers),
> >> +};
> >> +
> >> +static const struct stm32_lptim_cfg stm32mp25_lptim_cfg = {
> >> +	.triggers = stm32mp25_lptim_triggers,
> >> +	.nb_triggers = ARRAY_SIZE(stm32mp25_lptim_triggers),
> >>  };
> >>  
> >>  struct stm32_lptim_trigger {
> >>  	struct device *dev;
> >> -	const char *trg;
> >> +	const char * const *triggers;
> >>  };
> >>  
> >>  static int stm32_lptim_validate_device(struct iio_trigger *trig,
> >> @@ -56,22 +83,33 @@ EXPORT_SYMBOL(is_stm32_lptim_trigger);
> >>  
> >>  static int stm32_lptim_setup_trig(struct stm32_lptim_trigger *priv)
> >>  {
> >> -	struct iio_trigger *trig;
> >> +	const char * const *cur = priv->triggers;
> >> +	int ret;
> >>  
> >> -	trig = devm_iio_trigger_alloc(priv->dev, "%s", priv->trg);
> >> -	if  (!trig)
> >> -		return -ENOMEM;
> >> +	while (cur && *cur) {
> >> +		struct iio_trigger *trig;
> >>  
> >> -	trig->dev.parent = priv->dev->parent;
> >> -	trig->ops = &stm32_lptim_trigger_ops;
> >> -	iio_trigger_set_drvdata(trig, priv);
> >> +		trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
> >> +		if  (!trig)
> >> +			return -ENOMEM;
> >>  
> >> -	return devm_iio_trigger_register(priv->dev, trig);
> >> +		trig->dev.parent = priv->dev->parent;
> >> +		trig->ops = &stm32_lptim_trigger_ops;
> >> +		iio_trigger_set_drvdata(trig, priv);
> >> +
> >> +		ret = devm_iio_trigger_register(priv->dev, trig);
> >> +		if (ret)
> >> +			return ret;
> >> +		cur++;
> >> +	}
> >> +
> >> +	return 0;
> >>  }
> >>  
> >>  static int stm32_lptim_trigger_probe(struct platform_device *pdev)
> >>  {
> >>  	struct stm32_lptim_trigger *priv;
> >> +	struct stm32_lptim_cfg const *lptim_cfg;
> >>  	u32 index;
> >>  
> >>  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> >> @@ -81,17 +119,20 @@ static int stm32_lptim_trigger_probe(struct platform_device *pdev)
> >>  	if (device_property_read_u32(&pdev->dev, "reg", &index))
> >>  		return -EINVAL;
> >>  
> >> -	if (index >= ARRAY_SIZE(stm32_lptim_triggers))
> >> +	lptim_cfg = device_get_match_data(&pdev->dev);
> >> +
> >> +	if (index >= lptim_cfg->nb_triggers)
> >>  		return -EINVAL;
> >>  
> >>  	priv->dev = &pdev->dev;
> >> -	priv->trg = stm32_lptim_triggers[index];
> >> +	priv->triggers = lptim_cfg->triggers[index];
> >>  
> >>  	return stm32_lptim_setup_trig(priv);
> >>  }
> >>  
> >>  static const struct of_device_id stm32_lptim_trig_of_match[] = {
> >> -	{ .compatible = "st,stm32-lptimer-trigger", },
> >> +	{ .compatible = "st,stm32-lptimer-trigger", .data = &stm32mp15_lptim_cfg },
> >> +	{ .compatible = "st,stm32mp25-lptimer-trigger", .data = &stm32mp25_lptim_cfg},
> >>  	{},
> >>  };
> >>  MODULE_DEVICE_TABLE(of, stm32_lptim_trig_of_match);
> >> diff --git a/include/linux/iio/timer/stm32-lptim-trigger.h b/include/linux/iio/timer/stm32-lptim-trigger.h
> >> index a34dcf6a6001..ce3cf0addb2e 100644
> >> --- a/include/linux/iio/timer/stm32-lptim-trigger.h
> >> +++ b/include/linux/iio/timer/stm32-lptim-trigger.h
> >> @@ -14,6 +14,15 @@
> >>  #define LPTIM1_OUT	"lptim1_out"
> >>  #define LPTIM2_OUT	"lptim2_out"
> >>  #define LPTIM3_OUT	"lptim3_out"
> >> +#define LPTIM4_OUT	"lptim4_out"
> >> +#define LPTIM5_OUT	"lptim5_out"
> >> +
> >> +#define LPTIM1_CH1	"lptim1_ch1"
> >> +#define LPTIM1_CH2	"lptim1_ch2"
> >> +#define LPTIM2_CH1	"lptim2_ch1"
> >> +#define LPTIM2_CH2	"lptim2_ch2"
> >> +#define LPTIM3_CH1	"lptim3_ch1"
> >> +#define LPTIM4_CH1	"lptim4_ch1"
> >>  
> >>  #if IS_REACHABLE(CONFIG_IIO_STM32_LPTIMER_TRIGGER)
> >>  bool is_stm32_lptim_trigger(struct iio_trigger *trig);  
> >   


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 2/8] mfd: stm32-lptimer: add support for stm32mp25
  2025-03-14 17:14 ` [PATCH v4 2/8] " Fabrice Gasnier
@ 2025-04-04 14:40   ` Lee Jones
  2025-04-24 13:01     ` Lee Jones
  0 siblings, 1 reply; 17+ messages in thread
From: Lee Jones @ 2025-04-04 14:40 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx, robh, catalin.marinas, will, devicetree,
	wbg, linux-stm32, linux-arm-kernel, linux-kernel, linux-iio,
	linux-pwm, olivier.moysan

On Fri, 14 Mar 2025, Fabrice Gasnier wrote:

> Add support for STM32MP25 SoC.
> A new hardware configuration register (HWCFGR2) has been added, to gather
> number of capture/compare channels, autonomous mode and input capture
> capability. The full feature set is implemented in LPTIM1/2/3/4. LPTIM5
> supports a smaller set of features. This can now be read from HWCFGR
> registers.
> 
> Add new registers to the stm32-lptimer.h: CCMR1, CCR2, HWCFGR1/2 and VERR.
> Update the stm32_lptimer data struct so signal the number of
> capture/compare channels to the child devices.
> Also Remove some unused bit masks (CMPOK_ARROK / CMPOKCF_ARROKCF).
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> ---
> Changes in V4:
> - Add DIEROK, ARROK status flags, and their clear flags.
> Changes in V2:
> - rely on fallback compatible as no specific .data is associated to the
>   driver. Compatibility is added by reading hardware configuration
>   registers.
> - read version register, to be used by clockevent child driver
> - rename register/bits definitions
> ---
>  drivers/mfd/stm32-lptimer.c       | 33 ++++++++++++++++++++++++++-
>  include/linux/mfd/stm32-lptimer.h | 37 ++++++++++++++++++++++++++++---

At least the Clocksource driver depends on this.

I need Acks from the other Maintainers before I can merge this.

-- 
Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 5/8] pwm: stm32-lp: add support for stm32mp25
  2025-03-14 17:14 ` [PATCH v4 5/8] pwm: stm32-lp: " Fabrice Gasnier
@ 2025-04-04 15:07   ` Uwe Kleine-König
  0 siblings, 0 replies; 17+ messages in thread
From: Uwe Kleine-König @ 2025-04-04 15:07 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: lee, alexandre.torgue, krzk+dt, conor+dt, jic23, daniel.lezcano,
	tglx, robh, catalin.marinas, will, devicetree, wbg, linux-stm32,
	linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
	olivier.moysan

[-- Attachment #1: Type: text/plain, Size: 1302 bytes --]

Hello,

On Fri, Mar 14, 2025 at 06:14:48PM +0100, Fabrice Gasnier wrote:
> Add support for STM32MP25 SoC. A new compatible has been added to the
> dt-bindings. It represents handle new features, registers and bits
> diversity.
> It isn't used currently in the driver, as matching is done by retrieving
> MFD parent data.
> 
> New dedicated capture/compare channels has been added: e.g. a new compare
> register for channel 2. Some controls (polarity / cc channel enable) are
> handled in CCMR register on this new variant (instead of wavepol bit).
> 
> So, Low-power timer can now have up to two PWM outputs. Use device data
> from the MFD parent to configure the number of PWM channels e.g. 'npwm'.
> 
> Update current get_state() and apply() ops to support either:
> - one PWM channel (as on older revision, or LPTIM5 on STM32MP25)
> - two PWM channels (e.g. LPTIM1/2/3/4 on STM32MP25 that has the full
>   feature set)
> Introduce new routines to manage common prescaler, reload register and
> global enable bit.
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>

I didn't do an in-depth review, but the patch looks fine to me.
It's ok for me if Lee picks this up for v6.16-rc1, so:

Acked-by: Uwe Kleine-König <ukleinek@kernel.org>

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 4/8] clocksource: stm32-lptimer: add support for stm32mp25
  2025-03-14 17:14 ` [PATCH v4 4/8] clocksource: " Fabrice Gasnier
@ 2025-04-08 14:48   ` Fabrice Gasnier
  0 siblings, 0 replies; 17+ messages in thread
From: Fabrice Gasnier @ 2025-04-08 14:48 UTC (permalink / raw)
  To: lee, alexandre.torgue, daniel.lezcano, tglx
  Cc: krzk+dt, jic23, conor+dt, ukleinek, robh, catalin.marinas, will,
	devicetree, wbg, linux-stm32, linux-arm-kernel, linux-kernel,
	linux-iio, linux-pwm, olivier.moysan

On 3/14/25 18:14, Fabrice Gasnier wrote:
> On stm32mp25, DIER (former IER) must only be modified when the lptimer
> is enabled. On earlier SoCs, it must be only be modified when it is
> disabled. There's also a new DIEROK flag, to ensure register access
> has completed.
> Add a new "set_evt" routine to be used on stm32mp25, called depending
> on the version register, read by the MFD core (LPTIM_VERR).
> 
> Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> ---
> Changes in V4:
> - Daniel suggests to encapsulate IER write into a separate function
>   that manages the enabling/disabling of the LP timer. In addition,
>   DIEROK and ARROK flags checks have been added. So adopt a new routine
>   to set the event into ARR register and enable the interrupt.

Hi all, Daniel,

Does anybody else have additional remarks on this driver ?

I think Lee is waiting for review, before merging the MFD part (at least).

Best Regards,
Thanks,
Fabrice

> Changes in V2:
> - rely on fallback compatible as no specific .data is associated to the
>   driver. Use version data from MFD core.
> - Added interrupt enable register access update in (missed in V1)
> ---
>  drivers/clocksource/timer-stm32-lp.c | 51 +++++++++++++++++++++++++---
>  1 file changed, 47 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c
> index 928da2f6de69..e58932300fb4 100644
> --- a/drivers/clocksource/timer-stm32-lp.c
> +++ b/drivers/clocksource/timer-stm32-lp.c
> @@ -27,6 +27,7 @@ struct stm32_lp_private {
>  	u32 psc;
>  	struct device *dev;
>  	struct clk *clk;
> +	u32 version;
>  };
>  
>  static struct stm32_lp_private*
> @@ -47,12 +48,37 @@ static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt)
>  	return 0;
>  }
>  
> -static int stm32_clkevent_lp_set_timer(unsigned long evt,
> -				       struct clock_event_device *clkevt,
> -				       int is_periodic)
> +static int stm32mp25_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt)
>  {
> -	struct stm32_lp_private *priv = to_priv(clkevt);
> +	int ret;
> +	u32 val;
> +
> +	/* Enable LPTIMER to be able to write into IER and ARR registers */
> +	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
> +	/* set next event counter */
> +	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
> +	/* enable ARR interrupt */
> +	regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
> +
> +	/* Poll DIEROK and ARROK to ensure register access has completed */
> +	ret = regmap_read_poll_timeout_atomic(priv->reg, STM32_LPTIM_ISR, val,
> +					      (val & STM32_LPTIM_DIEROK_ARROK) ==
> +					      STM32_LPTIM_DIEROK_ARROK,
> +					      10, 500);
> +	if (ret) {
> +		dev_err(priv->dev, "access to LPTIM timed out\n");
> +		/* Disable LPTIMER */
> +		regmap_write(priv->reg, STM32_LPTIM_CR, 0);
> +		return ret;
> +	}
> +	/* Clear DIEROK and ARROK flags */
> +	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_DIEROKCF_ARROKCF);
> +
> +	return 0;
> +}
>  
> +static void stm32_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt)
> +{
>  	/* disable LPTIMER to be able to write into IER register*/
>  	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
>  	/* enable ARR interrupt */
> @@ -61,6 +87,22 @@ static int stm32_clkevent_lp_set_timer(unsigned long evt,
>  	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
>  	/* set next event counter */
>  	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
> +}
> +
> +static int stm32_clkevent_lp_set_timer(unsigned long evt,
> +				       struct clock_event_device *clkevt,
> +				       int is_periodic)
> +{
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +	int ret;
> +
> +	if (priv->version == STM32_LPTIM_VERR_23) {
> +		ret = stm32mp25_clkevent_lp_set_evt(priv, evt);
> +		if (ret)
> +			return ret;
> +	} else {
> +		stm32_clkevent_lp_set_evt(priv, evt);
> +	}
>  
>  	/* start counter */
>  	if (is_periodic)
> @@ -176,6 +218,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  
>  	priv->reg = ddata->regmap;
> +	priv->version = ddata->version;
>  	priv->clk = ddata->clk;
>  	ret = clk_prepare_enable(priv->clk);
>  	if (ret)

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 2/8] mfd: stm32-lptimer: add support for stm32mp25
  2025-04-04 14:40   ` Lee Jones
@ 2025-04-24 13:01     ` Lee Jones
  2025-04-25 12:50       ` Fabrice Gasnier
  0 siblings, 1 reply; 17+ messages in thread
From: Lee Jones @ 2025-04-24 13:01 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx, robh, catalin.marinas, will, devicetree,
	wbg, linux-stm32, linux-arm-kernel, linux-kernel, linux-iio,
	linux-pwm, olivier.moysan

On Fri, 04 Apr 2025, Lee Jones wrote:

> On Fri, 14 Mar 2025, Fabrice Gasnier wrote:
> 
> > Add support for STM32MP25 SoC.
> > A new hardware configuration register (HWCFGR2) has been added, to gather
> > number of capture/compare channels, autonomous mode and input capture
> > capability. The full feature set is implemented in LPTIM1/2/3/4. LPTIM5
> > supports a smaller set of features. This can now be read from HWCFGR
> > registers.
> > 
> > Add new registers to the stm32-lptimer.h: CCMR1, CCR2, HWCFGR1/2 and VERR.
> > Update the stm32_lptimer data struct so signal the number of
> > capture/compare channels to the child devices.
> > Also Remove some unused bit masks (CMPOK_ARROK / CMPOKCF_ARROKCF).
> > 
> > Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> > ---
> > Changes in V4:
> > - Add DIEROK, ARROK status flags, and their clear flags.
> > Changes in V2:
> > - rely on fallback compatible as no specific .data is associated to the
> >   driver. Compatibility is added by reading hardware configuration
> >   registers.
> > - read version register, to be used by clockevent child driver
> > - rename register/bits definitions
> > ---
> >  drivers/mfd/stm32-lptimer.c       | 33 ++++++++++++++++++++++++++-
> >  include/linux/mfd/stm32-lptimer.h | 37 ++++++++++++++++++++++++++++---
> 
> At least the Clocksource driver depends on this.
> 
> I need Acks from the other Maintainers before I can merge this.

Suggest you resubmit the set as a [RESEND] to re-gain traction.

-- 
Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 2/8] mfd: stm32-lptimer: add support for stm32mp25
  2025-04-24 13:01     ` Lee Jones
@ 2025-04-25 12:50       ` Fabrice Gasnier
  0 siblings, 0 replies; 17+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:50 UTC (permalink / raw)
  To: Lee Jones
  Cc: ukleinek, alexandre.torgue, krzk+dt, conor+dt, jic23,
	daniel.lezcano, tglx, robh, catalin.marinas, will, devicetree,
	wbg, linux-stm32, linux-arm-kernel, linux-kernel, linux-iio,
	linux-pwm, olivier.moysan

On 4/24/25 15:01, Lee Jones wrote:
> On Fri, 04 Apr 2025, Lee Jones wrote:
> 
>> On Fri, 14 Mar 2025, Fabrice Gasnier wrote:
>>
>>> Add support for STM32MP25 SoC.
>>> A new hardware configuration register (HWCFGR2) has been added, to gather
>>> number of capture/compare channels, autonomous mode and input capture
>>> capability. The full feature set is implemented in LPTIM1/2/3/4. LPTIM5
>>> supports a smaller set of features. This can now be read from HWCFGR
>>> registers.
>>>
>>> Add new registers to the stm32-lptimer.h: CCMR1, CCR2, HWCFGR1/2 and VERR.
>>> Update the stm32_lptimer data struct so signal the number of
>>> capture/compare channels to the child devices.
>>> Also Remove some unused bit masks (CMPOK_ARROK / CMPOKCF_ARROKCF).
>>>
>>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
>>> ---
>>> Changes in V4:
>>> - Add DIEROK, ARROK status flags, and their clear flags.
>>> Changes in V2:
>>> - rely on fallback compatible as no specific .data is associated to the
>>>   driver. Compatibility is added by reading hardware configuration
>>>   registers.
>>> - read version register, to be used by clockevent child driver
>>> - rename register/bits definitions
>>> ---
>>>  drivers/mfd/stm32-lptimer.c       | 33 ++++++++++++++++++++++++++-
>>>  include/linux/mfd/stm32-lptimer.h | 37 ++++++++++++++++++++++++++++---
>>
>> At least the Clocksource driver depends on this.
>>
>> I need Acks from the other Maintainers before I can merge this.
> 
> Suggest you resubmit the set as a [RESEND] to re-gain traction.
> 

Hi Lee,

Thanks for suggesting.
I recently found I needed to add a small delay in clocksource driver. So
I just have sent a V5.

Best Regards,
Fabrice

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2025-04-25 12:53 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-14 17:14 [PATCH v4 0/8] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
2025-03-14 17:14 ` [PATCH v4 1/8] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25 Fabrice Gasnier
2025-03-14 17:14 ` [PATCH v4 2/8] " Fabrice Gasnier
2025-04-04 14:40   ` Lee Jones
2025-04-24 13:01     ` Lee Jones
2025-04-25 12:50       ` Fabrice Gasnier
2025-03-14 17:14 ` [PATCH v4 3/8] iio: trigger: " Fabrice Gasnier
2025-03-15 12:56   ` Jonathan Cameron
2025-03-27 16:36     ` Fabrice Gasnier
2025-03-31 10:04       ` Jonathan Cameron
2025-03-14 17:14 ` [PATCH v4 4/8] clocksource: " Fabrice Gasnier
2025-04-08 14:48   ` Fabrice Gasnier
2025-03-14 17:14 ` [PATCH v4 5/8] pwm: stm32-lp: " Fabrice Gasnier
2025-04-04 15:07   ` Uwe Kleine-König
2025-03-14 17:14 ` [PATCH v4 6/8] arm64: defconfig: enable STM32 LP timer clockevent driver Fabrice Gasnier
2025-03-14 17:14 ` [PATCH v4 7/8] arm64: dts: st: add low-power timer nodes on stm32mp251 Fabrice Gasnier
2025-03-14 17:14 ` [PATCH v4 8/8] arm64: dts: st: use lptimer3 as tick broadcast source on stm32mp257f-ev1 Fabrice Gasnier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).