All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/6] clockevent: add low power STM32 timer
@ 2020-04-20 12:16 ` Benjamin Gaignard
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	Benjamin Gaignard

This series add low power timer as boadcast clockevent device.
Low power timer could runs even when CPUs are in idle mode and 
could wakeup them.

Lee has acked the MFD part.
Clocksource driver still need to be reviewed by maintainers.
Add missing part of the bindings to describe interrupt.

version 7:
- rebased on top of v5.7-rc2

version 6:
- simplify binding, DT and code to use only one interrupt

version 5:
- document interrupts and interrupt-names bindings
- use a different wake up interrupt
- add device-tree patch
- make STM32MP157 select low power timer configuration flag
- enable fast_io in regmap configuration

version 4:
- move defines in mfd/stm32-lptimer.h
- change compatible and subnode names
- document wakeup-source property
- reword commit message
- make driver Kconfig depends of MFD_STM32_LPTIMER
- remove useless include
- remove rate and clk fields from the private structure
- to add comments about the registers sequence in stm32_clkevent_lp_set_timer
- rework probe function and use devm_request_irq()
- do not allow module to be removed

version 3:
- fix timer set sequence
- don't forget to free irq on remove function
- use devm_kzalloc to simplify errors handling in probe function

version 2:
- stm32 clkevent driver is now a child of the stm32 lp timer node
- add a probe function and adpat the driver to use regmap provide
  by it parent
- stop using timer_of helpers


Benjamin Gaignard (6):
  dt-bindings: mfd: Document STM32 low power timer bindings
  ARM: dts: stm32: Add timer subnodes on stm32mp15 SoCs
  mfd: stm32: Add defines to be used for clkevent purpose
  mfd: stm32: enable regmap fast_io for stm32-lptimer
  clocksource: Add Low Power STM32 timers driver
  ARM: mach-stm32: select low power timer for STM32MP157

 .../devicetree/bindings/mfd/st,stm32-lptimer.yaml  |   5 +
 arch/arm/boot/dts/stm32mp151.dtsi                  |  35 ++++
 arch/arm/mach-stm32/Kconfig                        |   1 +
 drivers/clocksource/Kconfig                        |   4 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-stm32-lp.c               | 221 +++++++++++++++++++++
 drivers/mfd/stm32-lptimer.c                        |   1 +
 include/linux/mfd/stm32-lptimer.h                  |   5 +
 8 files changed, 273 insertions(+)
 create mode 100644 drivers/clocksource/timer-stm32-lp.c

-- 
2.15.0


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

* [PATCH v7 0/6] clockevent: add low power STM32 timer
@ 2020-04-20 12:16 ` Benjamin Gaignard
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: Benjamin Gaignard, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel

This series add low power timer as boadcast clockevent device.
Low power timer could runs even when CPUs are in idle mode and 
could wakeup them.

Lee has acked the MFD part.
Clocksource driver still need to be reviewed by maintainers.
Add missing part of the bindings to describe interrupt.

version 7:
- rebased on top of v5.7-rc2

version 6:
- simplify binding, DT and code to use only one interrupt

version 5:
- document interrupts and interrupt-names bindings
- use a different wake up interrupt
- add device-tree patch
- make STM32MP157 select low power timer configuration flag
- enable fast_io in regmap configuration

version 4:
- move defines in mfd/stm32-lptimer.h
- change compatible and subnode names
- document wakeup-source property
- reword commit message
- make driver Kconfig depends of MFD_STM32_LPTIMER
- remove useless include
- remove rate and clk fields from the private structure
- to add comments about the registers sequence in stm32_clkevent_lp_set_timer
- rework probe function and use devm_request_irq()
- do not allow module to be removed

version 3:
- fix timer set sequence
- don't forget to free irq on remove function
- use devm_kzalloc to simplify errors handling in probe function

version 2:
- stm32 clkevent driver is now a child of the stm32 lp timer node
- add a probe function and adpat the driver to use regmap provide
  by it parent
- stop using timer_of helpers


Benjamin Gaignard (6):
  dt-bindings: mfd: Document STM32 low power timer bindings
  ARM: dts: stm32: Add timer subnodes on stm32mp15 SoCs
  mfd: stm32: Add defines to be used for clkevent purpose
  mfd: stm32: enable regmap fast_io for stm32-lptimer
  clocksource: Add Low Power STM32 timers driver
  ARM: mach-stm32: select low power timer for STM32MP157

 .../devicetree/bindings/mfd/st,stm32-lptimer.yaml  |   5 +
 arch/arm/boot/dts/stm32mp151.dtsi                  |  35 ++++
 arch/arm/mach-stm32/Kconfig                        |   1 +
 drivers/clocksource/Kconfig                        |   4 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-stm32-lp.c               | 221 +++++++++++++++++++++
 drivers/mfd/stm32-lptimer.c                        |   1 +
 include/linux/mfd/stm32-lptimer.h                  |   5 +
 8 files changed, 273 insertions(+)
 create mode 100644 drivers/clocksource/timer-stm32-lp.c

-- 
2.15.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v7 1/6] dt-bindings: mfd: Document STM32 low power timer bindings
  2020-04-20 12:16 ` Benjamin Gaignard
@ 2020-04-20 12:16   ` Benjamin Gaignard
  -1 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	Benjamin Gaignard

Add a subnode to STM low power timer bindings to support timer driver

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml b/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
index ddf190cb800b..2a99b2296d2b 100644
--- a/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
+++ b/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
@@ -33,6 +33,9 @@ properties:
     items:
       - const: mux
 
+  interrupts:
+    maxItems: 1
+
   "#address-cells":
     const: 1
 
