* [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource
@ 2025-04-25 12:47 Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 1/7] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25 Fabrice Gasnier
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:47 UTC (permalink / raw)
To: lee, alexandre.torgue, daniel.lezcano, tglx
Cc: ukleinek, krzk+dt, conor+dt, jic23, 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 V5
---
- Add a necessary delay in clocksource driver, when enabling the timer.
- Add collected Acks
- Dropped IIO trigger patch as applied by Jonathan [1] (no dependency)
[1] https://lore.kernel.org/all/20250331110435.26157ebe@jic23-huawei/
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
.../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 | 60 ++++-
drivers/mfd/stm32-lptimer.c | 33 ++-
drivers/pwm/pwm-stm32-lp.c | 219 +++++++++++++++---
include/linux/mfd/stm32-lptimer.h | 37 ++-
8 files changed, 536 insertions(+), 40 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v5 1/7] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25
2025-04-25 12:47 [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
@ 2025-04-25 12:47 ` Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 2/7] " Fabrice Gasnier
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:47 UTC (permalink / raw)
To: lee, alexandre.torgue, daniel.lezcano, tglx
Cc: ukleinek, krzk+dt, conor+dt, jic23, 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] 9+ messages in thread
* [PATCH v5 2/7] mfd: stm32-lptimer: add support for stm32mp25
2025-04-25 12:47 [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 1/7] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25 Fabrice Gasnier
@ 2025-04-25 12:47 ` Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 3/7] clocksource: " Fabrice Gasnier
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:47 UTC (permalink / raw)
To: lee, alexandre.torgue, daniel.lezcano, tglx
Cc: ukleinek, krzk+dt, conor+dt, jic23, 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] 9+ messages in thread
* [PATCH v5 3/7] clocksource: stm32-lptimer: add support for stm32mp25
2025-04-25 12:47 [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 1/7] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25 Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 2/7] " Fabrice Gasnier
@ 2025-04-25 12:47 ` Fabrice Gasnier
2025-04-26 7:01 ` kernel test robot
2025-04-25 12:47 ` [PATCH v5 4/7] pwm: stm32-lp: " Fabrice Gasnier
` (3 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:47 UTC (permalink / raw)
To: lee, alexandre.torgue, daniel.lezcano, tglx
Cc: ukleinek, krzk+dt, conor+dt, jic23, 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 V5:
- Added a delay after timer enable, it needs two clock cycles.
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 | 60 ++++++++++++++++++++++++++--
1 file changed, 56 insertions(+), 4 deletions(-)
diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c
index 928da2f6de69..a214ff6edbae 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,46 @@ 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;
+
+ regmap_read(priv->reg, STM32_LPTIM_CR, &val);
+ if (!val & STM32_LPTIM_ENABLE) {
+ /* Enable LPTIMER to be able to write into IER and ARR registers */
+ regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
+ /*
+ * After setting the ENABLE bit, a delay of two counter clock cycles is needed
+ * before the LPTIM is actually enabled. For 32KHz rate, this makes approximately
+ * 62.5 micro-seconds, round it up.
+ */
+ udelay(63);
+ }
+ /* 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 +96,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 +227,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] 9+ messages in thread
* [PATCH v5 4/7] pwm: stm32-lp: add support for stm32mp25
2025-04-25 12:47 [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
` (2 preceding siblings ...)
2025-04-25 12:47 ` [PATCH v5 3/7] clocksource: " Fabrice Gasnier
@ 2025-04-25 12:47 ` Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 5/7] arm64: defconfig: enable STM32 LP timer clockevent driver Fabrice Gasnier
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:47 UTC (permalink / raw)
To: lee, alexandre.torgue, daniel.lezcano, tglx
Cc: ukleinek, krzk+dt, conor+dt, jic23, 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.
Acked-by: Uwe Kleine-König <ukleinek@kernel.org>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Changes in V5:
- Add Uwe's Acked-by
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] 9+ messages in thread
* [PATCH v5 5/7] arm64: defconfig: enable STM32 LP timer clockevent driver
2025-04-25 12:47 [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
` (3 preceding siblings ...)
2025-04-25 12:47 ` [PATCH v5 4/7] pwm: stm32-lp: " Fabrice Gasnier
@ 2025-04-25 12:47 ` Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 6/7] arm64: dts: st: add low-power timer nodes on stm32mp251 Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 7/7] arm64: dts: st: use lptimer3 as tick broadcast source on stm32mp257f-ev1 Fabrice Gasnier
6 siblings, 0 replies; 9+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:47 UTC (permalink / raw)
To: lee, alexandre.torgue, daniel.lezcano, tglx
Cc: ukleinek, krzk+dt, conor+dt, jic23, 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 5bb8f09422a2..d106cdac05fa 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -777,6 +777,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
@@ -1414,6 +1415,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] 9+ messages in thread
* [PATCH v5 6/7] arm64: dts: st: add low-power timer nodes on stm32mp251
2025-04-25 12:47 [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
` (4 preceding siblings ...)
2025-04-25 12:47 ` [PATCH v5 5/7] arm64: defconfig: enable STM32 LP timer clockevent driver Fabrice Gasnier
@ 2025-04-25 12:47 ` Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 7/7] arm64: dts: st: use lptimer3 as tick broadcast source on stm32mp257f-ev1 Fabrice Gasnier
6 siblings, 0 replies; 9+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:47 UTC (permalink / raw)
To: lee, alexandre.torgue, daniel.lezcano, tglx
Cc: ukleinek, krzk+dt, conor+dt, jic23, 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] 9+ messages in thread
* [PATCH v5 7/7] arm64: dts: st: use lptimer3 as tick broadcast source on stm32mp257f-ev1
2025-04-25 12:47 [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
` (5 preceding siblings ...)
2025-04-25 12:47 ` [PATCH v5 6/7] arm64: dts: st: add low-power timer nodes on stm32mp251 Fabrice Gasnier
@ 2025-04-25 12:47 ` Fabrice Gasnier
6 siblings, 0 replies; 9+ messages in thread
From: Fabrice Gasnier @ 2025-04-25 12:47 UTC (permalink / raw)
To: lee, alexandre.torgue, daniel.lezcano, tglx
Cc: ukleinek, krzk+dt, conor+dt, jic23, 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] 9+ messages in thread
* Re: [PATCH v5 3/7] clocksource: stm32-lptimer: add support for stm32mp25
2025-04-25 12:47 ` [PATCH v5 3/7] clocksource: " Fabrice Gasnier
@ 2025-04-26 7:01 ` kernel test robot
0 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2025-04-26 7:01 UTC (permalink / raw)
To: Fabrice Gasnier, lee, alexandre.torgue, daniel.lezcano, tglx
Cc: llvm, oe-kbuild-all, ukleinek, krzk+dt, conor+dt, jic23, robh,
catalin.marinas, will, devicetree, wbg, linux-stm32,
linux-arm-kernel, linux-kernel, linux-iio, linux-pwm,
olivier.moysan, fabrice.gasnier
Hi Fabrice,
kernel test robot noticed the following build warnings:
[auto build test WARNING on lee-mfd/for-mfd-next]
[also build test WARNING on lee-leds/for-leds-next linus/master v6.15-rc3 next-20250424]
[cannot apply to atorgue-stm32/stm32-next lee-mfd/for-mfd-fixes]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Fabrice-Gasnier/dt-bindings-mfd-stm32-lptimer-add-support-for-stm32mp25/20250425-210409
base: https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-next
patch link: https://lore.kernel.org/r/20250425124755.166193-4-fabrice.gasnier%40foss.st.com
patch subject: [PATCH v5 3/7] clocksource: stm32-lptimer: add support for stm32mp25
config: arm-randconfig-003-20250426 (https://download.01.org/0day-ci/archive/20250426/202504261456.aCATBoYN-lkp@intel.com/config)
compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project f819f46284f2a79790038e1f6649172789734ae8)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250426/202504261456.aCATBoYN-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504261456.aCATBoYN-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/clocksource/timer-stm32-lp.c:57:6: warning: logical not is only applied to the left hand side of this bitwise operator [-Wlogical-not-parentheses]
57 | if (!val & STM32_LPTIM_ENABLE) {
| ^ ~
drivers/clocksource/timer-stm32-lp.c:57:6: note: add parentheses after the '!' to evaluate the bitwise operator first
57 | if (!val & STM32_LPTIM_ENABLE) {
| ^
| ( )
drivers/clocksource/timer-stm32-lp.c:57:6: note: add parentheses around left hand side expression to silence this warning
57 | if (!val & STM32_LPTIM_ENABLE) {
| ^
| ( )
1 warning generated.
vim +57 drivers/clocksource/timer-stm32-lp.c
50
51 static int stm32mp25_clkevent_lp_set_evt(struct stm32_lp_private *priv, unsigned long evt)
52 {
53 int ret;
54 u32 val;
55
56 regmap_read(priv->reg, STM32_LPTIM_CR, &val);
> 57 if (!val & STM32_LPTIM_ENABLE) {
58 /* Enable LPTIMER to be able to write into IER and ARR registers */
59 regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
60 /*
61 * After setting the ENABLE bit, a delay of two counter clock cycles is needed
62 * before the LPTIM is actually enabled. For 32KHz rate, this makes approximately
63 * 62.5 micro-seconds, round it up.
64 */
65 udelay(63);
66 }
67 /* set next event counter */
68 regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
69 /* enable ARR interrupt */
70 regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
71
72 /* Poll DIEROK and ARROK to ensure register access has completed */
73 ret = regmap_read_poll_timeout_atomic(priv->reg, STM32_LPTIM_ISR, val,
74 (val & STM32_LPTIM_DIEROK_ARROK) ==
75 STM32_LPTIM_DIEROK_ARROK,
76 10, 500);
77 if (ret) {
78 dev_err(priv->dev, "access to LPTIM timed out\n");
79 /* Disable LPTIMER */
80 regmap_write(priv->reg, STM32_LPTIM_CR, 0);
81 return ret;
82 }
83 /* Clear DIEROK and ARROK flags */
84 regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_DIEROKCF_ARROKCF);
85
86 return 0;
87 }
88
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-04-26 7:01 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-25 12:47 [PATCH v5 0/7] Add STM32MP25 LPTIM support: MFD, PWM, IIO, counter, clocksource Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 1/7] dt-bindings: mfd: stm32-lptimer: add support for stm32mp25 Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 2/7] " Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 3/7] clocksource: " Fabrice Gasnier
2025-04-26 7:01 ` kernel test robot
2025-04-25 12:47 ` [PATCH v5 4/7] pwm: stm32-lp: " Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 5/7] arm64: defconfig: enable STM32 LP timer clockevent driver Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 6/7] arm64: dts: st: add low-power timer nodes on stm32mp251 Fabrice Gasnier
2025-04-25 12:47 ` [PATCH v5 7/7] 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).