@@ -106,11 +109,13 @@ additionalProperties: false
 examples:
   - |
     #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
     timer@40002400 {
       compatible = "st,stm32-lptimer";
       reg = <0x40002400 0x400>;
       clocks = <&timer_clk>;
       clock-names = "mux";
+      interrupts-extended = <&exti 47 IRQ_TYPE_LEVEL_HIGH>;
       #address-cells = <1>;
       #size-cells = <0>;
 
-- 
2.15.0


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

* [PATCH v7 1/6] dt-bindings: mfd: Document STM32 low power timer bindings
@ 2020-04-20 12:16   ` Benjamin Gaignard
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: Benjamin Gaignard, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel

Add a subnode to STM low power timer bindings to support timer driver

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml b/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
index ddf190cb800b..2a99b2296d2b 100644
--- a/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
+++ b/Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml
@@ -33,6 +33,9 @@ properties:
     items:
       - const: mux
 
+  interrupts:
+    maxItems: 1
+
   "#address-cells":
     const: 1
 
@@ -106,11 +109,13 @@ additionalProperties: false
 examples:
   - |
     #include <dt-bindings/clock/stm32mp1-clks.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
     timer@40002400 {
       compatible = "st,stm32-lptimer";
       reg = <0x40002400 0x400>;
       clocks = <&timer_clk>;
       clock-names = "mux";
+      interrupts-extended = <&exti 47 IRQ_TYPE_LEVEL_HIGH>;
       #address-cells = <1>;
       #size-cells = <0>;
 
-- 
2.15.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v7 2/6] ARM: dts: stm32: Add timer subnodes on stm32mp15 SoCs
  2020-04-20 12:16 ` Benjamin Gaignard
@ 2020-04-20 12:16   ` Benjamin Gaignard
  -1 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	Benjamin Gaignard

Add timer subnode and interrupts to low power timer nodes for
all stm32mp15x SoCs.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 arch/arm/boot/dts/stm32mp151.dtsi | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi
index 3ea05ba48215..5e881e8d0f58 100644
--- a/arch/arm/boot/dts/stm32mp151.dtsi
+++ b/arch/arm/boot/dts/stm32mp151.dtsi
@@ -359,6 +359,8 @@
 			reg = <0x40009000 0x400>;
 			clocks = <&rcc LPTIM1_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 47 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -377,6 +379,11 @@
 				compatible = "st,stm32-lptimer-counter";
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		spi2: spi@4000b000 {
@@ -1144,6 +1151,8 @@
 			reg = <0x50021000 0x400>;
 			clocks = <&rcc LPTIM2_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 48 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -1162,6 +1171,11 @@
 				compatible = "st,stm32-lptimer-counter";
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		lptimer3: timer@50022000 {
@@ -1171,6 +1185,8 @@
 			reg = <0x50022000 0x400>;
 			clocks = <&rcc LPTIM3_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 50 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -1184,6 +1200,11 @@
 				reg = <2>;
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		lptimer4: timer@50023000 {
@@ -1191,6 +1212,8 @@
 			reg = <0x50023000 0x400>;
 			clocks = <&rcc LPTIM4_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 52 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -1198,6 +1221,11 @@
 				#pwm-cells = <3>;
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		lptimer5: timer@50024000 {
@@ -1205,6 +1233,8 @@
 			reg = <0x50024000 0x400>;
 			clocks = <&rcc LPTIM5_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 53 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -1212,6 +1242,11 @@
 				#pwm-cells = <3>;
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		vrefbuf: vrefbuf@50025000 {
-- 
2.15.0


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

* [PATCH v7 2/6] ARM: dts: stm32: Add timer subnodes on stm32mp15 SoCs
@ 2020-04-20 12:16   ` Benjamin Gaignard
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: Benjamin Gaignard, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel

Add timer subnode and interrupts to low power timer nodes for
all stm32mp15x SoCs.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 arch/arm/boot/dts/stm32mp151.dtsi | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi
index 3ea05ba48215..5e881e8d0f58 100644
--- a/arch/arm/boot/dts/stm32mp151.dtsi
+++ b/arch/arm/boot/dts/stm32mp151.dtsi
@@ -359,6 +359,8 @@
 			reg = <0x40009000 0x400>;
 			clocks = <&rcc LPTIM1_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 47 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -377,6 +379,11 @@
 				compatible = "st,stm32-lptimer-counter";
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		spi2: spi@4000b000 {
@@ -1144,6 +1151,8 @@
 			reg = <0x50021000 0x400>;
 			clocks = <&rcc LPTIM2_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 48 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -1162,6 +1171,11 @@
 				compatible = "st,stm32-lptimer-counter";
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		lptimer3: timer@50022000 {
@@ -1171,6 +1185,8 @@
 			reg = <0x50022000 0x400>;
 			clocks = <&rcc LPTIM3_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 50 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -1184,6 +1200,11 @@
 				reg = <2>;
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		lptimer4: timer@50023000 {
@@ -1191,6 +1212,8 @@
 			reg = <0x50023000 0x400>;
 			clocks = <&rcc LPTIM4_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 52 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -1198,6 +1221,11 @@
 				#pwm-cells = <3>;
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		lptimer5: timer@50024000 {
@@ -1205,6 +1233,8 @@
 			reg = <0x50024000 0x400>;
 			clocks = <&rcc LPTIM5_K>;
 			clock-names = "mux";
+			interrupts-extended = <&exti 53 IRQ_TYPE_LEVEL_HIGH>;
+			wakeup-source;
 			status = "disabled";
 
 			pwm {
@@ -1212,6 +1242,11 @@
 				#pwm-cells = <3>;
 				status = "disabled";
 			};
+
+			timer {
+				compatible = "st,stm32-lptimer-timer";
+				status = "disabled";
+			};
 		};
 
 		vrefbuf: vrefbuf@50025000 {
-- 
2.15.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v7 3/6] mfd: stm32: Add defines to be used for clkevent purpose
  2020-04-20 12:16 ` Benjamin Gaignard
@ 2020-04-20 12:16   ` Benjamin Gaignard
  -1 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	Benjamin Gaignard

Add defines to be able to enable/clear irq and configure one shot mode.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 include/linux/mfd/stm32-lptimer.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/mfd/stm32-lptimer.h b/include/linux/mfd/stm32-lptimer.h
index 605f62264825..90b20550c1c8 100644
--- a/include/linux/mfd/stm32-lptimer.h
+++ b/include/linux/mfd/stm32-lptimer.h
@@ -27,10 +27,15 @@
 #define STM32_LPTIM_CMPOK		BIT(3)
 
 /* STM32_LPTIM_ICR - bit fields */
+#define STM32_LPTIM_ARRMCF		BIT(1)
 #define STM32_LPTIM_CMPOKCF_ARROKCF	GENMASK(4, 3)
 
+/* STM32_LPTIM_IER - bit flieds */
+#define STM32_LPTIM_ARRMIE	BIT(1)
+
 /* STM32_LPTIM_CR - bit fields */
 #define STM32_LPTIM_CNTSTRT	BIT(2)
+#define STM32_LPTIM_SNGSTRT	BIT(1)
 #define STM32_LPTIM_ENABLE	BIT(0)
 
 /* STM32_LPTIM_CFGR - bit fields */
-- 
2.15.0


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

* [PATCH v7 3/6] mfd: stm32: Add defines to be used for clkevent purpose
@ 2020-04-20 12:16   ` Benjamin Gaignard
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: Benjamin Gaignard, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel

Add defines to be able to enable/clear irq and configure one shot mode.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 include/linux/mfd/stm32-lptimer.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/mfd/stm32-lptimer.h b/include/linux/mfd/stm32-lptimer.h
index 605f62264825..90b20550c1c8 100644
--- a/include/linux/mfd/stm32-lptimer.h
+++ b/include/linux/mfd/stm32-lptimer.h
@@ -27,10 +27,15 @@
 #define STM32_LPTIM_CMPOK		BIT(3)
 
 /* STM32_LPTIM_ICR - bit fields */
+#define STM32_LPTIM_ARRMCF		BIT(1)
 #define STM32_LPTIM_CMPOKCF_ARROKCF	GENMASK(4, 3)
 
+/* STM32_LPTIM_IER - bit flieds */
+#define STM32_LPTIM_ARRMIE	BIT(1)
+
 /* STM32_LPTIM_CR - bit fields */
 #define STM32_LPTIM_CNTSTRT	BIT(2)
+#define STM32_LPTIM_SNGSTRT	BIT(1)
 #define STM32_LPTIM_ENABLE	BIT(0)
 
 /* STM32_LPTIM_CFGR - bit fields */
-- 
2.15.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v7 4/6] mfd: stm32: enable regmap fast_io for stm32-lptimer
  2020-04-20 12:16 ` Benjamin Gaignard
@ 2020-04-20 12:16   ` Benjamin Gaignard
  -1 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	Benjamin Gaignard

Because stm32-lptimer need to write in registers in interrupt context
enable regmap fast_io to use a spin_lock to protect registers access
rather than a mutex.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/stm32-lptimer.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c
index a00f99f36559..746e51a17cc8 100644
--- a/drivers/mfd/stm32-lptimer.c
+++ b/drivers/mfd/stm32-lptimer.c
@@ -17,6 +17,7 @@ static const struct regmap_config stm32_lptimer_regmap_cfg = {
 	.val_bits = 32,
 	.reg_stride = sizeof(u32),
 	.max_register = STM32_LPTIM_MAX_REGISTER,
+	.fast_io = true,
 };
 
 static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata)
-- 
2.15.0


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

* [PATCH v7 4/6] mfd: stm32: enable regmap fast_io for stm32-lptimer
@ 2020-04-20 12:16   ` Benjamin Gaignard
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: Benjamin Gaignard, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel

Because stm32-lptimer need to write in registers in interrupt context
enable regmap fast_io to use a spin_lock to protect registers access
rather than a mutex.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/stm32-lptimer.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c
index a00f99f36559..746e51a17cc8 100644
--- a/drivers/mfd/stm32-lptimer.c
+++ b/drivers/mfd/stm32-lptimer.c
@@ -17,6 +17,7 @@ static const struct regmap_config stm32_lptimer_regmap_cfg = {
 	.val_bits = 32,
 	.reg_stride = sizeof(u32),
 	.max_register = STM32_LPTIM_MAX_REGISTER,
+	.fast_io = true,
 };
 
 static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata)
-- 
2.15.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
  2020-04-20 12:16 ` Benjamin Gaignard
@ 2020-04-20 12:16   ` Benjamin Gaignard
  -1 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	Benjamin Gaignard, Pascal Paillet

From: Benjamin Gaignard <benjamin.gaignard@linaro.org>

Implement clock event driver using low power STM32 timers.
Low power timer counters running even when CPUs are stopped.
It could be used as clock event broadcaster to wake up CPUs but not like
a clocksource because each it rise an interrupt the counter restart from 0.

Low power timers have a 16 bits counter and a prescaler which allow to
divide the clock per power of 2 to up 128 to target a 32KHz rate.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Pascal Paillet <p.paillet@st.com>
---
 drivers/clocksource/Kconfig          |   4 +
 drivers/clocksource/Makefile         |   1 +
 drivers/clocksource/timer-stm32-lp.c | 221 +++++++++++++++++++++++++++++++++++
 3 files changed, 226 insertions(+)
 create mode 100644 drivers/clocksource/timer-stm32-lp.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index f2142e6bbea3..22b8d8f1eb40 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -292,6 +292,10 @@ config CLKSRC_STM32
 	select CLKSRC_MMIO
 	select TIMER_OF
 
+config CLKSRC_STM32_LP
+	bool "Low power clocksource for STM32 SoCs"
+	depends on MFD_STM32_LPTIMER || COMPILE_TEST
+
 config CLKSRC_MPS2
 	bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
 	depends on GENERIC_SCHED_CLOCK
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 641ba5383ab5..69f744135cb5 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_BCM_KONA_TIMER)	+= bcm_kona_timer.o
 obj-$(CONFIG_CADENCE_TTC_TIMER)	+= timer-cadence-ttc.o
 obj-$(CONFIG_CLKSRC_EFM32)	+= timer-efm32.o
 obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
+obj-$(CONFIG_CLKSRC_STM32_LP)	+= timer-stm32-lp.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_LPC32XX)	+= timer-lpc32xx.o
 obj-$(CONFIG_CLKSRC_MPS2)	+= mps2-timer.o
diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c
new file mode 100644
index 000000000000..0f06b8a337aa
--- /dev/null
+++ b/drivers/clocksource/timer-stm32-lp.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ *	    Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stm32-lptimer.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+
+#define CFGR_PSC_OFFSET		9
+#define STM32_LP_RATING		1000
+#define STM32_TARGET_CLKRATE	(32000 * HZ)
+#define STM32_LP_MAX_PSC	7
+
+struct stm32_lp_private {
+	struct regmap *reg;
+	struct clock_event_device clkevt;
+	unsigned long period;
+	struct device *dev;
+};
+
+static struct stm32_lp_private*
+to_priv(struct clock_event_device *clkevt)
+{
+	return container_of(clkevt, struct stm32_lp_private, clkevt);
+}
+
+static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt)
+{
+	struct stm32_lp_private *priv = to_priv(clkevt);
+
+	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
+	regmap_write(priv->reg, STM32_LPTIM_IER, 0);
+	/* clear pending flags */
+	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
+
+	return 0;
+}
+
+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);
+
+	/* disable LPTIMER to be able to write into IER register*/
+	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
+	/* enable ARR interrupt */
+	regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
+	/* enable LPTIMER to be able to write into ARR register */
+	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
+	/* set next event counter */
+	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
+
+	/* start counter */
+	if (is_periodic)
+		regmap_write(priv->reg, STM32_LPTIM_CR,
+			     STM32_LPTIM_CNTSTRT | STM32_LPTIM_ENABLE);
+	else
+		regmap_write(priv->reg, STM32_LPTIM_CR,
+			     STM32_LPTIM_SNGSTRT | STM32_LPTIM_ENABLE);
+
+	return 0;
+}
+
+static int stm32_clkevent_lp_set_next_event(unsigned long evt,
+					    struct clock_event_device *clkevt)
+{
+	return stm32_clkevent_lp_set_timer(evt, clkevt,
+					   clockevent_state_periodic(clkevt));
+}
+
+static int stm32_clkevent_lp_set_periodic(struct clock_event_device *clkevt)
+{
+	struct stm32_lp_private *priv = to_priv(clkevt);
+
+	return stm32_clkevent_lp_set_timer(priv->period, clkevt, true);
+}
+
+static int stm32_clkevent_lp_set_oneshot(struct clock_event_device *clkevt)
+{
+	struct stm32_lp_private *priv = to_priv(clkevt);
+
+	return stm32_clkevent_lp_set_timer(priv->period, clkevt, false);
+}
+
+static irqreturn_t stm32_clkevent_lp_irq_handler(int irq, void *dev_id)
+{
+	struct clock_event_device *clkevt = (struct clock_event_device *)dev_id;
+	struct stm32_lp_private *priv = to_priv(clkevt);
+
+	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
+
+	if (clkevt->event_handler)
+		clkevt->event_handler(clkevt);
+
+	return IRQ_HANDLED;
+}
+
+static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv,
+					    unsigned long *rate)
+{
+	int i;
+
+	for (i = 0; i <= STM32_LP_MAX_PSC; i++) {
+		if (DIV_ROUND_CLOSEST(*rate, 1 << i) < STM32_TARGET_CLKRATE)
+			break;
+	}
+
+	regmap_write(priv->reg, STM32_LPTIM_CFGR, i << CFGR_PSC_OFFSET);
+
+	/* Adjust rate and period given the prescaler value */
+	*rate = DIV_ROUND_CLOSEST(*rate, (1 << i));
+	priv->period = DIV_ROUND_UP(*rate, HZ);
+}
+
+static void stm32_clkevent_lp_init(struct stm32_lp_private *priv,
+				  struct device_node *np, unsigned long rate)
+{
+	priv->clkevt.name = np->full_name;
+	priv->clkevt.cpumask = cpu_possible_mask;
+	priv->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
+				CLOCK_EVT_FEAT_ONESHOT;
+	priv->clkevt.set_state_shutdown = stm32_clkevent_lp_shutdown;
+	priv->clkevt.set_state_periodic = stm32_clkevent_lp_set_periodic;
+	priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot;
+	priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event;
+	priv->clkevt.rating = STM32_LP_RATING;
+
+	clockevents_config_and_register(&priv->clkevt, rate, 0x1,
+					STM32_LPTIM_MAX_ARR);
+}
+
+static int stm32_clkevent_lp_probe(struct platform_device *pdev)
+{
+	struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct stm32_lp_private *priv;
+	unsigned long rate;
+	int ret, irq;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->reg = ddata->regmap;
+	ret = clk_prepare_enable(ddata->clk);
+	if (ret)
+		return -EINVAL;
+
+	rate = clk_get_rate(ddata->clk);
+	if (!rate) {
+		ret = -EINVAL;
+		goto out_clk_disable;
+	}
+
+	irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0);
+	if (irq <= 0) {
+		ret = irq;
+		goto out_clk_disable;
+	}
+
+	if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) {
+		ret = device_init_wakeup(&pdev->dev, true);
+		if (ret)
+			goto out_clk_disable;
+
+		ret = dev_pm_set_wake_irq(&pdev->dev, irq);
+		if (ret)
+			goto out_clk_disable;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, stm32_clkevent_lp_irq_handler,
+			       IRQF_TIMER, pdev->name, &priv->clkevt);
+	if (ret)
+		goto out_clk_disable;
+
+	stm32_clkevent_lp_set_prescaler(priv, &rate);
+
+	stm32_clkevent_lp_init(priv, pdev->dev.parent->of_node, rate);
+
+	priv->dev = &pdev->dev;
+
+	return 0;
+
+out_clk_disable:
+	clk_disable_unprepare(ddata->clk);
+	return ret;
+}
+
+static int stm32_clkevent_lp_remove(struct platform_device *pdev)
+{
+	return -EBUSY; /* cannot unregister clockevent */
+}
+
+static const struct of_device_id stm32_clkevent_lp_of_match[] = {
+	{ .compatible = "st,stm32-lptimer-timer", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match);
+
+static struct platform_driver stm32_clkevent_lp_driver = {
+	.probe	= stm32_clkevent_lp_probe,
+	.remove = stm32_clkevent_lp_remove,
+	.driver	= {
+		.name = "stm32-lptimer-timer",
+		.of_match_table = of_match_ptr(stm32_clkevent_lp_of_match),
+	},
+};
+module_platform_driver(stm32_clkevent_lp_driver);
+
+MODULE_ALIAS("platform:stm32-lptimer-timer");
+MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
+MODULE_LICENSE("GPL v2");
-- 
2.15.0


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

* [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
@ 2020-04-20 12:16   ` Benjamin Gaignard
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: devicetree, linux-kernel, Pascal Paillet, Benjamin Gaignard,
	linux-stm32, linux-arm-kernel

From: Benjamin Gaignard <benjamin.gaignard@linaro.org>

Implement clock event driver using low power STM32 timers.
Low power timer counters running even when CPUs are stopped.
It could be used as clock event broadcaster to wake up CPUs but not like
a clocksource because each it rise an interrupt the counter restart from 0.

Low power timers have a 16 bits counter and a prescaler which allow to
divide the clock per power of 2 to up 128 to target a 32KHz rate.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Pascal Paillet <p.paillet@st.com>
---
 drivers/clocksource/Kconfig          |   4 +
 drivers/clocksource/Makefile         |   1 +
 drivers/clocksource/timer-stm32-lp.c | 221 +++++++++++++++++++++++++++++++++++
 3 files changed, 226 insertions(+)
 create mode 100644 drivers/clocksource/timer-stm32-lp.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index f2142e6bbea3..22b8d8f1eb40 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -292,6 +292,10 @@ config CLKSRC_STM32
 	select CLKSRC_MMIO
 	select TIMER_OF
 
+config CLKSRC_STM32_LP
+	bool "Low power clocksource for STM32 SoCs"
+	depends on MFD_STM32_LPTIMER || COMPILE_TEST
+
 config CLKSRC_MPS2
 	bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
 	depends on GENERIC_SCHED_CLOCK
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 641ba5383ab5..69f744135cb5 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_BCM_KONA_TIMER)	+= bcm_kona_timer.o
 obj-$(CONFIG_CADENCE_TTC_TIMER)	+= timer-cadence-ttc.o
 obj-$(CONFIG_CLKSRC_EFM32)	+= timer-efm32.o
 obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
+obj-$(CONFIG_CLKSRC_STM32_LP)	+= timer-stm32-lp.o
 obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
 obj-$(CONFIG_CLKSRC_LPC32XX)	+= timer-lpc32xx.o
 obj-$(CONFIG_CLKSRC_MPS2)	+= mps2-timer.o
diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c
new file mode 100644
index 000000000000..0f06b8a337aa
--- /dev/null
+++ b/drivers/clocksource/timer-stm32-lp.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ *	    Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stm32-lptimer.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+
+#define CFGR_PSC_OFFSET		9
+#define STM32_LP_RATING		1000
+#define STM32_TARGET_CLKRATE	(32000 * HZ)
+#define STM32_LP_MAX_PSC	7
+
+struct stm32_lp_private {
+	struct regmap *reg;
+	struct clock_event_device clkevt;
+	unsigned long period;
+	struct device *dev;
+};
+
+static struct stm32_lp_private*
+to_priv(struct clock_event_device *clkevt)
+{
+	return container_of(clkevt, struct stm32_lp_private, clkevt);
+}
+
+static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt)
+{
+	struct stm32_lp_private *priv = to_priv(clkevt);
+
+	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
+	regmap_write(priv->reg, STM32_LPTIM_IER, 0);
+	/* clear pending flags */
+	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
+
+	return 0;
+}
+
+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);
+
+	/* disable LPTIMER to be able to write into IER register*/
+	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
+	/* enable ARR interrupt */
+	regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
+	/* enable LPTIMER to be able to write into ARR register */
+	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
+	/* set next event counter */
+	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
+
+	/* start counter */
+	if (is_periodic)
+		regmap_write(priv->reg, STM32_LPTIM_CR,
+			     STM32_LPTIM_CNTSTRT | STM32_LPTIM_ENABLE);
+	else
+		regmap_write(priv->reg, STM32_LPTIM_CR,
+			     STM32_LPTIM_SNGSTRT | STM32_LPTIM_ENABLE);
+
+	return 0;
+}
+
+static int stm32_clkevent_lp_set_next_event(unsigned long evt,
+					    struct clock_event_device *clkevt)
+{
+	return stm32_clkevent_lp_set_timer(evt, clkevt,
+					   clockevent_state_periodic(clkevt));
+}
+
+static int stm32_clkevent_lp_set_periodic(struct clock_event_device *clkevt)
+{
+	struct stm32_lp_private *priv = to_priv(clkevt);
+
+	return stm32_clkevent_lp_set_timer(priv->period, clkevt, true);
+}
+
+static int stm32_clkevent_lp_set_oneshot(struct clock_event_device *clkevt)
+{
+	struct stm32_lp_private *priv = to_priv(clkevt);
+
+	return stm32_clkevent_lp_set_timer(priv->period, clkevt, false);
+}
+
+static irqreturn_t stm32_clkevent_lp_irq_handler(int irq, void *dev_id)
+{
+	struct clock_event_device *clkevt = (struct clock_event_device *)dev_id;
+	struct stm32_lp_private *priv = to_priv(clkevt);
+
+	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
+
+	if (clkevt->event_handler)
+		clkevt->event_handler(clkevt);
+
+	return IRQ_HANDLED;
+}
+
+static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv,
+					    unsigned long *rate)
+{
+	int i;
+
+	for (i = 0; i <= STM32_LP_MAX_PSC; i++) {
+		if (DIV_ROUND_CLOSEST(*rate, 1 << i) < STM32_TARGET_CLKRATE)
+			break;
+	}
+
+	regmap_write(priv->reg, STM32_LPTIM_CFGR, i << CFGR_PSC_OFFSET);
+
+	/* Adjust rate and period given the prescaler value */
+	*rate = DIV_ROUND_CLOSEST(*rate, (1 << i));
+	priv->period = DIV_ROUND_UP(*rate, HZ);
+}
+
+static void stm32_clkevent_lp_init(struct stm32_lp_private *priv,
+				  struct device_node *np, unsigned long rate)
+{
+	priv->clkevt.name = np->full_name;
+	priv->clkevt.cpumask = cpu_possible_mask;
+	priv->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
+				CLOCK_EVT_FEAT_ONESHOT;
+	priv->clkevt.set_state_shutdown = stm32_clkevent_lp_shutdown;
+	priv->clkevt.set_state_periodic = stm32_clkevent_lp_set_periodic;
+	priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot;
+	priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event;
+	priv->clkevt.rating = STM32_LP_RATING;
+
+	clockevents_config_and_register(&priv->clkevt, rate, 0x1,
+					STM32_LPTIM_MAX_ARR);
+}
+
+static int stm32_clkevent_lp_probe(struct platform_device *pdev)
+{
+	struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct stm32_lp_private *priv;
+	unsigned long rate;
+	int ret, irq;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->reg = ddata->regmap;
+	ret = clk_prepare_enable(ddata->clk);
+	if (ret)
+		return -EINVAL;
+
+	rate = clk_get_rate(ddata->clk);
+	if (!rate) {
+		ret = -EINVAL;
+		goto out_clk_disable;
+	}
+
+	irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0);
+	if (irq <= 0) {
+		ret = irq;
+		goto out_clk_disable;
+	}
+
+	if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) {
+		ret = device_init_wakeup(&pdev->dev, true);
+		if (ret)
+			goto out_clk_disable;
+
+		ret = dev_pm_set_wake_irq(&pdev->dev, irq);
+		if (ret)
+			goto out_clk_disable;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, stm32_clkevent_lp_irq_handler,
+			       IRQF_TIMER, pdev->name, &priv->clkevt);
+	if (ret)
+		goto out_clk_disable;
+
+	stm32_clkevent_lp_set_prescaler(priv, &rate);
+
+	stm32_clkevent_lp_init(priv, pdev->dev.parent->of_node, rate);
+
+	priv->dev = &pdev->dev;
+
+	return 0;
+
+out_clk_disable:
+	clk_disable_unprepare(ddata->clk);
+	return ret;
+}
+
+static int stm32_clkevent_lp_remove(struct platform_device *pdev)
+{
+	return -EBUSY; /* cannot unregister clockevent */
+}
+
+static const struct of_device_id stm32_clkevent_lp_of_match[] = {
+	{ .compatible = "st,stm32-lptimer-timer", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match);
+
+static struct platform_driver stm32_clkevent_lp_driver = {
+	.probe	= stm32_clkevent_lp_probe,
+	.remove = stm32_clkevent_lp_remove,
+	.driver	= {
+		.name = "stm32-lptimer-timer",
+		.of_match_table = of_match_ptr(stm32_clkevent_lp_of_match),
+	},
+};
+module_platform_driver(stm32_clkevent_lp_driver);
+
+MODULE_ALIAS("platform:stm32-lptimer-timer");
+MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
+MODULE_LICENSE("GPL v2");
-- 
2.15.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v7 6/6] ARM: mach-stm32: select low power timer for STM32MP157
  2020-04-20 12:16 ` Benjamin Gaignard
@ 2020-04-20 12:16   ` Benjamin Gaignard
  -1 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	Benjamin Gaignard

Make MACH_STM32MP157 select CLKSRC_STM32_LP to get a broadcast timer.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 arch/arm/mach-stm32/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig
index 57699bd8f107..d78f55b7b1d0 100644
--- a/arch/arm/mach-stm32/Kconfig
+++ b/arch/arm/mach-stm32/Kconfig
@@ -46,6 +46,7 @@ if ARCH_MULTI_V7
 config MACH_STM32MP157
 	bool "STMicroelectronics STM32MP157"
 	select ARM_ERRATA_814220
+	select CLKSRC_STM32_LP
 	default y
 
 endif # ARMv7-A
-- 
2.15.0


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

* [PATCH v7 6/6] ARM: mach-stm32: select low power timer for STM32MP157
@ 2020-04-20 12:16   ` Benjamin Gaignard
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin Gaignard @ 2020-04-20 12:16 UTC (permalink / raw)
  To: fabrice.gasnier, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, alexandre.torgue, daniel.lezcano, tglx
  Cc: Benjamin Gaignard, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel

Make MACH_STM32MP157 select CLKSRC_STM32_LP to get a broadcast timer.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 arch/arm/mach-stm32/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig
index 57699bd8f107..d78f55b7b1d0 100644
--- a/arch/arm/mach-stm32/Kconfig
+++ b/arch/arm/mach-stm32/Kconfig
@@ -46,6 +46,7 @@ if ARCH_MULTI_V7
 config MACH_STM32MP157
 	bool "STMicroelectronics STM32MP157"
 	select ARM_ERRATA_814220
+	select CLKSRC_STM32_LP
 	default y
 
 endif # ARMv7-A
-- 
2.15.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v7 1/6] dt-bindings: mfd: Document STM32 low power timer bindings
  2020-04-20 12:16   ` Benjamin Gaignard
@ 2020-04-20 18:04     ` Rob Herring
  -1 siblings, 0 replies; 24+ messages in thread
From: Rob Herring @ 2020-04-20 18:04 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: fabrice.gasnier, lee.jones, mark.rutland, mcoquelin.stm32,
	alexandre.torgue, daniel.lezcano, tglx, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

On Mon, Apr 20, 2020 at 02:16:15PM +0200, Benjamin Gaignard wrote:
> Add a subnode to STM low power timer bindings to support timer driver
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v7 1/6] dt-bindings: mfd: Document STM32 low power timer bindings
@ 2020-04-20 18:04     ` Rob Herring
  0 siblings, 0 replies; 24+ messages in thread
From: Rob Herring @ 2020-04-20 18:04 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: mark.rutland, devicetree, alexandre.torgue, daniel.lezcano,
	linux-kernel, mcoquelin.stm32, tglx, fabrice.gasnier, lee.jones,
	linux-stm32, linux-arm-kernel

On Mon, Apr 20, 2020 at 02:16:15PM +0200, Benjamin Gaignard wrote:
> Add a subnode to STM low power timer bindings to support timer driver
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml | 5 +++++
>  1 file changed, 5 insertions(+)

Reviewed-by: Rob Herring <robh@kernel.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [Linux-stm32] [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
  2020-04-20 12:16   ` Benjamin Gaignard
@ 2020-05-05  7:26     ` Benjamin GAIGNARD
  -1 siblings, 0 replies; 24+ messages in thread
From: Benjamin GAIGNARD @ 2020-05-05  7:26 UTC (permalink / raw)
  To: Fabrice GASNIER, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, Alexandre TORGUE, daniel.lezcano, tglx
  Cc: devicetree, linux-kernel, Pascal PAILLET-LME, Benjamin Gaignard,
	linux-stm32, linux-arm-kernel



On 4/20/20 2:16 PM, Benjamin Gaignard wrote:
> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>
> Implement clock event driver using low power STM32 timers.
> Low power timer counters running even when CPUs are stopped.
> It could be used as clock event broadcaster to wake up CPUs but not like
> a clocksource because each it rise an interrupt the counter restart from 0.
>
> Low power timers have a 16 bits counter and a prescaler which allow to
> divide the clock per power of 2 to up 128 to target a 32KHz rate.
Gentle ping to reviewers on this driver part of the series.
The bindings and the MFD have been reviewed so I hope I can progress
on the driver part too.

Thanks.
Benjamin
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> Signed-off-by: Pascal Paillet <p.paillet@st.com>
> ---
>   drivers/clocksource/Kconfig          |   4 +
>   drivers/clocksource/Makefile         |   1 +
>   drivers/clocksource/timer-stm32-lp.c | 221 +++++++++++++++++++++++++++++++++++
>   3 files changed, 226 insertions(+)
>   create mode 100644 drivers/clocksource/timer-stm32-lp.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index f2142e6bbea3..22b8d8f1eb40 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -292,6 +292,10 @@ config CLKSRC_STM32
>   	select CLKSRC_MMIO
>   	select TIMER_OF
>   
> +config CLKSRC_STM32_LP
> +	bool "Low power clocksource for STM32 SoCs"
> +	depends on MFD_STM32_LPTIMER || COMPILE_TEST
> +
>   config CLKSRC_MPS2
>   	bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
>   	depends on GENERIC_SCHED_CLOCK
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 641ba5383ab5..69f744135cb5 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -44,6 +44,7 @@ obj-$(CONFIG_BCM_KONA_TIMER)	+= bcm_kona_timer.o
>   obj-$(CONFIG_CADENCE_TTC_TIMER)	+= timer-cadence-ttc.o
>   obj-$(CONFIG_CLKSRC_EFM32)	+= timer-efm32.o
>   obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
> +obj-$(CONFIG_CLKSRC_STM32_LP)	+= timer-stm32-lp.o
>   obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
>   obj-$(CONFIG_CLKSRC_LPC32XX)	+= timer-lpc32xx.o
>   obj-$(CONFIG_CLKSRC_MPS2)	+= mps2-timer.o
> diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c
> new file mode 100644
> index 000000000000..0f06b8a337aa
> --- /dev/null
> +++ b/drivers/clocksource/timer-stm32-lp.c
> @@ -0,0 +1,221 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
> + * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> + *	    Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/stm32-lptimer.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeirq.h>
> +
> +#define CFGR_PSC_OFFSET		9
> +#define STM32_LP_RATING		1000
> +#define STM32_TARGET_CLKRATE	(32000 * HZ)
> +#define STM32_LP_MAX_PSC	7
> +
> +struct stm32_lp_private {
> +	struct regmap *reg;
> +	struct clock_event_device clkevt;
> +	unsigned long period;
> +	struct device *dev;
> +};
> +
> +static struct stm32_lp_private*
> +to_priv(struct clock_event_device *clkevt)
> +{
> +	return container_of(clkevt, struct stm32_lp_private, clkevt);
> +}
> +
> +static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt)
> +{
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +
> +	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
> +	regmap_write(priv->reg, STM32_LPTIM_IER, 0);
> +	/* clear pending flags */
> +	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
> +
> +	return 0;
> +}
> +
> +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);
> +
> +	/* disable LPTIMER to be able to write into IER register*/
> +	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
> +	/* enable ARR interrupt */
> +	regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
> +	/* enable LPTIMER to be able to write into ARR register */
> +	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
> +	/* set next event counter */
> +	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
> +
> +	/* start counter */
> +	if (is_periodic)
> +		regmap_write(priv->reg, STM32_LPTIM_CR,
> +			     STM32_LPTIM_CNTSTRT | STM32_LPTIM_ENABLE);
> +	else
> +		regmap_write(priv->reg, STM32_LPTIM_CR,
> +			     STM32_LPTIM_SNGSTRT | STM32_LPTIM_ENABLE);
> +
> +	return 0;
> +}
> +
> +static int stm32_clkevent_lp_set_next_event(unsigned long evt,
> +					    struct clock_event_device *clkevt)
> +{
> +	return stm32_clkevent_lp_set_timer(evt, clkevt,
> +					   clockevent_state_periodic(clkevt));
> +}
> +
> +static int stm32_clkevent_lp_set_periodic(struct clock_event_device *clkevt)
> +{
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +
> +	return stm32_clkevent_lp_set_timer(priv->period, clkevt, true);
> +}
> +
> +static int stm32_clkevent_lp_set_oneshot(struct clock_event_device *clkevt)
> +{
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +
> +	return stm32_clkevent_lp_set_timer(priv->period, clkevt, false);
> +}
> +
> +static irqreturn_t stm32_clkevent_lp_irq_handler(int irq, void *dev_id)
> +{
> +	struct clock_event_device *clkevt = (struct clock_event_device *)dev_id;
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +
> +	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
> +
> +	if (clkevt->event_handler)
> +		clkevt->event_handler(clkevt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv,
> +					    unsigned long *rate)
> +{
> +	int i;
> +
> +	for (i = 0; i <= STM32_LP_MAX_PSC; i++) {
> +		if (DIV_ROUND_CLOSEST(*rate, 1 << i) < STM32_TARGET_CLKRATE)
> +			break;
> +	}
> +
> +	regmap_write(priv->reg, STM32_LPTIM_CFGR, i << CFGR_PSC_OFFSET);
> +
> +	/* Adjust rate and period given the prescaler value */
> +	*rate = DIV_ROUND_CLOSEST(*rate, (1 << i));
> +	priv->period = DIV_ROUND_UP(*rate, HZ);
> +}
> +
> +static void stm32_clkevent_lp_init(struct stm32_lp_private *priv,
> +				  struct device_node *np, unsigned long rate)
> +{
> +	priv->clkevt.name = np->full_name;
> +	priv->clkevt.cpumask = cpu_possible_mask;
> +	priv->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
> +				CLOCK_EVT_FEAT_ONESHOT;
> +	priv->clkevt.set_state_shutdown = stm32_clkevent_lp_shutdown;
> +	priv->clkevt.set_state_periodic = stm32_clkevent_lp_set_periodic;
> +	priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot;
> +	priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event;
> +	priv->clkevt.rating = STM32_LP_RATING;
> +
> +	clockevents_config_and_register(&priv->clkevt, rate, 0x1,
> +					STM32_LPTIM_MAX_ARR);
> +}
> +
> +static int stm32_clkevent_lp_probe(struct platform_device *pdev)
> +{
> +	struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
> +	struct stm32_lp_private *priv;
> +	unsigned long rate;
> +	int ret, irq;
> +
> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->reg = ddata->regmap;
> +	ret = clk_prepare_enable(ddata->clk);
> +	if (ret)
> +		return -EINVAL;
> +
> +	rate = clk_get_rate(ddata->clk);
> +	if (!rate) {
> +		ret = -EINVAL;
> +		goto out_clk_disable;
> +	}
> +
> +	irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0);
> +	if (irq <= 0) {
> +		ret = irq;
> +		goto out_clk_disable;
> +	}
> +
> +	if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) {
> +		ret = device_init_wakeup(&pdev->dev, true);
> +		if (ret)
> +			goto out_clk_disable;
> +
> +		ret = dev_pm_set_wake_irq(&pdev->dev, irq);
> +		if (ret)
> +			goto out_clk_disable;
> +	}
> +
> +	ret = devm_request_irq(&pdev->dev, irq, stm32_clkevent_lp_irq_handler,
> +			       IRQF_TIMER, pdev->name, &priv->clkevt);
> +	if (ret)
> +		goto out_clk_disable;
> +
> +	stm32_clkevent_lp_set_prescaler(priv, &rate);
> +
> +	stm32_clkevent_lp_init(priv, pdev->dev.parent->of_node, rate);
> +
> +	priv->dev = &pdev->dev;
> +
> +	return 0;
> +
> +out_clk_disable:
> +	clk_disable_unprepare(ddata->clk);
> +	return ret;
> +}
> +
> +static int stm32_clkevent_lp_remove(struct platform_device *pdev)
> +{
> +	return -EBUSY; /* cannot unregister clockevent */
> +}
> +
> +static const struct of_device_id stm32_clkevent_lp_of_match[] = {
> +	{ .compatible = "st,stm32-lptimer-timer", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match);
> +
> +static struct platform_driver stm32_clkevent_lp_driver = {
> +	.probe	= stm32_clkevent_lp_probe,
> +	.remove = stm32_clkevent_lp_remove,
> +	.driver	= {
> +		.name = "stm32-lptimer-timer",
> +		.of_match_table = of_match_ptr(stm32_clkevent_lp_of_match),
> +	},
> +};
> +module_platform_driver(stm32_clkevent_lp_driver);
> +
> +MODULE_ALIAS("platform:stm32-lptimer-timer");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
> +MODULE_LICENSE("GPL v2");

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

* Re: [Linux-stm32] [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
@ 2020-05-05  7:26     ` Benjamin GAIGNARD
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin GAIGNARD @ 2020-05-05  7:26 UTC (permalink / raw)
  To: Fabrice GASNIER, lee.jones, robh+dt, mark.rutland,
	mcoquelin.stm32, Alexandre TORGUE, daniel.lezcano, tglx
  Cc: devicetree, linux-kernel, Pascal PAILLET-LME, Benjamin Gaignard,
	linux-stm32, linux-arm-kernel



On 4/20/20 2:16 PM, Benjamin Gaignard wrote:
> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>
> Implement clock event driver using low power STM32 timers.
> Low power timer counters running even when CPUs are stopped.
> It could be used as clock event broadcaster to wake up CPUs but not like
> a clocksource because each it rise an interrupt the counter restart from 0.
>
> Low power timers have a 16 bits counter and a prescaler which allow to
> divide the clock per power of 2 to up 128 to target a 32KHz rate.
Gentle ping to reviewers on this driver part of the series.
The bindings and the MFD have been reviewed so I hope I can progress
on the driver part too.

Thanks.
Benjamin
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> Signed-off-by: Pascal Paillet <p.paillet@st.com>
> ---
>   drivers/clocksource/Kconfig          |   4 +
>   drivers/clocksource/Makefile         |   1 +
>   drivers/clocksource/timer-stm32-lp.c | 221 +++++++++++++++++++++++++++++++++++
>   3 files changed, 226 insertions(+)
>   create mode 100644 drivers/clocksource/timer-stm32-lp.c
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index f2142e6bbea3..22b8d8f1eb40 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -292,6 +292,10 @@ config CLKSRC_STM32
>   	select CLKSRC_MMIO
>   	select TIMER_OF
>   
> +config CLKSRC_STM32_LP
> +	bool "Low power clocksource for STM32 SoCs"
> +	depends on MFD_STM32_LPTIMER || COMPILE_TEST
> +
>   config CLKSRC_MPS2
>   	bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
>   	depends on GENERIC_SCHED_CLOCK
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 641ba5383ab5..69f744135cb5 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -44,6 +44,7 @@ obj-$(CONFIG_BCM_KONA_TIMER)	+= bcm_kona_timer.o
>   obj-$(CONFIG_CADENCE_TTC_TIMER)	+= timer-cadence-ttc.o
>   obj-$(CONFIG_CLKSRC_EFM32)	+= timer-efm32.o
>   obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
> +obj-$(CONFIG_CLKSRC_STM32_LP)	+= timer-stm32-lp.o
>   obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
>   obj-$(CONFIG_CLKSRC_LPC32XX)	+= timer-lpc32xx.o
>   obj-$(CONFIG_CLKSRC_MPS2)	+= mps2-timer.o
> diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c
> new file mode 100644
> index 000000000000..0f06b8a337aa
> --- /dev/null
> +++ b/drivers/clocksource/timer-stm32-lp.c
> @@ -0,0 +1,221 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
> + * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> + *	    Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/stm32-lptimer.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeirq.h>
> +
> +#define CFGR_PSC_OFFSET		9
> +#define STM32_LP_RATING		1000
> +#define STM32_TARGET_CLKRATE	(32000 * HZ)
> +#define STM32_LP_MAX_PSC	7
> +
> +struct stm32_lp_private {
> +	struct regmap *reg;
> +	struct clock_event_device clkevt;
> +	unsigned long period;
> +	struct device *dev;
> +};
> +
> +static struct stm32_lp_private*
> +to_priv(struct clock_event_device *clkevt)
> +{
> +	return container_of(clkevt, struct stm32_lp_private, clkevt);
> +}
> +
> +static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt)
> +{
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +
> +	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
> +	regmap_write(priv->reg, STM32_LPTIM_IER, 0);
> +	/* clear pending flags */
> +	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
> +
> +	return 0;
> +}
> +
> +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);
> +
> +	/* disable LPTIMER to be able to write into IER register*/
> +	regmap_write(priv->reg, STM32_LPTIM_CR, 0);
> +	/* enable ARR interrupt */
> +	regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
> +	/* enable LPTIMER to be able to write into ARR register */
> +	regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
> +	/* set next event counter */
> +	regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
> +
> +	/* start counter */
> +	if (is_periodic)
> +		regmap_write(priv->reg, STM32_LPTIM_CR,
> +			     STM32_LPTIM_CNTSTRT | STM32_LPTIM_ENABLE);
> +	else
> +		regmap_write(priv->reg, STM32_LPTIM_CR,
> +			     STM32_LPTIM_SNGSTRT | STM32_LPTIM_ENABLE);
> +
> +	return 0;
> +}
> +
> +static int stm32_clkevent_lp_set_next_event(unsigned long evt,
> +					    struct clock_event_device *clkevt)
> +{
> +	return stm32_clkevent_lp_set_timer(evt, clkevt,
> +					   clockevent_state_periodic(clkevt));
> +}
> +
> +static int stm32_clkevent_lp_set_periodic(struct clock_event_device *clkevt)
> +{
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +
> +	return stm32_clkevent_lp_set_timer(priv->period, clkevt, true);
> +}
> +
> +static int stm32_clkevent_lp_set_oneshot(struct clock_event_device *clkevt)
> +{
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +
> +	return stm32_clkevent_lp_set_timer(priv->period, clkevt, false);
> +}
> +
> +static irqreturn_t stm32_clkevent_lp_irq_handler(int irq, void *dev_id)
> +{
> +	struct clock_event_device *clkevt = (struct clock_event_device *)dev_id;
> +	struct stm32_lp_private *priv = to_priv(clkevt);
> +
> +	regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
> +
> +	if (clkevt->event_handler)
> +		clkevt->event_handler(clkevt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv,
> +					    unsigned long *rate)
> +{
> +	int i;
> +
> +	for (i = 0; i <= STM32_LP_MAX_PSC; i++) {
> +		if (DIV_ROUND_CLOSEST(*rate, 1 << i) < STM32_TARGET_CLKRATE)
> +			break;
> +	}
> +
> +	regmap_write(priv->reg, STM32_LPTIM_CFGR, i << CFGR_PSC_OFFSET);
> +
> +	/* Adjust rate and period given the prescaler value */
> +	*rate = DIV_ROUND_CLOSEST(*rate, (1 << i));
> +	priv->period = DIV_ROUND_UP(*rate, HZ);
> +}
> +
> +static void stm32_clkevent_lp_init(struct stm32_lp_private *priv,
> +				  struct device_node *np, unsigned long rate)
> +{
> +	priv->clkevt.name = np->full_name;
> +	priv->clkevt.cpumask = cpu_possible_mask;
> +	priv->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
> +				CLOCK_EVT_FEAT_ONESHOT;
> +	priv->clkevt.set_state_shutdown = stm32_clkevent_lp_shutdown;
> +	priv->clkevt.set_state_periodic = stm32_clkevent_lp_set_periodic;
> +	priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot;
> +	priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event;
> +	priv->clkevt.rating = STM32_LP_RATING;
> +
> +	clockevents_config_and_register(&priv->clkevt, rate, 0x1,
> +					STM32_LPTIM_MAX_ARR);
> +}
> +
> +static int stm32_clkevent_lp_probe(struct platform_device *pdev)
> +{
> +	struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
> +	struct stm32_lp_private *priv;
> +	unsigned long rate;
> +	int ret, irq;
> +
> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->reg = ddata->regmap;
> +	ret = clk_prepare_enable(ddata->clk);
> +	if (ret)
> +		return -EINVAL;
> +
> +	rate = clk_get_rate(ddata->clk);
> +	if (!rate) {
> +		ret = -EINVAL;
> +		goto out_clk_disable;
> +	}
> +
> +	irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0);
> +	if (irq <= 0) {
> +		ret = irq;
> +		goto out_clk_disable;
> +	}
> +
> +	if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) {
> +		ret = device_init_wakeup(&pdev->dev, true);
> +		if (ret)
> +			goto out_clk_disable;
> +
> +		ret = dev_pm_set_wake_irq(&pdev->dev, irq);
> +		if (ret)
> +			goto out_clk_disable;
> +	}
> +
> +	ret = devm_request_irq(&pdev->dev, irq, stm32_clkevent_lp_irq_handler,
> +			       IRQF_TIMER, pdev->name, &priv->clkevt);
> +	if (ret)
> +		goto out_clk_disable;
> +
> +	stm32_clkevent_lp_set_prescaler(priv, &rate);
> +
> +	stm32_clkevent_lp_init(priv, pdev->dev.parent->of_node, rate);
> +
> +	priv->dev = &pdev->dev;
> +
> +	return 0;
> +
> +out_clk_disable:
> +	clk_disable_unprepare(ddata->clk);
> +	return ret;
> +}
> +
> +static int stm32_clkevent_lp_remove(struct platform_device *pdev)
> +{
> +	return -EBUSY; /* cannot unregister clockevent */
> +}
> +
> +static const struct of_device_id stm32_clkevent_lp_of_match[] = {
> +	{ .compatible = "st,stm32-lptimer-timer", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match);
> +
> +static struct platform_driver stm32_clkevent_lp_driver = {
> +	.probe	= stm32_clkevent_lp_probe,
> +	.remove = stm32_clkevent_lp_remove,
> +	.driver	= {
> +		.name = "stm32-lptimer-timer",
> +		.of_match_table = of_match_ptr(stm32_clkevent_lp_of_match),
> +	},
> +};
> +module_platform_driver(stm32_clkevent_lp_driver);
> +
> +MODULE_ALIAS("platform:stm32-lptimer-timer");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
> +MODULE_LICENSE("GPL v2");
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [Linux-stm32] [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
  2020-05-05  7:26     ` Benjamin GAIGNARD
@ 2020-05-15 15:25       ` Daniel Lezcano
  -1 siblings, 0 replies; 24+ messages in thread
From: Daniel Lezcano @ 2020-05-15 15:25 UTC (permalink / raw)
  To: Benjamin GAIGNARD, Fabrice GASNIER, lee.jones, robh+dt,
	mark.rutland, mcoquelin.stm32, Alexandre TORGUE, tglx
  Cc: devicetree, linux-kernel, Pascal PAILLET-LME, Benjamin Gaignard,
	linux-stm32, linux-arm-kernel

Hi Benjamin,

On 05/05/2020 09:26, Benjamin GAIGNARD wrote:
> 
> 
> On 4/20/20 2:16 PM, Benjamin Gaignard wrote:
>> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>>
>> Implement clock event driver using low power STM32 timers.
>> Low power timer counters running even when CPUs are stopped.
>> It could be used as clock event broadcaster to wake up CPUs but not like
>> a clocksource because each it rise an interrupt the counter restart from 0.
>>
>> Low power timers have a 16 bits counter and a prescaler which allow to
>> divide the clock per power of 2 to up 128 to target a 32KHz rate.
> Gentle ping to reviewers on this driver part of the series.
> The bindings and the MFD have been reviewed so I hope I can progress
> on the driver part too.

[ ... ]

sorry for the delay.

How do you want these patches to be merged?

Shall I pick patch 6/7 ?



-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [Linux-stm32] [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
@ 2020-05-15 15:25       ` Daniel Lezcano
  0 siblings, 0 replies; 24+ messages in thread
From: Daniel Lezcano @ 2020-05-15 15:25 UTC (permalink / raw)
  To: Benjamin GAIGNARD, Fabrice GASNIER, lee.jones, robh+dt,
	mark.rutland, mcoquelin.stm32, Alexandre TORGUE, tglx
  Cc: devicetree, linux-kernel, Pascal PAILLET-LME, Benjamin Gaignard,
	linux-stm32, linux-arm-kernel

Hi Benjamin,

On 05/05/2020 09:26, Benjamin GAIGNARD wrote:
> 
> 
> On 4/20/20 2:16 PM, Benjamin Gaignard wrote:
>> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>>
>> Implement clock event driver using low power STM32 timers.
>> Low power timer counters running even when CPUs are stopped.
>> It could be used as clock event broadcaster to wake up CPUs but not like
>> a clocksource because each it rise an interrupt the counter restart from 0.
>>
>> Low power timers have a 16 bits counter and a prescaler which allow to
>> divide the clock per power of 2 to up 128 to target a 32KHz rate.
> Gentle ping to reviewers on this driver part of the series.
> The bindings and the MFD have been reviewed so I hope I can progress
> on the driver part too.

[ ... ]

sorry for the delay.

How do you want these patches to be merged?

Shall I pick patch 6/7 ?



-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [Linux-stm32] [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
  2020-05-15 15:25       ` Daniel Lezcano
@ 2020-05-16 18:51         ` Benjamin GAIGNARD
  -1 siblings, 0 replies; 24+ messages in thread
From: Benjamin GAIGNARD @ 2020-05-16 18:51 UTC (permalink / raw)
  To: Daniel Lezcano, Fabrice GASNIER, lee.jones, robh+dt,
	mark.rutland, mcoquelin.stm32, Alexandre TORGUE, tglx
  Cc: devicetree, linux-kernel, Pascal PAILLET-LME, Benjamin Gaignard,
	linux-stm32, linux-arm-kernel



On 5/15/20 5:25 PM, Daniel Lezcano wrote:
> Hi Benjamin,
>
> On 05/05/2020 09:26, Benjamin GAIGNARD wrote:
>>
>> On 4/20/20 2:16 PM, Benjamin Gaignard wrote:
>>> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>>>
>>> Implement clock event driver using low power STM32 timers.
>>> Low power timer counters running even when CPUs are stopped.
>>> It could be used as clock event broadcaster to wake up CPUs but not like
>>> a clocksource because each it rise an interrupt the counter restart from 0.
>>>
>>> Low power timers have a 16 bits counter and a prescaler which allow to
>>> divide the clock per power of 2 to up 128 to target a 32KHz rate.
>> Gentle ping to reviewers on this driver part of the series.
>> The bindings and the MFD have been reviewed so I hope I can progress
>> on the driver part too.
> [ ... ]
>
> sorry for the delay.
>
> How do you want these patches to be merged?
>
> Shall I pick patch 6/7 ?
If Lee agrees I think the best is to get all the patches in mfd tree because
of the dependencies between them.

Benjamin
>
>

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

* Re: [Linux-stm32] [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
@ 2020-05-16 18:51         ` Benjamin GAIGNARD
  0 siblings, 0 replies; 24+ messages in thread
From: Benjamin GAIGNARD @ 2020-05-16 18:51 UTC (permalink / raw)
  To: Daniel Lezcano, Fabrice GASNIER, lee.jones, robh+dt,
	mark.rutland, mcoquelin.stm32, Alexandre TORGUE, tglx
  Cc: devicetree, linux-kernel, Pascal PAILLET-LME, Benjamin Gaignard,
	linux-stm32, linux-arm-kernel



On 5/15/20 5:25 PM, Daniel Lezcano wrote:
> Hi Benjamin,
>
> On 05/05/2020 09:26, Benjamin GAIGNARD wrote:
>>
>> On 4/20/20 2:16 PM, Benjamin Gaignard wrote:
>>> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>>>
>>> Implement clock event driver using low power STM32 timers.
>>> Low power timer counters running even when CPUs are stopped.
>>> It could be used as clock event broadcaster to wake up CPUs but not like
>>> a clocksource because each it rise an interrupt the counter restart from 0.
>>>
>>> Low power timers have a 16 bits counter and a prescaler which allow to
>>> divide the clock per power of 2 to up 128 to target a 32KHz rate.
>> Gentle ping to reviewers on this driver part of the series.
>> The bindings and the MFD have been reviewed so I hope I can progress
>> on the driver part too.
> [ ... ]
>
> sorry for the delay.
>
> How do you want these patches to be merged?
>
> Shall I pick patch 6/7 ?
If Lee agrees I think the best is to get all the patches in mfd tree because
of the dependencies between them.

Benjamin
>
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
  2020-04-20 12:16   ` Benjamin Gaignard
@ 2020-05-18 20:18     ` Daniel Lezcano
  -1 siblings, 0 replies; 24+ messages in thread
From: Daniel Lezcano @ 2020-05-18 20:18 UTC (permalink / raw)
  To: Benjamin Gaignard, fabrice.gasnier, lee.jones, robh+dt,
	mark.rutland, mcoquelin.stm32, alexandre.torgue, tglx
  Cc: devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	Benjamin Gaignard, Pascal Paillet

On 20/04/2020 14:16, Benjamin Gaignard wrote:
> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> 
> Implement clock event driver using low power STM32 timers.
> Low power timer counters running even when CPUs are stopped.
> It could be used as clock event broadcaster to wake up CPUs but not like
> a clocksource because each it rise an interrupt the counter restart from 0.
> 
> Low power timers have a 16 bits counter and a prescaler which allow to
> divide the clock per power of 2 to up 128 to target a 32KHz rate.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> Signed-off-by: Pascal Paillet <p.paillet@st.com>

Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>

[ ... ]

-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver
@ 2020-05-18 20:18     ` Daniel Lezcano
  0 siblings, 0 replies; 24+ messages in thread
From: Daniel Lezcano @ 2020-05-18 20:18 UTC (permalink / raw)
  To: Benjamin Gaignard, fabrice.gasnier, lee.jones, robh+dt,
	mark.rutland, mcoquelin.stm32, alexandre.torgue, tglx
  Cc: devicetree, linux-kernel, Pascal Paillet, Benjamin Gaignard,
	linux-stm32, linux-arm-kernel

On 20/04/2020 14:16, Benjamin Gaignard wrote:
> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> 
> Implement clock event driver using low power STM32 timers.
> Low power timer counters running even when CPUs are stopped.
> It could be used as clock event broadcaster to wake up CPUs but not like
> a clocksource because each it rise an interrupt the counter restart from 0.
> 
> Low power timers have a 16 bits counter and a prescaler which allow to
> divide the clock per power of 2 to up 128 to target a 32KHz rate.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> Signed-off-by: Pascal Paillet <p.paillet@st.com>

Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>

[ ... ]

-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2020-05-18 20:18 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-20 12:16 [PATCH v7 0/6] clockevent: add low power STM32 timer Benjamin Gaignard
2020-04-20 12:16 ` Benjamin Gaignard
2020-04-20 12:16 ` [PATCH v7 1/6] dt-bindings: mfd: Document STM32 low power timer bindings Benjamin Gaignard
2020-04-20 12:16   ` Benjamin Gaignard
2020-04-20 18:04   ` Rob Herring
2020-04-20 18:04     ` Rob Herring
2020-04-20 12:16 ` [PATCH v7 2/6] ARM: dts: stm32: Add timer subnodes on stm32mp15 SoCs Benjamin Gaignard
2020-04-20 12:16   ` Benjamin Gaignard
2020-04-20 12:16 ` [PATCH v7 3/6] mfd: stm32: Add defines to be used for clkevent purpose Benjamin Gaignard
2020-04-20 12:16   ` Benjamin Gaignard
2020-04-20 12:16 ` [PATCH v7 4/6] mfd: stm32: enable regmap fast_io for stm32-lptimer Benjamin Gaignard
2020-04-20 12:16   ` Benjamin Gaignard
2020-04-20 12:16 ` [PATCH v7 5/6] clocksource: Add Low Power STM32 timers driver Benjamin Gaignard
2020-04-20 12:16   ` Benjamin Gaignard
2020-05-05  7:26   ` [Linux-stm32] " Benjamin GAIGNARD
2020-05-05  7:26     ` Benjamin GAIGNARD
2020-05-15 15:25     ` Daniel Lezcano
2020-05-15 15:25       ` Daniel Lezcano
2020-05-16 18:51       ` Benjamin GAIGNARD
2020-05-16 18:51         ` Benjamin GAIGNARD
2020-05-18 20:18   ` Daniel Lezcano
2020-05-18 20:18     ` Daniel Lezcano
2020-04-20 12:16 ` [PATCH v7 6/6] ARM: mach-stm32: select low power timer for STM32MP157 Benjamin Gaignard
2020-04-20 12:16   ` Benjamin Gaignard

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.