You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/01/14 14:58:04 UTC

[incubator-nuttx] branch master updated: Add SPWM example to test STM32L4 PWM driver low level operations

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new bf5d48a  Add SPWM example to test STM32L4 PWM driver low level operations
bf5d48a is described below

commit bf5d48acacbf558175e0fc1627306d588fb2c9ef
Author: Daniel P. Carvalho <da...@gmail.com>
AuthorDate: Tue Jan 14 11:53:26 2020 -0300

    Add SPWM example to test STM32L4 PWM driver low level operations
    
    Author: Alan Carvalho de Assis <ac...@gmail.com>
    
        Run nxstyle again .c file and fix error message
    
    Author: Daniel P. Carvalho <da...@gmail.com>
    
        Add SPWM example to test STM32L4 PWM driver low level operations.
    
        Fix BUGs.
---
 arch/arm/src/stm32l4/Kconfig                       | 1467 +++++++-
 arch/arm/src/stm32l4/stm32l4_pwm.c                 | 3790 ++++++++++++++------
 arch/arm/src/stm32l4/stm32l4_pwm.h                 |  371 +-
 boards/arm/stm32l4/nucleo-l432kc/Kconfig           |   34 +
 boards/arm/stm32l4/nucleo-l432kc/README.txt        |   11 +
 .../stm32l4/nucleo-l432kc/configs/spwm/defconfig   | 1360 +++++++
 .../stm32l4/nucleo-l432kc/include/nucleo-l432kc.h  |   15 +-
 boards/arm/stm32l4/nucleo-l432kc/src/Makefile      |    4 +
 boards/arm/stm32l4/nucleo-l432kc/src/stm32_spwm.c  |  664 ++++
 9 files changed, 6510 insertions(+), 1206 deletions(-)

diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig
index 3d37219..d5e5bda 100644
--- a/arch/arm/src/stm32l4/Kconfig
+++ b/arch/arm/src/stm32l4/Kconfig
@@ -1878,6 +1878,12 @@ endchoice
 
 endif # STM32L4_LPTIM2_PWM
 
+config STM32L4_PWM_LL_OPS
+	bool "PWM low-level operations"
+	default n
+	---help---
+		Enable low-level PWM ops.
+
 config STM32L4_TIM1_PWM
 	bool "TIM1 PWM"
 	default n
@@ -1901,6 +1907,27 @@ config STM32L4_TIM1_MODE
 	---help---
 		Specifies the timer mode.
 
+config STM32L4_TIM1_LOCK
+	int "TIM1 Lock Level Configuration"
+	default 0
+	range 0 3
+	---help---
+		Timer 1 lock level configuration
+
+config STM32L4_TIM1_TDTS
+	int "TIM1 t_DTS Division"
+	default 0
+	range 0 2
+	---help---
+		Timer 1 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM1_DEADTIME
+	int "TIM1 Initial Dead-time"
+	default 0
+	range 0 255
+	---help---
+		Timer 1 initial dead-time
+
 if STM32L4_PWM_MULTICHAN
 
 config STM32L4_TIM1_CHANNEL1
@@ -1913,10 +1940,10 @@ if STM32L4_TIM1_CHANNEL1
 
 config STM32L4_TIM1_CH1MODE
 	int "TIM1 Channel 1 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM1_CH1OUT
 	bool "TIM1 Channel 1 Output"
@@ -1943,10 +1970,10 @@ if STM32L4_TIM1_CHANNEL2
 
 config STM32L4_TIM1_CH2MODE
 	int "TIM1 Channel 2 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM1_CH2OUT
 	bool "TIM1 Channel 2 Output"
@@ -1973,10 +2000,10 @@ if STM32L4_TIM1_CHANNEL3
 
 config STM32L4_TIM1_CH3MODE
 	int "TIM1 Channel 3 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM1_CH3OUT
 	bool "TIM1 Channel 3 Output"
@@ -2003,10 +2030,10 @@ if STM32L4_TIM1_CHANNEL4
 
 config STM32L4_TIM1_CH4MODE
 	int "TIM1 Channel 4 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM1_CH4OUT
 	bool "TIM1 Channel 4 Output"
@@ -2028,12 +2055,70 @@ config STM32L4_TIM1_CHANNEL
 		If TIM1 is enabled for PWM usage, you also need specifies the timer output
 		channel {1,..,4}
 
+if STM32L4_TIM1_CHANNEL = 1
+
+config STM32L4_TIM1_CH1OUT
+	bool "TIM1 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+config STM32L4_TIM1_CH1NOUT
+	bool "TIM1 Channel 1 Complementary Output"
+	default n
+	---help---
+		Enables channel 1 Complementary Output.
+
+endif # STM32L4_TIM1_CHANNEL = 1
+
+if STM32L4_TIM1_CHANNEL = 2
+
+config STM32L4_TIM1_CH2OUT
+	bool "TIM1 Channel 2 Output"
+	default n
+	---help---
+		Enables channel 2 output.
+
+config STM32L4_TIM1_CH2NOUT
+	bool "TIM1 Channel 2 Complementary Output"
+	default n
+	---help---
+		Enables channel 2 Complementary Output.
+
+endif # STM32L4_TIM1_CHANNEL = 2
+
+if STM32L4_TIM1_CHANNEL = 3
+
+config STM32L4_TIM1_CH3OUT
+	bool "TIM1 Channel 3 Output"
+	default n
+	---help---
+		Enables channel 3 output.
+
+config STM32L4_TIM1_CH3NOUT
+	bool "TIM1 Channel 3 Complementary Output"
+	default n
+	---help---
+		Enables channel 3 Complementary Output.
+
+endif # STM32L4_TIM1_CHANNEL = 3
+
+if STM32L4_TIM1_CHANNEL = 4
+
+config STM32L4_TIM1_CH4OUT
+	bool "TIM1 Channel 4 Output"
+	default n
+	---help---
+		Enables channel 4 output.
+
+endif # STM32L4_TIM1_CHANNEL = 4
+
 config STM32L4_TIM1_CHMODE
 	int "TIM1 Channel Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -2074,10 +2159,10 @@ if STM32L4_TIM2_CHANNEL1
 
 config STM32L4_TIM2_CH1MODE
 	int "TIM2 Channel 1 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM2_CH1OUT
 	bool "TIM2 Channel 1 Output"
@@ -2097,10 +2182,10 @@ if STM32L4_TIM2_CHANNEL2
 
 config STM32L4_TIM2_CH2MODE
 	int "TIM2 Channel 2 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM2_CH2OUT
 	bool "TIM2 Channel 2 Output"
@@ -2120,10 +2205,10 @@ if STM32L4_TIM2_CHANNEL3
 
 config STM32L4_TIM2_CH3MODE
 	int "TIM2 Channel 3 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM2_CH3OUT
 	bool "TIM2 Channel 3 Output"
@@ -2143,10 +2228,10 @@ if STM32L4_TIM2_CHANNEL4
 
 config STM32L4_TIM2_CH4MODE
 	int "TIM2 Channel 4 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM2_CH4OUT
 	bool "TIM2 Channel 4 Output"
@@ -2168,12 +2253,52 @@ config STM32L4_TIM2_CHANNEL
 		If TIM2 is enabled for PWM usage, you also need specifies the timer output
 		channel {1,..,4}
 
+if STM32L4_TIM2_CHANNEL = 1
+
+config STM32L4_TIM2_CH1OUT
+	bool "TIM2 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+endif # STM32L4_TIM2_CHANNEL = 1
+
+if STM32L4_TIM2_CHANNEL = 2
+
+config STM32L4_TIM2_CH2OUT
+	bool "TIM2 Channel 2 Output"
+	default n
+	---help---
+		Enables channel 2 output.
+
+endif # STM32L4_TIM2_CHANNEL = 2
+
+if STM32L4_TIM2_CHANNEL = 3
+
+config STM32L4_TIM2_CH3OUT
+	bool "TIM2 Channel 3 Output"
+	default n
+	---help---
+		Enables channel 3 output.
+
+endif # STM32L4_TIM2_CHANNEL = 3
+
+if STM32L4_TIM2_CHANNEL = 4
+
+config STM32L4_TIM2_CH4OUT
+	bool "TIM2 Channel 4 Output"
+	default n
+	---help---
+		Enables channel 4 output.
+
+endif # STM32L4_TIM2_CHANNEL = 4
+
 config STM32L4_TIM2_CHMODE
 	int "TIM2 Channel Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -2214,10 +2339,10 @@ if STM32L4_TIM3_CHANNEL1
 
 config STM32L4_TIM3_CH1MODE
 	int "TIM3 Channel 1 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM3_CH1OUT
 	bool "TIM3 Channel 1 Output"
@@ -2237,10 +2362,10 @@ if STM32L4_TIM3_CHANNEL2
 
 config STM32L4_TIM3_CH2MODE
 	int "TIM3 Channel 2 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM3_CH2OUT
 	bool "TIM3 Channel 2 Output"
@@ -2260,10 +2385,10 @@ if STM32L4_TIM3_CHANNEL3
 
 config STM32L4_TIM3_CH3MODE
 	int "TIM3 Channel 3 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM3_CH3OUT
 	bool "TIM3 Channel 3 Output"
@@ -2283,10 +2408,10 @@ if STM32L4_TIM3_CHANNEL4
 
 config STM32L4_TIM3_CH4MODE
 	int "TIM3 Channel 4 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM3_CH4OUT
 	bool "TIM3 Channel 4 Output"
@@ -2308,12 +2433,52 @@ config STM32L4_TIM3_CHANNEL
 		If TIM3 is enabled for PWM usage, you also need specifies the timer output
 		channel {1,..,4}
 
+if STM32L4_TIM3_CHANNEL = 1
+
+config STM32L4_TIM3_CH1OUT
+	bool "TIM3 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+endif # STM32L4_TIM3_CHANNEL = 1
+
+if STM32L4_TIM3_CHANNEL = 2
+
+config STM32L4_TIM3_CH2OUT
+	bool "TIM3 Channel 2 Output"
+	default n
+	---help---
+		Enables channel 2 output.
+
+endif # STM32L4_TIM3_CHANNEL = 2
+
+if STM32L4_TIM3_CHANNEL = 3
+
+config STM32L4_TIM3_CH3OUT
+	bool "TIM3 Channel 3 Output"
+	default n
+	---help---
+		Enables channel 3 output.
+
+endif # STM32L4_TIM3_CHANNEL = 3
+
+if STM32L4_TIM3_CHANNEL = 4
+
+config STM32L4_TIM3_CH4OUT
+	bool "TIM3 Channel 4 Output"
+	default n
+	---help---
+		Enables channel 4 output.
+
+endif # STM32L4_TIM3_CHANNEL = 4
+
 config STM32L4_TIM3_CHMODE
 	int "TIM3 Channel Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -2354,10 +2519,10 @@ if STM32L4_TIM4_CHANNEL1
 
 config STM32L4_TIM4_CH1MODE
 	int "TIM4 Channel 1 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM4_CH1OUT
 	bool "TIM4 Channel 1 Output"
@@ -2377,10 +2542,10 @@ if STM32L4_TIM4_CHANNEL2
 
 config STM32L4_TIM4_CH2MODE
 	int "TIM4 Channel 2 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM4_CH2OUT
 	bool "TIM4 Channel 2 Output"
@@ -2400,10 +2565,10 @@ if STM32L4_TIM4_CHANNEL3
 
 config STM32L4_TIM4_CH3MODE
 	int "TIM4 Channel 3 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM4_CH3OUT
 	bool "TIM4 Channel 3 Output"
@@ -2423,10 +2588,10 @@ if STM32L4_TIM4_CHANNEL4
 
 config STM32L4_TIM4_CH4MODE
 	int "TIM4 Channel 4 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM4_CH4OUT
 	bool "TIM4 Channel 4 Output"
@@ -2448,12 +2613,52 @@ config STM32L4_TIM4_CHANNEL
 		If TIM4 is enabled for PWM usage, you also need specifies the timer output
 		channel {1,..,4}
 
+if STM32L4_TIM4_CHANNEL = 1
+
+config STM32L4_TIM4_CH1OUT
+	bool "TIM4 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+endif # STM32L4_TIM4_CHANNEL = 1
+
+if STM32L4_TIM4_CHANNEL = 2
+
+config STM32L4_TIM4_CH2OUT
+	bool "TIM4 Channel 2 Output"
+	default n
+	---help---
+		Enables channel 2 output.
+
+endif # STM32L4_TIM4_CHANNEL = 2
+
+if STM32L4_TIM4_CHANNEL = 3
+
+config STM32L4_TIM4_CH3OUT
+	bool "TIM4 Channel 3 Output"
+	default n
+	---help---
+		Enables channel 3 output.
+
+endif # STM32L4_TIM4_CHANNEL = 3
+
+if STM32L4_TIM4_CHANNEL = 4
+
+config STM32L4_TIM4_CH4OUT
+	bool "TIM4 Channel 4 Output"
+	default n
+	---help---
+		Enables channel 4 output.
+
+endif # STM32L4_TIM4_CHANNEL = 4
+
 config STM32L4_TIM4_CHMODE
 	int "TIM4 Channel Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -2494,10 +2699,10 @@ if STM32L4_TIM5_CHANNEL1
 
 config STM32L4_TIM5_CH1MODE
 	int "TIM5 Channel 1 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM5_CH1OUT
 	bool "TIM5 Channel 1 Output"
@@ -2517,10 +2722,10 @@ if STM32L4_TIM5_CHANNEL2
 
 config STM32L4_TIM5_CH2MODE
 	int "TIM5 Channel 2 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM5_CH2OUT
 	bool "TIM5 Channel 2 Output"
@@ -2540,10 +2745,10 @@ if STM32L4_TIM5_CHANNEL3
 
 config STM32L4_TIM5_CH3MODE
 	int "TIM5 Channel 3 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM5_CH3OUT
 	bool "TIM5 Channel 3 Output"
@@ -2563,10 +2768,10 @@ if STM32L4_TIM5_CHANNEL4
 
 config STM32L4_TIM5_CH4MODE
 	int "TIM5 Channel 4 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM5_CH4OUT
 	bool "TIM5 Channel 4 Output"
@@ -2588,12 +2793,52 @@ config STM32L4_TIM5_CHANNEL
 		If TIM5 is enabled for PWM usage, you also need specifies the timer output
 		channel {1,..,4}
 
+if STM32L4_TIM5_CHANNEL = 1
+
+config STM32L4_TIM5_CH1OUT
+	bool "TIM5 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+endif # STM32L4_TIM5_CHANNEL = 1
+
+if STM32L4_TIM5_CHANNEL = 2
+
+config STM32L4_TIM5_CH2OUT
+	bool "TIM5 Channel 2 Output"
+	default n
+	---help---
+		Enables channel 2 output.
+
+endif # STM32L4_TIM5_CHANNEL = 2
+
+if STM32L4_TIM5_CHANNEL = 3
+
+config STM32L4_TIM5_CH3OUT
+	bool "TIM5 Channel 3 Output"
+	default n
+	---help---
+		Enables channel 3 output.
+
+endif # STM32L4_TIM5_CHANNEL = 3
+
+if STM32L4_TIM5_CHANNEL = 4
+
+config STM32L4_TIM5_CH4OUT
+	bool "TIM5 Channel 4 Output"
+	default n
+	---help---
+		Enables channel 4 output.
+
+endif # STM32L4_TIM5_CHANNEL = 4
+
 config STM32L4_TIM5_CHMODE
 	int "TIM5 Channel Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -2622,6 +2867,27 @@ config STM32L4_TIM8_MODE
 	---help---
 		Specifies the timer mode.
 
+config STM32L4_TIM8_LOCK
+	int "TIM1 Lock Level Configuration"
+	default 0
+	range 0 3
+	---help---
+		Timer 8 lock level configuration
+
+config STM32L4_TIM8_TDTS
+	int "TIM8 t_DTS Division"
+	default 0
+	range 0 2
+	---help---
+		Timer 8 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM8_DEADTIME
+	int "TIM8 Initial Dead-time"
+	default 0
+	range 0 255
+	---help---
+		Timer 8 initial dead-time
+
 if STM32L4_PWM_MULTICHAN
 
 config STM32L4_TIM8_CHANNEL1
@@ -2634,10 +2900,10 @@ if STM32L4_TIM8_CHANNEL1
 
 config STM32L4_TIM8_CH1MODE
 	int "TIM8 Channel 1 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM8_CH1OUT
 	bool "TIM8 Channel 1 Output"
@@ -2664,10 +2930,10 @@ if STM32L4_TIM8_CHANNEL2
 
 config STM32L4_TIM8_CH2MODE
 	int "TIM8 Channel 2 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM8_CH2OUT
 	bool "TIM8 Channel 2 Output"
@@ -2694,10 +2960,10 @@ if STM32L4_TIM8_CHANNEL3
 
 config STM32L4_TIM8_CH3MODE
 	int "TIM8 Channel 3 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM8_CH3OUT
 	bool "TIM8 Channel 3 Output"
@@ -2724,10 +2990,10 @@ if STM32L4_TIM8_CHANNEL4
 
 config STM32L4_TIM8_CH4MODE
 	int "TIM8 Channel 4 Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM8_CH4OUT
 	bool "TIM8 Channel 4 Output"
@@ -2749,12 +3015,70 @@ config STM32L4_TIM8_CHANNEL
 		If TIM8 is enabled for PWM usage, you also need specifies the timer output
 		channel {1,..,4}
 
-config STM32L4_TIM8_CHMODE
+if STM32L4_TIM8_CHANNEL = 1
+
+config STM32L4_TIM8_CH1OUT
+	bool "TIM8 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+config STM32L4_TIM8_CH1NOUT
+	bool "TIM8 Channel 1 Complementary Output"
+	default n
+	---help---
+		Enables channel 1 Complementary Output.
+
+endif # STM32L4_TIM8_CHANNEL = 1
+
+if STM32L4_TIM8_CHANNEL = 2
+
+config STM32L4_TIM8_CH2OUT
+	bool "TIM8 Channel 2 Output"
+	default n
+	---help---
+		Enables channel 2 output.
+
+config STM32L4_TIM8_CH2NOUT
+	bool "TIM8 Channel 2 Complementary Output"
+	default n
+	---help---
+		Enables channel 2 Complementary Output.
+
+endif # STM32L4_TIM8_CHANNEL = 2
+
+if STM32L4_TIM8_CHANNEL = 3
+
+config STM32L4_TIM8_CH3OUT
+	bool "TIM8 Channel 3 Output"
+	default n
+	---help---
+		Enables channel 3 output.
+
+config STM32L4_TIM8_CH3NOUT
+	bool "TIM8 Channel 3 Complementary Output"
+	default n
+	---help---
+		Enables channel 3 Complementary Output.
+
+endif # STM32L4_TIM8_CHANNEL = 3
+
+if STM32L4_TIM8_CHANNEL = 4
+
+config STM32L4_TIM8_CH4OUT
+	bool "TIM8 Channel 4 Output"
+	default n
+	---help---
+		Enables channel 4 output.
+
+endif # STM32L4_TIM8_CHANNEL = 4
+
+config STM32L4_TIM8_CHMODE
 	int "TIM8 Channel Mode"
-	default 0
-	range 0 5
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -2775,6 +3099,27 @@ config STM32L4_TIM15_PWM
 
 if STM32L4_TIM15_PWM
 
+config STM32L4_TIM15_LOCK
+	int "TIM15 Lock Level Configuration"
+	default 0
+	range 0 3
+	---help---
+		Timer 15 lock level configuration
+
+config STM32L4_TIM15_TDTS
+	int "TIM15 t_DTS Division"
+	default 0
+	range 0 2
+	---help---
+		Timer 15 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM15_DEADTIME
+	int "TIM15 Initial Dead-time"
+	default 0
+	range 0 255
+	---help---
+		Timer 15 initial dead-time
+
 if STM32L4_PWM_MULTICHAN
 
 config STM32L4_TIM15_CHANNEL1
@@ -2787,10 +3132,10 @@ if STM32L4_TIM15_CHANNEL1
 
 config STM32L4_TIM15_CH1MODE
 	int "TIM15 Channel 1 Mode"
-	default 0
-	range 0 3
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM15_CH1OUT
 	bool "TIM15 Channel 1 Output"
@@ -2817,10 +3162,10 @@ if STM32L4_TIM15_CHANNEL2
 
 config STM32L4_TIM15_CH2MODE
 	int "TIM15 Channel 2 Mode"
-	default 0
-	range 0 3
+	default 6
+	range 0 11
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM15_CH2OUT
 	bool "TIM15 Channel 2 Output"
@@ -2842,12 +3187,44 @@ config STM32L4_TIM15_CHANNEL
 		If TIM15 is enabled for PWM usage, you also need specifies the timer output
 		channel {1,2}
 
+if STM32L4_TIM15_CHANNEL = 1
+
+config STM32L4_TIM15_CH1OUT
+	bool "TIM15 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+config STM32L4_TIM15_CH1NOUT
+	bool "TIM15 Channel 1 Complementary Output"
+	default n
+	---help---
+		Enables channel 1 Complementary Output.
+
+endif # STM32L4_TIM15_CHANNEL = 1
+
+if STM32L4_TIM15_CHANNEL = 2
+
+config STM32L4_TIM15_CH2OUT
+	bool "TIM15 Channel 2 Output"
+	default n
+	---help---
+		Enables channel 2 output.
+
+config STM32L4_TIM15_CH2NOUT
+	bool "TIM15 Channel 2 Complementary Output"
+	default n
+	---help---
+		Enables channel 2 Complementary Output.
+
+endif # STM32L4_TIM15_CHANNEL = 2
+
 config STM32L4_TIM15_CHMODE
 	int "TIM15 Channel Mode"
-	default 0
-	range 0 3
+	default 6
+	range 0 9
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -2868,6 +3245,27 @@ config STM32L4_TIM16_PWM
 
 if STM32L4_TIM16_PWM
 
+config STM32L4_TIM16_LOCK
+	int "TIM16 Lock Level Configuration"
+	default 0
+	range 0 3
+	---help---
+		Timer 16 lock level configuration
+
+config STM32L4_TIM16_TDTS
+	int "TIM16 t_DTS Division"
+	default 0
+	range 0 2
+	---help---
+		Timer 16 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM16_DEADTIME
+	int "TIM16 Initial Dead-time"
+	default 0
+	range 0 255
+	---help---
+		Timer 16 initial dead-time
+
 if STM32L4_PWM_MULTICHAN
 
 config STM32L4_TIM16_CHANNEL1
@@ -2880,10 +3278,10 @@ if STM32L4_TIM16_CHANNEL1
 
 config STM32L4_TIM16_CH1MODE
 	int "TIM16 Channel 1 Mode"
-	default 0
-	range 0 1
+	default 6
+	range 0 7
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM16_CH1OUT
 	bool "TIM16 Channel 1 Output"
@@ -2912,12 +3310,22 @@ config STM32L4_TIM16_CHANNEL
 		If TIM16 is enabled for PWM usage, you also need specifies the timer output
 		channel {1}
 
+if STM32L4_TIM16_CHANNEL = 1
+
+config STM32L4_TIM16_CH1OUT
+	bool "TIM16 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+endif # STM32L4_TIM16_CHANNEL = 1
+
 config STM32L4_TIM16_CHMODE
 	int "TIM16 Channel Mode"
-	default 0
-	range 0 1
+	default 6
+	range 0 7
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -2938,6 +3346,27 @@ config STM32L4_TIM17_PWM
 
 if STM32L4_TIM17_PWM
 
+config STM32L4_TIM17_LOCK
+	int "TIM17 Lock Level Configuration"
+	default 0
+	range 0 3
+	---help---
+		Timer 17 lock level configuration
+
+config STM32L4_TIM17_TDTS
+	int "TIM17 t_DTS Division"
+	default 0
+	range 0 2
+	---help---
+		Timer 17 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM17_DEADTIME
+	int "TIM17 Initial Dead-time"
+	default 0
+	range 0 255
+	---help---
+		Timer 17 initial dead-time
+
 if STM32L4_PWM_MULTICHAN
 
 config STM32L4_TIM17_CHANNEL1
@@ -2950,10 +3379,10 @@ if STM32L4_TIM17_CHANNEL1
 
 config STM32L4_TIM17_CH1MODE
 	int "TIM17 Channel 1 Mode"
-	default 0
-	range 0 1
+	default 6
+	range 0 7
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 config STM32L4_TIM17_CH1OUT
 	bool "TIM17 Channel 1 Output"
@@ -2982,12 +3411,22 @@ config STM32L4_TIM17_CHANNEL
 		If TIM17 is enabled for PWM usage, you also need specifies the timer output
 		channel {1}
 
+if STM32_TIM17_CHANNEL = 1
+
+config STM32L4_TIM17_CH1OUT
+	bool "TIM17 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+endif # STM32L4_TIM17_CHANNEL = 1
+
 config STM32L4_TIM17_CHMODE
 	int "TIM17 Channel Mode"
-	default 0
-	range 0 1
+	default 6
+	range 0 7
 	---help---
-		Specifies the channel mode.
+		Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
 
 endif # !STM32L4_PWM_MULTICHAN
 
@@ -3032,6 +3471,22 @@ config STM32L4_LPTIM1_CHANNEL
 		If LPTIM1 is enabled for PWM usage, you also need specifies the timer output
 		channel {1}
 
+if STM32L4_LPTIM1_CHANNEL = 1
+
+config STM32L4_LPTIM1_CH1OUT
+	bool "LPTIM1 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+config STM32L4_LPTIM1_CH1NOUT
+	bool "LPTIM1 Channel 1 Complementary Output"
+	default n
+	---help---
+		Enables channel 1 Complementary Output.
+
+endif # STM32L4_LPTIM1_CHANNEL = 1
+
 endif # !STM32L4_PWM_MULTICHAN
 
 endif # STM32L4_LPTIM1_PWM
@@ -3075,6 +3530,22 @@ config STM32L4_LPTIM2_CHANNEL
 		If LPTIM2 is enabled for PWM usage, you also need specifies the timer output
 		channel {1}
 
+if STM32L4_LPTIM2_CHANNEL = 1
+
+config STM32L4_LPTIM2_CH1OUT
+	bool "LPTIM2 Channel 1 Output"
+	default n
+	---help---
+		Enables channel 1 output.
+
+config STM32L4_LPTIM2_CH1NOUT
+	bool "LPTIM2 Channel 1 Complementary Output"
+	default n
+	---help---
+		Enables channel 1 Complementary Output.
+
+endif # STM32L4_LPTIM2_CHANNEL = 1
+
 endif # !STM32L4_PWM_MULTICHAN
 
 endif # STM32L4_LPTIM2_PWM
@@ -3744,6 +4215,778 @@ config STM32L4_TIM8_CAP
 		Timer devices may be used for different purposes.  One special purpose is
 		to capture input.
 
+menu "STM32L4 TIMx Outputs Configuration"
+
+config STM32L4_TIM1_CH1POL
+	int "TIM1 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH1OUT
+	---help---
+		TIM1 Channel 1 output polarity
+
+config STM32L4_TIM1_CH1IDLE
+	int "TIM1 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH1OUT
+	---help---
+		TIM1 Channel 1 output IDLE
+
+config STM32L4_TIM1_CH1NPOL
+	int "TIM1 Channel 1 Complementary Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH1NOUT
+	---help---
+		TIM1 Channel 1 Complementary Output polarity
+
+config STM32L4_TIM1_CH1NIDLE
+	int "TIM1 Channel 1 Complementary Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH1NOUT
+	---help---
+		TIM1 Channel 1 Complementary Output IDLE
+
+config STM32L4_TIM1_CH2POL
+	int "TIM1 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH2OUT
+	---help---
+		TIM1 Channel 2 output polarity
+
+config STM32L4_TIM1_CH2IDLE
+	int "TIM1 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH2OUT
+	---help---
+		TIM1 Channel 2 output IDLE
+
+config STM32L4_TIM1_CH2NPOL
+	int "TIM1 Channel 2 Complementary Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH2NOUT
+	---help---
+		TIM1 Channel 2 Complementary Output polarity
+
+config STM32L4_TIM1_CH2NIDLE
+	int "TIM1 Channel 2 Complementary Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH2NOUT
+	---help---
+		TIM1 Channel 2 Complementary Output IDLE
+
+config STM32L4_TIM1_CH3POL
+	int "TIM1 Channel 3 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH3OUT
+	---help---
+		TIM1 Channel 3 output polarity
+
+config STM32L4_TIM1_CH3IDLE
+	int "TIM1 Channel 3 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH3OUT
+	---help---
+		TIM1 Channel 3 output IDLE
+
+config STM32L4_TIM1_CH3NPOL
+	int "TIM1 Channel 3 Complementary Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH3NOUT
+	---help---
+		TIM1 Channel 3 Complementary Output polarity
+
+config STM32L4_TIM1_CH3NIDLE
+	int "TIM1 Channel 3 Complementary Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH3NOUT
+	---help---
+		TIM1 Channel 3 Complementary Output IDLE
+
+config STM32L4_TIM1_CH4POL
+	int "TIM1 Channel 4 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH4OUT
+	---help---
+		TIM1 Channel 4 output polarity
+
+config STM32L4_TIM1_CH4IDLE
+	int "TIM1 Channel 4 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH4OUT
+	---help---
+		TIM1 Channel 4 output IDLE
+
+config STM32L4_TIM1_CH5POL
+	int "TIM1 Channel 5 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH5OUT
+	---help---
+		TIM1 Channel 5 output polarity
+
+config STM32L4_TIM1_CH5IDLE
+	int "TIM1 Channel 5 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH5OUT
+	---help---
+		TIM1 Channel 5 output IDLE
+
+config STM32L4_TIM1_CH6POL
+	int "TIM1 Channel 6 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH6OUT
+	---help---
+		TIM1 Channel 6 output polarity
+
+config STM32L4_TIM1_CH6IDLE
+	int "TIM1 Channel 6 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM1_CH6OUT
+	---help---
+		TIM1 Channel 6 output IDLE
+
+config STM32L4_TIM2_CH1POL
+	int "TIM2 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM2_CH1OUT
+	---help---
+		TIM2 Channel 1 output polarity
+
+config STM32L4_TIM2_CH1IDLE
+	int "TIM2 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM2_CH1OUT
+	---help---
+		TIM2 Channel 1 output IDLE
+
+config STM32L4_TIM2_CH2POL
+	int "TIM2 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM2_CH2OUT
+	---help---
+		TIM2 Channel 2 output polarity
+
+config STM32L4_TIM2_CH2IDLE
+	int "TIM2 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM2_CH2OUT
+	---help---
+		TIM2 Channel 2 output IDLE
+
+config STM32L4_TIM2_CH3POL
+	int "TIM2 Channel 3 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM2_CH3OUT
+	---help---
+		TIM2 Channel 3 output polarity
+
+config STM32L4_TIM2_CH3IDLE
+	int "TIM2 Channel 3 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM2_CH3OUT
+	---help---
+		TIM2 Channel 3 output IDLE
+
+config STM32L4_TIM2_CH4POL
+	int "TIM2 Channel 4 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM2_CH4OUT
+	---help---
+		TIM2 Channel 4 output polarity
+
+config STM32L4_TIM2_CH4IDLE
+	int "TIM2 Channel 4 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM2_CH4OUT
+	---help---
+		TIM2 Channel 4 output IDLE
+
+config STM32L4_TIM3_CH1POL
+	int "TIM3 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM3_CH1OUT
+	---help---
+		TIM3 Channel 1 output polarity
+
+config STM32L4_TIM3_CH1IDLE
+	int "TIM3 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM3_CH1OUT
+	---help---
+		TIM3 Channel 1 output IDLE
+
+config STM32L4_TIM3_CH2POL
+	int "TIM3 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM3_CH2OUT
+	---help---
+		TIM3 Channel 2 output polarity
+
+config STM32L4_TIM3_CH2IDLE
+	int "TIM3 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM3_CH2OUT
+	---help---
+		TIM3 Channel 2 output IDLE
+
+config STM32L4_TIM3_CH3POL
+	int "TIM3 Channel 3 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM3_CH3OUT
+	---help---
+		TIM3 Channel 3 output polarity
+
+config STM32L4_TIM3_CH3IDLE
+	int "TIM3 Channel 3 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM3_CH3OUT
+	---help---
+		TIM3 Channel 3 output IDLE
+
+config STM32L4_TIM3_CH4POL
+	int "TIM3 Channel 4 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM3_CH4OUT
+	---help---
+		TIM3 Channel 4 output polarity
+
+config STM32L4_TIM3_CH4IDLE
+	int "TIM3 Channel 4 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM3_CH4OUT
+	---help---
+		TIM3 Channel 4 output IDLE
+
+config STM32L4_TIM4_CH1POL
+	int "TIM4 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM4_CH1OUT
+	---help---
+		TIM4 Channel 1 output polarity
+
+config STM32L4_TIM4_CH1IDLE
+	int "TIM4 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM4_CH1OUT
+	---help---
+		TIM4 Channel 1 output IDLE
+
+config STM32L4_TIM4_CH2POL
+	int "TIM4 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM4_CH2OUT
+	---help---
+		TIM4 Channel 2 output polarity
+
+config STM32L4_TIM4_CH2IDLE
+	int "TIM4 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM4_CH2OUT
+	---help---
+		TIM4 Channel 2 output IDLE
+
+config STM32L4_TIM4_CH3POL
+	int "TIM4 Channel 3 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM4_CH3OUT
+	---help---
+		TIM4 Channel 3 output polarity
+
+config STM32L4_TIM4_CH3IDLE
+	int "TIM4 Channel 3 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM4_CH3OUT
+	---help---
+		TIM4 Channel 3 output IDLE
+
+config STM32L4_TIM4_CH4POL
+	int "TIM4 Channel 4 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM4_CH4OUT
+	---help---
+		TIM4 Channel 4 output polarity
+
+config STM32L4_TIM4_CH4IDLE
+	int "TIM4 Channel 4 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM4_CH4OUT
+	---help---
+		TIM4 Channel 4 output IDLE
+
+config STM32L4_TIM5_CH1POL
+	int "TIM5 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM5_CH1OUT
+	---help---
+		TIM5 Channel 1 output polarity
+
+config STM32L4_TIM5_CH1IDLE
+	int "TIM5 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM5_CH1OUT
+	---help---
+		TIM5 Channel 1 output IDLE
+
+config STM32L4_TIM5_CH2POL
+	int "TIM5 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM5_CH2OUT
+	---help---
+		TIM5 Channel 2 output polarity
+
+config STM32L4_TIM5_CH2IDLE
+	int "TIM5 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM5_CH2OUT
+	---help---
+		TIM5 Channel 2 output IDLE
+
+config STM32L4_TIM5_CH3POL
+	int "TIM5 Channel 3 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM5_CH3OUT
+	---help---
+		TIM5 Channel 3 output polarity
+
+config STM32L4_TIM5_CH3IDLE
+	int "TIM5 Channel 3 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM5_CH3OUT
+	---help---
+		TIM5 Channel 3 output IDLE
+
+config STM32L4_TIM5_CH4POL
+	int "TIM5 Channel 4 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM5_CH4OUT
+	---help---
+		TIM5 Channel 4 output polarity
+
+config STM32L4_TIM5_CH4IDLE
+	int "TIM5 Channel 4 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM5_CH4OUT
+	---help---
+		TIM5 Channel 4 output IDLE
+
+config STM32L4_TIM8_CH1POL
+	int "TIM8 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH1OUT
+	---help---
+		TIM8 Channel 1 output polarity
+
+config STM32L4_TIM8_CH1IDLE
+	int "TIM8 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH1OUT
+	---help---
+		TIM8 Channel 1 output IDLE
+
+config STM32L4_TIM8_CH1NPOL
+	int "TIM8 Channel 1 Complementary Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH1NOUT
+	---help---
+		TIM8 Channel 1 Complementary Output polarity
+
+config STM32L4_TIM8_CH1NIDLE
+	int "TIM8 Channel 1 Complementary Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH1NOUT
+	---help---
+		TIM8 Channel 1 Complementary Output IDLE
+
+config STM32L4_TIM8_CH2POL
+	int "TIM8 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH2OUT
+	---help---
+		TIM8 Channel 2 output polarity
+
+config STM32L4_TIM8_CH2IDLE
+	int "TIM8 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH2OUT
+	---help---
+		TIM8 Channel 2 output IDLE
+
+config STM32L4_TIM8_CH2NPOL
+	int "TIM8 Channel 2 Complementary Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH2NOUT
+	---help---
+		TIM8 Channel 2 Complementary Output polarity
+
+config STM32L4_TIM8_CH2NIDLE
+	int "TIM8 Channel 2 Complementary Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH2NOUT
+	---help---
+		TIM8 Channel 2 Complementary Output IDLE
+
+config STM32L4_TIM8_CH3POL
+	int "TIM8 Channel 3 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH3OUT
+	---help---
+		TIM8 Channel 3 output polarity
+
+config STM32L4_TIM8_CH3IDLE
+	int "TIM8 Channel 3 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH3OUT
+	---help---
+		TIM8 Channel 3 output IDLE
+
+config STM32L4_TIM8_CH3NPOL
+	int "TIM8 Channel 3 Complementary Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH3NOUT
+	---help---
+		TIM8 Channel 3 Complementary Output polarity
+
+config STM32L4_TIM8_CH3NIDLE
+	int "TIM8 Channel 3 Complementary Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH3NOUT
+	---help---
+		TIM8 Channel 3 Complementary Output IDLE
+
+config STM32L4_TIM8_CH4POL
+	int "TIM8 Channel 4 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH4OUT
+	---help---
+		TIM8 Channel 4 output polarity
+
+config STM32L4_TIM8_CH4IDLE
+	int "TIM8 Channel 4 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH4OUT
+	---help---
+		TIM8 Channel 4 output IDLE
+
+config STM32L4_TIM8_CH5POL
+	int "TIM8 Channel 5 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH5OUT
+	---help---
+		TIM8 Channel 5 output polarity
+
+config STM32L4_TIM8_CH5IDLE
+	int "TIM8 Channel 5 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH5OUT
+	---help---
+		TIM8 Channel 5 output IDLE
+
+config STM32L4_TIM8_CH6POL
+	int "TIM8 Channel 6 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH6OUT
+	---help---
+		TIM8 Channel 6 output polarity
+
+config STM32L4_TIM8_CH6IDLE
+	int "TIM8 Channel 6 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM8_CH6OUT
+	---help---
+		TIM8 Channel 6 output IDLE
+
+config STM32L4_TIM9_CH1POL
+	int "TIM9 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM9_CH1OUT
+	---help---
+		TIM9 Channel 1 output polarity
+
+config STM32L4_TIM9_CH1IDLE
+	int "TIM9 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM9_CH1OUT
+	---help---
+		TIM9 Channel 1 output IDLE
+
+config STM32L4_TIM9_CH2POL
+	int "TIM9 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM9_CH2OUT
+	---help---
+		TIM9 Channel 2 output polarity
+
+config STM32L4_TIM9_CH2IDLE
+	int "TIM9 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM9_CH2OUT
+	---help---
+		TIM9 Channel 2 output IDLE
+
+config STM32L4_TIM10_CH1POL
+	int "TIM10 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM10_CH1OUT
+	---help---
+		TIM10 Channel 1 output polarity
+
+config STM32L4_TIM10_CH1IDLE
+	int "TIM10 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM10_CH1OUT
+	---help---
+		TIM10 Channel 1 output IDLE
+
+config STM32L4_TIM11_CH1POL
+	int "TIM11 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM11_CH1OUT
+	---help---
+		TIM11 Channel 1 output polarity
+
+config STM32L4_TIM11_CH1IDLE
+	int "TIM11 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM11_CH1OUT
+	---help---
+		TIM11 Channel 1 output IDLE
+
+config STM32L4_TIM12_CH1POL
+	int "TIM12 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM12_CH1OUT
+	---help---
+		TIM12 Channel 1 output polarity
+
+config STM32L4_TIM12_CH1IDLE
+	int "TIM12 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM12_CH1OUT
+	---help---
+		TIM12 Channel 1 output IDLE
+
+config STM32L4_TIM12_CH2POL
+	int "TIM12 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM12_CH2OUT
+	---help---
+		TIM12 Channel 2 output polarity
+
+config STM32L4_TIM12_CH2IDLE
+	int "TIM12 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM12_CH2OUT
+	---help---
+		TIM12 Channel 2 output IDLE
+
+config STM32L4_TIM13_CH1POL
+	int "TIM13 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM13_CH1OUT
+	---help---
+		TIM13 Channel 1 output polarity
+
+config STM32L4_TIM13_CH1IDLE
+	int "TIM13 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM13_CH1OUT
+	---help---
+		TIM13 Channel 1 output IDLE
+
+config STM32L4_TIM14_CH1POL
+	int "TIM14 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM14_CH1OUT
+	---help---
+		TIM14 Channel 1 output polarity
+
+config STM32L4_TIM14_CH1IDLE
+	int "TIM14 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM14_CH1OUT
+	---help---
+		TIM14 Channel 1 output IDLE
+
+config STM32L4_TIM15_CH1POL
+	int "TIM15 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM15_CH1OUT
+	---help---
+		TIM15 Channel 1 output polarity
+
+config STM32L4_TIM15_CH1IDLE
+	int "TIM15 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM15_CH1OUT
+	---help---
+		TIM15 Channel 1 output IDLE
+
+config STM32L4_TIM15_CH1NPOL
+	int "TIM15 Channel 1 Complementary Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM15_CH1NOUT
+	---help---
+		TIM15 Channel 1 Complementary Output polarity
+
+config STM32L4_TIM15_CH1NIDLE
+	int "TIM15 Channel 1 Complementary Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM15_CH1NOUT
+	---help---
+		TIM15 Channel 1 Complementary Output IDLE
+
+config STM32L4_TIM15_CH2POL
+	int "TIM15 Channel 2 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM15_CH2OUT
+	---help---
+		TIM15 Channel 2 output polarity
+
+config STM32L4_TIM15_CH2IDLE
+	int "TIM15 Channel 2 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM15_CH2OUT
+	---help---
+		TIM15 Channel 2 output IDLE
+
+config STM32L4_TIM15_CH2NPOL
+	int "TIM15 Channel 2 Complementary Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM15_CH2NOUT
+	---help---
+		TIM15 Channel 2 Complementary Output polarity
+
+config STM32L4_TIM15_CH2NIDLE
+	int "TIM15 Channel 2 Complementary Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM15_CH2NOUT
+	---help---
+		TIM15 Channel 2 Complementary Output IDLE
+
+config STM32L4_TIM16_CH1POL
+	int "TIM16 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM16_CH1OUT
+	---help---
+		TIM16 Channel 1 output polarity
+
+config STM32L4_TIM16_CH1IDLE
+	int "TIM16 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM16_CH1OUT
+	---help---
+		TIM16 Channel 1 output IDLE
+
+config STM32L4_TIM17_CH1POL
+	int "TIM17 Channel 1 Output polarity"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM17_CH1OUT
+	---help---
+		TIM17 Channel 1 output polarity
+
+config STM32L4_TIM17_CH1IDLE
+	int "TIM17 Channel 1 Output IDLE"
+	default 0
+	range 0 1
+	depends on STM32L4_TIM17_CH1OUT
+	---help---
+		TIM17 Channel 1 output IDLE
+
+endmenu #STM32L4 TIMx Outputs Configuration
+
 endmenu # Timer Configuration
 
 menu "ADC Configuration"
diff --git a/arch/arm/src/stm32l4/stm32l4_pwm.c b/arch/arm/src/stm32l4/stm32l4_pwm.c
index 84b36eb..d9d34e9 100644
--- a/arch/arm/src/stm32l4/stm32l4_pwm.c
+++ b/arch/arm/src/stm32l4/stm32l4_pwm.c
@@ -77,12 +77,15 @@
 
 /* The following definitions are used to identify the various time types */
 
-#define TIMTYPE_BASIC      0  /* Basic timers: TIM6,7 */
-#define TIMTYPE_GENERAL16  1  /* General 16-bit timers: TIM3,4 */
-#define TIMTYPE_COUNTUP16  2  /* General 16-bit count-up timers: TIM15-17 */
-#define TIMTYPE_GENERAL32  3  /* General 32-bit timers: TIM2,5 */
-#define TIMTYPE_ADVANCED   4  /* Advanced timers:  TIM1,8 */
-#define TIMTYPE_LOWPOWER   5  /* Low Power timers: LPTIM1,2 */
+#define TIMTYPE_BASIC        0  /* Basic timers: TIM6,7 */
+#define TIMTYPE_GENERAL16    1  /* General 16-bit timers: TIM3,4 */
+#define TIMTYPE_COUNTUP16    2  /* General 16-bit count-up timers: TIM15-17 */
+#define TIMTYPE_COUNTUP16_N  3  /* General 16-bit count-up timers with
+                                 * complementary outptus
+                                 */
+#define TIMTYPE_GENERAL32    4  /* General 32-bit timers: TIM2,5 */
+#define TIMTYPE_ADVANCED     5  /* Advanced timers:  TIM1,8 */
+#define TIMTYPE_LOWPOWER     6  /* Low Power timers: LPTIM1,2 */
 
 #define TIMTYPE_TIM1       TIMTYPE_ADVANCED
 #define TIMTYPE_TIM2       TIMTYPE_GENERAL32
@@ -92,12 +95,60 @@
 #define TIMTYPE_TIM6       TIMTYPE_BASIC
 #define TIMTYPE_TIM7       TIMTYPE_BASIC
 #define TIMTYPE_TIM8       TIMTYPE_ADVANCED
-#define TIMTYPE_TIM15      TIMTYPE_COUNTUP16
-#define TIMTYPE_TIM16      TIMTYPE_COUNTUP16
-#define TIMTYPE_TIM17      TIMTYPE_COUNTUP16
+#define TIMTYPE_TIM15      TIMTYPE_COUNTUP16_N /* Treated as ADVTIM */
+#define TIMTYPE_TIM16      TIMTYPE_COUNTUP16_N /* Treated as ADVTIM */
+#define TIMTYPE_TIM17      TIMTYPE_COUNTUP16_N /* Treated as ADVTIM */
 #define TIMTYPE_LPTIM1     TIMTYPE_LOWPOWER
 #define TIMTYPE_LPTIM2     TIMTYPE_LOWPOWER
 
+/* Advanced Timer support
+ * NOTE: TIM15-17 are not ADVTIM but they support most of the
+ *       ADVTIM functionality.  The main difference is the number of
+ *       supported capture/compare.
+ */
+
+#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM) || \
+    defined(CONFIG_STM32L4_TIM15_PWM) || defined(CONFIG_STM32L4_TIM16_PWM) || \
+    defined(CONFIG_STM32L4_TIM17_PWM)
+#  define HAVE_ADVTIM
+#else
+#  undef HAVE_ADVTIM
+#endif
+
+/* Low power Timer support */
+
+#if defined(CONFIG_STM32L4_LPTIM1_PWM) || defined(CONFIG_STM32L4_LPTIM2_PWM)
+#  define HAVE_LPTIM
+#else
+#  undef HAVE_LPTIM
+#endif
+
+/* Pulsecount support */
+
+#ifdef CONFIG_PWM_PULSECOUNT
+#  ifndef HAVE_ADVTIM
+#    error "PWM_PULSECOUNT requires HAVE_ADVTIM"
+#  endif
+#  if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
+#    define HAVE_PWM_INTERRUPT
+#  endif
+#endif
+
+/* Synchronisation support */
+
+#ifdef CONFIG_STM32L4_PWM_TRGO
+#  define HAVE_TRGO
+#endif
+
+/* Break support */
+
+#if defined(CONFIG_STM32L4_TIM1_BREAK1) || defined(CONFIG_STM32L4_TIM1_BREAK2) || \
+    defined(CONFIG_STM32L4_TIM8_BREAK1) || defined(CONFIG_STM32L4_TIM8_BREAK2) || \
+    defined(CONFIG_STM32L4_TIM15_BREAK1) || defined(CONFIG_STM32L4_TIM16_BREAK1) || \
+    defined(CONFIG_STM32L4_TIM17_BREAK1)
+#  defined HAVE_BREAK
+#endif
+
 /* Debug ********************************************************************/
 
 #ifdef CONFIG_DEBUG_PWM_INFO
@@ -110,44 +161,56 @@
  * Private Types
  ****************************************************************************/
 
-enum stm32l4_timmode_e
-{
-  STM32L4_TIMMODE_COUNTUP   = 0,
-  STM32L4_TIMMODE_COUNTDOWN = 1,
-  STM32L4_TIMMODE_CENTER1   = 2,
-  STM32L4_TIMMODE_CENTER2   = 3,
-  STM32L4_TIMMODE_CENTER3   = 4,
-};
+/* PWM output configuration */
 
-enum stm32l4_chanmode_e
+struct stm32l4_pwm_out_s
 {
-  STM32L4_CHANMODE_PWM1        = 0,
-  STM32L4_CHANMODE_PWM2        = 1,
-  STM32L4_CHANMODE_COMBINED1   = 2,
-  STM32L4_CHANMODE_COMBINED2   = 3,
-  STM32L4_CHANMODE_ASYMMETRIC1 = 4,
-  STM32L4_CHANMODE_ASYMMETRIC2 = 5,
+  uint8_t  in_use:1;                    /* Output in use */
+  uint8_t  pol:1;                       /* Polarity. Default: positive */
+  uint8_t  idle:1;                      /* Idle state. Default: inactive */
+  uint8_t  _res:5;                      /* Reserved */
+  uint32_t pincfg;                      /* Output pin configuration */
 };
 
+/* PWM channel configuration */
+
 struct stm32l4_pwmchan_s
 {
-  uint8_t channel;                     /* Timer output channel: {1,..4} */
-  enum stm32l4_chanmode_e mode;
-  uint32_t pincfg;                     /* Output pin configuration */
-  uint32_t npincfg;                    /* Complementary output pin configuration
-                                        * (only TIM1,8 CH1-3 and TIM15,16,17 CH1)
-                                        */
+  uint8_t                  channel:4;   /* Timer output channel: {1,..4} */
+  uint8_t                  mode:4;      /* PWM channel mode (see stm32l4_pwm_chanmode_e) */
+  struct stm32l4_pwm_out_s   out1;        /* PWM output configuration */
+#ifdef HAVE_BREAK
+  struct stm32l4_pwm_break_s brk;         /* PWM break configuration */
+#endif
+#ifdef HAVE_PWM_COMPLEMENTARY
+  struct stm32l4_pwm_out_s   out2;        /* PWM complementary output configuration */
+#endif
 };
 
 /* This structure represents the state of one PWM timer */
 
 struct stm32l4_pwmtimer_s
 {
-  FAR const struct pwm_ops_s *ops;     /* PWM operations */
-  struct stm32l4_pwmchan_s channels[PWM_NCHANNELS];
-  uint8_t timid;                       /* Timer ID {1,...,17} */
-  uint8_t timtype;                     /* See the TIMTYPE_* definitions */
-  enum stm32l4_timmode_e mode;
+  FAR const struct pwm_ops_s *ops;      /* PWM operations */
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  FAR const struct stm32l4_pwm_ops_s *llops; /* Low-level PWM ops */
+#endif  
+  FAR struct stm32l4_pwmchan_s *channels; /* Channels configuration */
+  uint8_t  timid:5;                     /* Timer ID {1,...,17} */
+  uint8_t  chan_num:3;                  /* Number of configured channels */
+  uint8_t  timtype:3;                   /* See the TIMTYPE_* definitions */
+  uint8_t  mode:3;                      /* Timer mode (see stm32l4_pwm_tim_mode_e) */
+  uint8_t  lock:2;                      /* TODO: Lock configuration */
+  uint8_t  t_dts:3;                     /* Clock division for t_DTS */
+  uint8_t  _res:5;                      /* Reserved */
+#ifdef HAVE_PWM_COMPLEMENTARY
+  uint8_t  deadtime;                    /* Dead-time value */
+#endif
+#ifdef HAVE_TRGO
+  uint8_t  trgo;                        /* TRGO configuration:
+                                         * 4 LSB = TRGO, 4 MSB = TRGO2
+                                         */
+#endif  
 #ifdef CONFIG_PWM_PULSECOUNT
   uint8_t irq;                         /* Timer update IRQ */
   uint8_t prev;                        /* The previous value of the RCR (pre-loaded) */
@@ -157,7 +220,7 @@ struct stm32l4_pwmtimer_s
   uint32_t frequency;                  /* Current frequency setting */
 #endif
   uint32_t base;                       /* The base address of the timer */
-  uint32_t pclk;                       /* The frequency of the peripheral clock
+  uint32_t pclk;                       /* Frequency of the peripheral clock
                                         * that drives the timer module. */
 #ifdef CONFIG_PWM_PULSECOUNT
   FAR void *handle;                    /* Handle used for upper-half callback */
@@ -170,55 +233,84 @@ struct stm32l4_pwmtimer_s
 
 /* Register access */
 
-static uint16_t stm32l4pwm_getreg(struct stm32l4_pwmtimer_s *priv,
-                                  int offset);
-static void stm32l4pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
-                              uint16_t value);
+static uint16_t pwm_getreg(struct stm32l4_pwmtimer_s *priv, int offset);
+static void pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
+                       uint16_t value);
+static void pwm_modifyreg(struct stm32l4_pwmtimer_s *priv, uint32_t offset,
+                          uint32_t clearbits, uint32_t setbits);
 
 #ifdef CONFIG_DEBUG_PWM_INFO
-static void stm32l4pwm_dumpregs(struct stm32l4_pwmtimer_s *priv,
-                                const char *msg);
+static void pwm_dumpregs(FAR struct pwm_lowerhalf_s *dev,
+                         FAR const char *msg);
 #else
-#  define stm32l4pwm_dumpregs(priv,msg)
+#  define pwm_dumpregs(priv,msg)
 #endif
 
 /* Timer management */
 
-static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
-                            FAR const struct pwm_info_s *info);
-
-static int stm32l4pwm_lptimer(FAR struct stm32l4_pwmtimer_s *priv,
-                              FAR const struct pwm_info_s *info);
-
-#if defined(CONFIG_PWM_PULSECOUNT) && (defined(CONFIG_STM32L4_TIM1_PWM) || \
-    defined(CONFIG_STM32L4_TIM8_PWM))
-static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv);
-#if defined(CONFIG_STM32L4_TIM1_PWM)
-static int stm32l4pwm_tim1interrupt(int irq, void *context, FAR void *arg);
+#ifdef CONFIG_PWM_PULSECOUNT
+static int pwm_pulsecount_timer(FAR struct pwm_lowerhalf_s *dev,
+                                FAR const struct pwm_info_s *info);
+#else
+static int pwm_timer(FAR struct pwm_lowerhalf_s *dev,
+                     FAR const struct pwm_info_s *info);
+#  ifdef HAVE_LPTIM
+static int pwm_lptimer(FAR struct pwm_lowerhalf_s *dev,
+                       FAR const struct pwm_info_s *info);
+#  endif
+static int pwm_configure(FAR struct pwm_lowerhalf_s *dev);
+#endif
+static int pwm_soft_break(FAR struct pwm_lowerhalf_s *dev, bool state); /* REVISIT: valid for all timers? */
+static int pwm_ccr_update(FAR struct pwm_lowerhalf_s *dev, uint8_t index,
+                          uint32_t ccr);
+static int pwm_mode_configure(FAR struct pwm_lowerhalf_s *dev,
+                              uint8_t channel, uint32_t mode);
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+static uint32_t pwm_ccr_get(FAR struct pwm_lowerhalf_s *dev, uint8_t index);
+#endif
+static int pwm_arr_update(FAR struct pwm_lowerhalf_s *dev, uint32_t arr);
+static uint32_t pwm_arr_get(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_outputs_enable(FAR struct pwm_lowerhalf_s *dev,
+                              uint16_t outputs, bool state);
+static int pwm_soft_update(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_frequency_update(FAR struct pwm_lowerhalf_s *dev,
+                                uint32_t frequency);
+static int pwm_timer_enable(FAR struct pwm_lowerhalf_s *dev, bool state);
+#if defined(HAVE_PWM_COMPLEMENTARY) && defined(CONFIG_STM32L4_PWM_LL_OPS)
+static int pwm_deadtime_update(FAR struct pwm_lowerhalf_s *dev, uint8_t dt);
 #endif
-#if defined(CONFIG_STM32L4_TIM8_PWM)
-static int stm32l4pwm_tim8interrupt(int irq, void *context, FAR void *arg);
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+static uint32_t pwm_ccr_get(FAR struct pwm_lowerhalf_s *dev, uint8_t index);
 #endif
-static uint8_t stm32l4pwm_pulsecount(uint32_t count);
+
+#ifdef HAVE_PWM_INTERRUPT
+static int pwm_interrupt(FAR struct pwm_lowerhalf_s *dev);
+#  ifdef CONFIG_STM32L4_TIM1_PWM
+static int pwm_tim1interrupt(int irq, void *context, FAR void *arg);
+#  endif
+#  ifdef CONFIG_STM32L4_TIM8_PWM
+static int pwm_tim8interrupt(int irq, void *context, FAR void *arg);
+#  endif
+static uint8_t pwm_pulsecount(uint32_t count);
 #endif
 
 /* PWM driver methods */
 
-static int stm32l4pwm_setup(FAR struct pwm_lowerhalf_s *dev);
-static int stm32l4pwm_shutdown(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_setup(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev);
 
 #ifdef CONFIG_PWM_PULSECOUNT
-static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
-                            FAR const struct pwm_info_s *info,
-                            FAR void *handle);
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
+                     FAR const struct pwm_info_s *info,
+                     FAR void *handle);
 #else
-static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
-                            FAR const struct pwm_info_s *info);
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
+                     FAR const struct pwm_info_s *info);
 #endif
 
-static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev);
-static int stm32l4pwm_ioctl(FAR struct pwm_lowerhalf_s *dev,
-                            int cmd, unsigned long arg);
+static int pwm_stop(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev,
+                     int cmd, unsigned long arg);
 
 /****************************************************************************
  * Private Data
@@ -230,416 +322,1032 @@ static int stm32l4pwm_ioctl(FAR struct pwm_lowerhalf_s *dev,
 
 static const struct pwm_ops_s g_pwmops =
 {
-  .setup       = stm32l4pwm_setup,
-  .shutdown    = stm32l4pwm_shutdown,
-  .start       = stm32l4pwm_start,
-  .stop        = stm32l4pwm_stop,
-  .ioctl       = stm32l4pwm_ioctl,
+  .setup       = pwm_setup,
+  .shutdown    = pwm_shutdown,
+  .start       = pwm_start,
+  .stop        = pwm_stop,
+  .ioctl       = pwm_ioctl,
+};
+
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+static const struct stm32l4_pwm_ops_s g_llpwmops =
+{
+  .configure       = pwm_configure,
+  .soft_break      = pwm_soft_break,
+  .ccr_update      = pwm_ccr_update,
+  .mode_update     = pwm_mode_configure,
+  .ccr_get         = pwm_ccr_get,
+  .arr_update      = pwm_arr_update,
+  .arr_get         = pwm_arr_get,
+  .outputs_enable  = pwm_outputs_enable,
+  .soft_update     = pwm_soft_update,
+  .freq_update     = pwm_frequency_update,
+  .tim_enable      = pwm_timer_enable,
+#  ifdef CONFIG_DEBUG_PWM_INFO
+  .dump_regs       = pwm_dumpregs,
+#  endif
+#  ifdef HAVE_PWM_COMPLEMENTARY
+  .dt_update       = pwm_deadtime_update,
+#  endif
 };
+#endif
 
 #ifdef CONFIG_STM32L4_TIM1_PWM
-static struct stm32l4_pwmtimer_s g_pwm1dev =
+
+static struct stm32l4_pwmchan_s g_pwm1channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 1,
-  .channels    =
-  {
+  /* TIM1 has 4 channels, 4 complementary */
+
 #ifdef CONFIG_STM32L4_TIM1_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM1_CH1MODE,
+#ifdef HAVE_BREAK
+    .brk =
+    {
+#ifdef CONFIG_STM32L4_TIM1_BREAK1
+      .en1 = 1,
+      .pol1 = CONFIG_STM32L4_TIM1_BRK1POL,
+#endif
+#ifdef CONFIG_STM32L4_TIM1_BREAK2
+      .en2 = 1,
+      .pol2 = CONFIG_STM32L4_TIM1_BRK2POL,
+      .flt2 = CONFIG_STM32L4_TIM1_BRK2FLT,
+#endif
+    },
+#endif
+#ifdef CONFIG_STM32L4_TIM1_CH1OUT
+    .out1 =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM1_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM1_CH1IDLE,
       .pincfg  = PWM_TIM1_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM1_CH1MODE,
-      .npincfg = PWM_TIM1_CH1NCFG,
     },
 #endif
+#ifdef CONFIG_STM32L4_TIM1_CH1NOUT
+    .out2 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM1_CH1NPOL,
+      .idle    = CONFIG_STM32L4_TIM1_CH1NIDLE,
+      .pincfg  = PWM_TIM1_CH1NCFG,
+    }
+#endif
+  },
+#endif
 #ifdef CONFIG_STM32L4_TIM1_CHANNEL2
+  {
+    .channel = 2,
+    .mode    = CONFIG_STM32L4_TIM1_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH2OUT
+    .out1 =
     {
-      .channel = 2,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM1_CH2POL,
+      .idle    = CONFIG_STM32L4_TIM1_CH2IDLE,
       .pincfg  = PWM_TIM1_CH2CFG,
-      .mode    = CONFIG_STM32L4_TIM1_CH2MODE,
-      .npincfg = PWM_TIM1_CH2NCFG,
     },
 #endif
+#ifdef CONFIG_STM32L4_TIM1_CH2NOUT
+    .out2 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM1_CH2NPOL,
+      .idle    = CONFIG_STM32L4_TIM1_CH2NIDLE,
+      .pincfg  = PWM_TIM1_CH2NCFG,
+    }
+#endif
+  },
+#endif
 #ifdef CONFIG_STM32L4_TIM1_CHANNEL3
+  {
+    .channel = 3,
+    .mode    = CONFIG_STM32L4_TIM1_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH3OUT
+    .out1 =
     {
-      .channel = 3,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM1_CH3POL,
+      .idle    = CONFIG_STM32L4_TIM1_CH3IDLE,
       .pincfg  = PWM_TIM1_CH3CFG,
-      .mode    = CONFIG_STM32L4_TIM1_CH3MODE,
-      .npincfg = PWM_TIM1_CH3NCFG,
     },
 #endif
+#ifdef CONFIG_STM32L4_TIM1_CH3NOUT
+    .out2 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM1_CH3NPOL,
+      .idle    = CONFIG_STM32L4_TIM1_CH3NIDLE,
+      .pincfg  = PWM_TIM1_CH3NCFG,
+    }
+#endif
+  },
+#endif
 #ifdef CONFIG_STM32L4_TIM1_CHANNEL4
+  {
+    .channel = 4,
+    .mode    = CONFIG_STM32L4_TIM1_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH4OUT
+    .out1 =
     {
-      .channel = 4,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4L4_TIM1_CH4POL,
+      .idle    = CONFIG_STM32L4L4_TIM1_CH4IDLE,
       .pincfg  = PWM_TIM1_CH4CFG,
-      .mode    = CONFIG_STM32L4_TIM1_CH4MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+  },
+#endif
+#ifdef CONFIG_STM32L4_TIM1_CHANNEL5
+  {
+    .channel = 5,
+    .mode    = CONFIG_STM32L4_TIM1_CH5MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH5OUT
+    .out1 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM1_CH5POL,
+      .idle    = CONFIG_STM32L4_TIM1_CH5IDLE,
+      .pincfg  = 0,    /* No available externaly */
+    }
 #endif
   },
+#endif
+#ifdef CONFIG_STM32L4_TIM1_CHANNEL6
+  {
+    .channel = 6,
+    .mode    = CONFIG_STM32L4_TIM1_CH6MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH6OUT
+    .out1 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM1_CH6POL,
+      .idle    = CONFIG_STM32L4_TIM1_CH6IDLE,
+      .pincfg  = 0,    /* No available externaly */
+    }
+#endif
+  }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm1dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 1,
+  .chan_num    = PWM_TIM1_NCHANNELS,
+  .channels    = g_pwm1channels,
   .timtype     = TIMTYPE_TIM1,
   .mode        = CONFIG_STM32L4_TIM1_MODE,
+  .lock        = CONFIG_STM32L4_TIM1_LOCK,
+  .t_dts       = CONFIG_STM32L4_TIM1_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = CONFIG_STM32L4_TIM1_DEADTIME,
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM1_TRGO)
+  .trgo        = STM32L4_TIM1_TRGO,
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM1UP,
 #endif
   .base        = STM32L4_TIM1_BASE,
   .pclk        = STM32L4_APB2_TIM1_CLKIN,
 };
-#endif
+#endif  /* CONFIG_STM32L4_TIM1_PWM */
 
 #ifdef CONFIG_STM32L4_TIM2_PWM
-static struct stm32l4_pwmtimer_s g_pwm2dev =
+
+static struct stm32l4_pwmchan_s g_pwm2channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 2,
-  .channels    =
-  {
+  /* TIM2 has 4 channels */
+
 #ifdef CONFIG_STM32L4_TIM2_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM2_CH1MODE,
+#ifdef CONFIG_STM32L4_TIM2_CH1OUT
+    .out1 =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM2_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM2_CH1IDLE,
       .pincfg  = PWM_TIM2_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM2_CH1MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM2_CHANNEL2
+  {
+    .channel = 2,
+    .mode    = CONFIG_STM32L4_TIM2_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM2_CH2OUT
+    .out1 =
     {
-      .channel = 2,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM2_CH2POL,
+      .idle    = CONFIG_STM32L4_TIM2_CH2IDLE,
       .pincfg  = PWM_TIM2_CH2CFG,
-      .mode    = CONFIG_STM32L4_TIM2_CH2MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM2_CHANNEL3
+  {
+    .channel = 3,
+    .mode    = CONFIG_STM32L4_TIM2_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM2_CH3OUT
+    .out1 =
     {
-      .channel = 3,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM2_CH3POL,
+      .idle    = CONFIG_STM32L4_TIM2_CH3IDLE,
       .pincfg  = PWM_TIM2_CH3CFG,
-      .mode    = CONFIG_STM32L4_TIM2_CH3MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM2_CHANNEL4
+  {
+    .channel = 4,
+    .mode    = CONFIG_STM32L4_TIM2_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM2_CH4OUT
+    .out1 =
     {
-      .channel = 4,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM2_CH4POL,
+      .idle    = CONFIG_STM32L4_TIM2_CH4IDLE,
       .pincfg  = PWM_TIM2_CH4CFG,
-      .mode    = CONFIG_STM32L4_TIM2_CH4MODE,
-      .npincfg = 0,
-    },
+    }
 #endif
-  },
+    /* No complementary outputs */
+  }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm2dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 2,
+  .chan_num    = PWM_TIM2_NCHANNELS,
+  .channels    = g_pwm2channels,
   .timtype     = TIMTYPE_TIM2,
   .mode        = CONFIG_STM32L4_TIM2_MODE,
+  .lock        = 0,             /* No lock */
+  .t_dts       = 0,             /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = 0,             /* No deadtime */
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM2_TRGO)
+  .trgo        = STM32L4_TIM2_TRGO,
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM2,
 #endif
   .base        = STM32L4_TIM2_BASE,
   .pclk        = STM32L4_APB1_TIM2_CLKIN,
 };
-#endif
+
+#endif  /* CONFIG_STM32L4_TIM2_PWM */
 
 #ifdef CONFIG_STM32L4_TIM3_PWM
-static struct stm32l4_pwmtimer_s g_pwm3dev =
+
+static struct stm32l4_pwmchan_s g_pwm3channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 3,
-  .channels    =
-  {
+  /* TIM3 has 4 channels */
+
 #ifdef CONFIG_STM32L4_TIM3_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM3_CH1MODE,
+#ifdef CONFIG_STM32L4_TIM3_CH1OUT
+    .out1    =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM3_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM3_CH1IDLE,
       .pincfg  = PWM_TIM3_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM3_CH1MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM3_CHANNEL2
+  {
+    .channel = 2,
+    .mode    = CONFIG_STM32L4_TIM3_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM3_CH2OUT
+    .out1    =
     {
-      .channel = 2,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM3_CH2POL,
+      .idle    = CONFIG_STM32L4_TIM3_CH2IDLE,
       .pincfg  = PWM_TIM3_CH2CFG,
-      .mode    = CONFIG_STM32L4_TIM3_CH2MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM3_CHANNEL3
+  {
+    .channel = 3,
+    .mode    = CONFIG_STM32L4_TIM3_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM3_CH3OUT
+    .out1    =
     {
-      .channel = 3,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM3_CH3POL,
+      .idle    = CONFIG_STM32L4_TIM3_CH3IDLE,
       .pincfg  = PWM_TIM3_CH3CFG,
-      .mode    = CONFIG_STM32L4_TIM3_CH3MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM3_CHANNEL4
+  {
+    .channel = 4,
+    .mode    = CONFIG_STM32L4_TIM3_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM3_CH4OUT
+    .out1    =
     {
-      .channel = 4,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM3_CH4POL,
+      .idle    = CONFIG_STM32L4_TIM3_CH4IDLE,
       .pincfg  = PWM_TIM3_CH4CFG,
-      .mode    = CONFIG_STM32L4_TIM3_CH4MODE,
-      .npincfg = 0,
-    },
+    }
 #endif
-  },
+    /* No complementary outputs */
+  }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm3dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 3,
+  .chan_num    = PWM_TIM3_NCHANNELS,
+  .channels    = g_pwm3channels,
   .timtype     = TIMTYPE_TIM3,
   .mode        = CONFIG_STM32L4_TIM3_MODE,
+  .lock        = 0,             /* No lock */
+  .t_dts       = 0,             /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = 0,             /* No deadtime */
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM3_TRGO)
+  .trgo        = STM32L4_TIM3_TRGO,
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM3,
 #endif
   .base        = STM32L4_TIM3_BASE,
   .pclk        = STM32L4_APB1_TIM3_CLKIN,
 };
-#endif
+#endif  /* CONFIG_STM32L4_TIM3_PWM */
 
 #ifdef CONFIG_STM32L4_TIM4_PWM
-static struct stm32l4_pwmtimer_s g_pwm4dev =
+
+static struct stm32l4_pwmchan_s g_pwm4channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 4,
-  .channels    =
-  {
+  /* TIM4 has 4 channels */
+
 #ifdef CONFIG_STM32L4_TIM4_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM4_CH1MODE,
+#ifdef CONFIG_STM32L4_TIM4_CH1OUT
+    .out1    =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM4_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM4_CH1IDLE,
       .pincfg  = PWM_TIM4_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM4_CH1MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM4_CHANNEL2
+  {
+    .channel = 2,
+    .mode    = CONFIG_STM32L4_TIM4_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM4_CH2OUT
+    .out1    =
     {
-      .channel = 2,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM4_CH2POL,
+      .idle    = CONFIG_STM32L4_TIM4_CH2IDLE,
       .pincfg  = PWM_TIM4_CH2CFG,
-      .mode    = CONFIG_STM32L4_TIM4_CH2MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM4_CHANNEL3
+  {
+    .channel = 3,
+    .mode    = CONFIG_STM32L4_TIM4_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM4_CH3OUT
+    .out1    =
     {
-      .channel = 3,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM4_CH3POL,
+      .idle    = CONFIG_STM32L4_TIM4_CH3IDLE,
       .pincfg  = PWM_TIM4_CH3CFG,
-      .mode    = CONFIG_STM32L4_TIM4_CH3MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM4_CHANNEL4
+  {
+    .channel = 4,
+    .mode    = CONFIG_STM32L4_TIM4_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM4_CH4OUT
+    .out1    =
     {
-      .channel = 4,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM4_CH4POL,
+      .idle    = CONFIG_STM32L4_TIM4_CH4IDLE,
       .pincfg  = PWM_TIM4_CH4CFG,
-      .mode    = CONFIG_STM32L4_TIM4_CH4MODE,
-      .npincfg = 0,
-    },
+    }
 #endif
-  },
+    /* No complementary outputs */
+  }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm4dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 4,
+  .chan_num    = PWM_TIM4_NCHANNELS,
+  .channels    = g_pwm4channels,
   .timtype     = TIMTYPE_TIM4,
   .mode        = CONFIG_STM32L4_TIM4_MODE,
+  .lock        = 0,             /* No lock */
+  .t_dts       = 0,             /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = 0,             /* No deadtime */
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM4_TRGO)
+  .trgo        = STM32L4_TIM4_TRGO,
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM4,
 #endif
   .base        = STM32L4_TIM4_BASE,
   .pclk        = STM32L4_APB1_TIM4_CLKIN,
 };
-#endif
+#endif  /* CONFIG_STM32L4_TIM4_PWM */
 
 #ifdef CONFIG_STM32L4_TIM5_PWM
-static struct stm32l4_pwmtimer_s g_pwm5dev =
+
+static struct stm32l4_pwmchan_s g_pwm5channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 5,
-  .channels    =
-  {
+  /* TIM5 has 4 channels */
+
 #ifdef CONFIG_STM32L4_TIM5_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM5_CH1MODE,
+#ifdef CONFIG_STM32L4_TIM5_CH1OUT
+    .out1    =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM5_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM5_CH1IDLE,
       .pincfg  = PWM_TIM5_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM5_CH1MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM5_CHANNEL2
+  {
+    .channel = 2,
+    .mode    = CONFIG_STM32L4_TIM5_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM5_CH2OUT
+    .out1    =
     {
-      .channel = 2,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM5_CH2POL,
+      .idle    = CONFIG_STM32L4_TIM5_CH2IDLE,
       .pincfg  = PWM_TIM5_CH2CFG,
-      .mode    = CONFIG_STM32L4_TIM5_CH2MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+    /* No complementary outputs */
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM5_CHANNEL3
+  {
+    .channel = 3,
+    .mode    = CONFIG_STM32L4_TIM5_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM5_CH3OUT
+    .out1    =
     {
-      .channel = 3,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM5_CH3POL,
+      .idle    = CONFIG_STM32L4_TIM5_CH3IDLE,
       .pincfg  = PWM_TIM5_CH3CFG,
-      .mode    = CONFIG_STM32L4_TIM5_CH3MODE,
-      .npincfg = 0,
-    },
+    }
+#endif
+  },
 #endif
 #ifdef CONFIG_STM32L4_TIM5_CHANNEL4
+  {
+    .channel = 4,
+    .mode    = CONFIG_STM32L4_TIM5_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM5_CH4OUT
+    .out1    =
     {
-      .channel = 4,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM5_CH4POL,
+      .idle    = CONFIG_STM32L4_TIM5_CH4IDLE,
       .pincfg  = PWM_TIM5_CH4CFG,
-      .mode    = CONFIG_STM32L4_TIM5_CH4MODE,
-      .npincfg = 0,
-    },
+    }
 #endif
   },
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm5dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 5,
+  .chan_num    = PWM_TIM5_NCHANNELS,
+  .channels    = g_pwm5channels,
   .timtype     = TIMTYPE_TIM5,
   .mode        = CONFIG_STM32L4_TIM5_MODE,
+  .lock        = 0,             /* No lock */
+  .t_dts       = 0,             /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = 0,             /* No deadtime */
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM5_TRGO)
+  .trgo        = STM32L4_TIM5_TRGO
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM5,
 #endif
   .base        = STM32L4_TIM5_BASE,
   .pclk        = STM32L4_APB1_TIM5_CLKIN,
 };
-#endif
+#endif  /* CONFIG_STM32L4_TIM5_PWM */
 
 #ifdef CONFIG_STM32L4_TIM8_PWM
-static struct stm32l4_pwmtimer_s g_pwm8dev =
+
+static struct stm32l4_pwmchan_s g_pwm8channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 8,
-  .channels    =
-  {
+  /* TIM8 has 4 channels, 4 complementary */
+
 #ifdef CONFIG_STM32L4_TIM8_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM8_CH1MODE,
+#ifdef HAVE_BREAK
+    .brk =
     {
-      .channel = 1,
-      .pincfg  = PWM_TIM8_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM8_CH1MODE,
-      .npincfg = PWM_TIM8_CH1NCFG,
-    },
+#ifdef CONFIG_STM32L4_TIM8_BREAK1
+      .en1 = 1,
+      .pol1 = CONFIG_STM32L4_TIM8_BRK1POL,
+#endif
+#ifdef CONFIG_STM32L4_TIM8_BREAK2
+      .en2 = 1,
+      .pol2 = CONFIG_STM32L4_TIM8_BRK2POL,
+      .flt2 = CONFIG_STM32L4_TIM8_BRK2FLT,
 #endif
-#ifdef CONFIG_STM32L4_TIM8_CHANNEL2
-    {
-      .channel = 2,
-      .pincfg  = PWM_TIM8_CH2CFG,
-      .mode    = CONFIG_STM32L4_TIM8_CH2MODE,
-      .npincfg = PWM_TIM8_CH2NCFG,
     },
 #endif
-#ifdef CONFIG_STM32L4_TIM8_CHANNEL3
+#ifdef CONFIG_STM32L4_TIM8_CH1OUT
+    .out1 =
     {
-      .channel = 3,
-      .pincfg  = PWM_TIM8_CH3CFG,
-      .mode    = CONFIG_STM32L4_TIM8_CH3MODE,
-      .npincfg = PWM_TIM8_CH3NCFG,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM8_CH1IDLE,
+      .pincfg  = PWM_TIM8_CH1CFG,
     },
 #endif
-#ifdef CONFIG_STM32L4_TIM8_CHANNEL4
+#ifdef CONFIG_STM32L4_TIM8_CH1NOUT
+    .out2 =
     {
-      .channel = 4,
-      .pincfg  = PWM_TIM8_CH4CFG,
-      .mode    = CONFIG_STM32L4_TIM8_CH4MODE,
-      .npincfg = 0,
-    },
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH1NPOL,
+      .idle    = CONFIG_STM32L4_TIM8_CH1NIDLE,
+      .pincfg  = PWM_TIM8_CH1NCFG,
+    }
 #endif
   },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL2
+  {
+    .channel = 2,
+    .mode    = CONFIG_STM32L4_TIM8_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH2OUT
+    .out1 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH2POL,
+      .idle    = CONFIG_STM32L4_TIM8_CH2IDLE,
+      .pincfg  = PWM_TIM8_CH2CFG,
+    },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CH2NOUT
+    .out2 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH2NPOL,
+      .idle    = CONFIG_STM32L4_TIM8_CH2NIDLE,
+      .pincfg  = PWM_TIM8_CH2NCFG,
+    }
+#endif
+  },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL3
+  {
+    .channel = 3,
+    .mode    = CONFIG_STM32L4_TIM8_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH3OUT
+    .out1 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH3POL,
+      .idle    = CONFIG_STM32L4_TIM8_CH3IDLE,
+      .pincfg  = PWM_TIM8_CH3CFG,
+    },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CH3NOUT
+    .out2 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH3NPOL,
+      .idle    = CONFIG_STM32L4_TIM8_CH3NIDLE,
+      .pincfg  = PWM_TIM8_CH3NCFG,
+    }
+#endif
+  },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL4
+  {
+    .channel = 4,
+    .mode    = CONFIG_STM32L4_TIM8_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH4OUT
+    .out1 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH4POL,
+      .idle    = CONFIG_STM32L4_TIM8_CH4IDLE,
+      .pincfg  = PWM_TIM8_CH4CFG,
+    }
+#endif
+  },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL5
+  {
+    .channel = 5,
+    .mode    = CONFIG_STM32L4_TIM8_CH5MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH5OUT
+    .out1 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH5POL,
+      .idle    = CONFIG_STM32L4_TIM8_CH5IDLE,
+      .pincfg  = 0,    /* No available externaly */
+    }
+#endif
+  },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL6
+  {
+    .channel = 6,
+    .mode    = CONFIG_STM32L4_TIM8_CH6MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH6OUT
+    .out1 =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM8_CH6POL,
+      .idle    = CONFIG_STM32L4_TIM8_CH6IDLE,
+      .pincfg  = 0,    /* No available externaly */
+    }
+#endif
+  }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm8dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 8,
+  .chan_num    = PWM_TIM8_NCHANNELS,
+  .channels    = g_pwm8channels,
   .timtype     = TIMTYPE_TIM8,
   .mode        = CONFIG_STM32L4_TIM8_MODE,
+  .lock        = CONFIG_STM32L4_TIM8_LOCK,
+  .t_dts       = CONFIG_STM32L4_TIM8_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = CONFIG_STM32L4_TIM8_DEADTIME,
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM8_TRGO)
+  .trgo        = STM32L4_TIM8_TRGO,
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM8UP,
 #endif
   .base        = STM32L4_TIM8_BASE,
   .pclk        = STM32L4_APB2_TIM8_CLKIN,
 };
-#endif
+#endif  /* CONFIG_STM32L4_TIM8_PWM */
 
 #ifdef CONFIG_STM32L4_TIM15_PWM
-static struct stm32l4_pwmtimer_s g_pwm15dev =
+
+static struct stm32l4_pwmchan_s g_pwm15channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 15,
-  .channels    =
-  {
+  /* TIM15 has 2 channels, 1 complementary */
+
 #ifdef CONFIG_STM32L4_TIM15_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM15_CH1MODE,
+#ifdef HAVE_BREAK
+    .brk =
+    {
+#ifdef CONFIG_STM32L4_TIM15_BREAK1
+      .en1 = 1,
+      .pol1 = CONFIG_STM32L4_TIM15_BRK1POL,
+#endif
+      /* No BREAK2 */
+    },
+#endif
+#ifdef CONFIG_STM32L4_TIM15_CH1OUT
+    .out1    =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM15_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM15_CH1IDLE,
       .pincfg  = PWM_TIM15_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM15_CH1MODE,
-      .npincfg = PWM_TIM15_CH1NCFG,
     },
 #endif
+#ifdef CONFIG_STM32L4_TIM15_CH1NOUT
+    .out2    =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM15_CH1NPOL,
+      .idle    = CONFIG_STM32L4_TIM15_CH1NIDLE,
+      .pincfg  = PWM_TIM15_CH2CFG,
+    }
+#endif
+  },
+#endif
 #ifdef CONFIG_STM32L4_TIM15_CHANNEL2
+  {
+    .channel = 2,
+    .mode    = CONFIG_STM32L4_TIM15_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM12_CH2OUT
+    .out1    =
     {
-      .channel = 2,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM15_CH2POL,
+      .idle    = CONFIG_STM32L4_TIM15_CH2IDLE,
       .pincfg  = PWM_TIM15_CH2CFG,
-      .mode    = CONFIG_STM32L4_TIM15_CH2MODE,
-      .npincfg = 0,
-    },
+    }
 #endif
+    /* No complementary outputs */
   },
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm15dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 15,
+  .chan_num    = PWM_TIM15_NCHANNELS,
+  .channels    = g_pwm15channels,
   .timtype     = TIMTYPE_TIM15,
   .mode        = STM32L4_TIMMODE_COUNTUP,
+  .lock        = CONFIG_STM32L4_TIM15_LOCK,
+  .t_dts       = CONFIG_STM32L4_TIM15_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = CONFIG_STM32L4_TIM15_DEADTIME,
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM15_TRGO)
+  .trgo        = STM32L4_TIM15_TRGO,
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM15,
 #endif
   .base        = STM32L4_TIM15_BASE,
   .pclk        = STM32L4_APB2_TIM15_CLKIN,
 };
-#endif
+#endif  /* CONFIG_STM32L4_TIM15_PWM */
 
 #ifdef CONFIG_STM32L4_TIM16_PWM
-static struct stm32l4_pwmtimer_s g_pwm16dev =
+
+static struct stm32l4_pwmchan_s g_pwm16channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 16,
-  .channels    =
-  {
+  /* TIM16 has 1 channel, 1 complementary */
+
 #ifdef CONFIG_STM32L4_TIM16_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM16_CH1MODE,
+#ifdef HAVE_BREAK
+    .brk =
+    {
+#ifdef CONFIG_STM32L4_TIM16_BREAK1
+      .en1 = 1,
+      .pol1 = CONFIG_STM32L4_TIM16_BRK1POL,
+#endif
+      /* No BREAK2 */
+    },
+#endif
+#ifdef CONFIG_STM32L4_TIM16_CH1OUT
+    .out1    =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM16_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM16_CH1IDLE,
       .pincfg  = PWM_TIM16_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM16_CH1MODE,
-      .npincfg = PWM_TIM16_CH1NCFG,
     },
 #endif
+#ifdef CONFIG_STM32L4_TIM16_CH1NOUT
+    .out2    =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM16_CH1NPOL,
+      .idle    = CONFIG_STM32L4_TIM16_CH1NIDLE,
+      .pincfg  = PWM_TIM16_CH2CFG,
+    }
+#endif
   },
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm16dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 16,
+  .chan_num    = PWM_TIM16_NCHANNELS,
+  .channels    = g_pwm16channels,
   .timtype     = TIMTYPE_TIM16,
   .mode        = STM32L4_TIMMODE_COUNTUP,
+  .lock        = CONFIG_STM32L4_TIM16_LOCK,
+  .t_dts       = CONFIG_STM32L4_TIM16_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = CONFIG_STM32L4_TIM16_DEADTIME,
+#endif
+#if defined(HAVE_TRGO)
+  .trgo        = 0,             /* TRGO not supported for TIM16 */
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM16,
 #endif
   .base        = STM32L4_TIM16_BASE,
   .pclk        = STM32L4_APB2_TIM16_CLKIN,
 };
-#endif
+#endif  /* CONFIG_STM32L4_TIM16_PWM */
 
 #ifdef CONFIG_STM32L4_TIM17_PWM
-static struct stm32l4_pwmtimer_s g_pwm17dev =
+
+static struct stm32l4_pwmchan_s g_pwm17channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 17,
-  .channels    =
-  {
+  /* TIM17 has 1 channel, 1 complementary */
+
 #ifdef CONFIG_STM32L4_TIM17_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = CONFIG_STM32L4_TIM17_CH1MODE,
+#ifdef HAVE_BREAK
+    .brk =
+    {
+#ifdef CONFIG_STM32L4_TIM17_BREAK1
+      .en1 = 1,
+      .pol1 = CONFIG_STM32L4_TIM17_BRK1POL,
+#endif
+      /* No BREAK2 */
+    },
+#endif
+#ifdef CONFIG_STM32L4_TIM17_CH1OUT
+    .out1    =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM17_CH1POL,
+      .idle    = CONFIG_STM32L4_TIM17_CH1IDLE,
       .pincfg  = PWM_TIM17_CH1CFG,
-      .mode    = CONFIG_STM32L4_TIM17_CH1MODE,
-      .npincfg = PWM_TIM17_CH1NCFG,
     },
 #endif
+#ifdef CONFIG_STM32L4_TIM17_CH1NOUT
+    .out2    =
+    {
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_TIM17_CH1NPOL,
+      .idle    = CONFIG_STM32L4_TIM17_CH1NIDLE,
+      .pincfg  = PWM_TIM17_CH2CFG,
+    }
+#endif
   },
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm17dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 17,
+  .chan_num    = PWM_TIM17_NCHANNELS,
+  .channels    = g_pwm17channels,
   .timtype     = TIMTYPE_TIM17,
   .mode        = STM32L4_TIMMODE_COUNTUP,
+  .lock        = CONFIG_STM32L4_TIM17_LOCK,
+  .t_dts       = CONFIG_STM32L4_TIM17_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = CONFIG_STM32L4_TIM17_DEADTIME,
+#endif
+#if defined(HAVE_TRGO)
+  .trgo        = 0,             /* TRGO not supported for TIM17 */
+#endif
 #ifdef CONFIG_PWM_PULSECOUNT
   .irq         = STM32L4_IRQ_TIM17,
 #endif
   .base        = STM32L4_TIM17_BASE,
   .pclk        = STM32L4_APB2_TIM17_CLKIN,
 };
-#endif
+#endif  /* CONFIG_STM32L4_TIM17_PWM */
 
 #ifdef CONFIG_STM32L4_LPTIM1_PWM
-static struct stm32l4_pwmtimer_s g_pwmlp1dev =
+
+static struct stm32l4_pwmchan_s g_pwmlp1channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 1,
-  .channels    =
-  {
+  /* LPTIM1 has 1 channel */
+
 #ifdef CONFIG_STM32L4_LPTIM1_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = 0,
+#ifdef CONFIG_STM32L4_LPTIM1_CH1OUT
+    .out1    =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = CONFIG_STM32L4_LPTIM1_CH1POL,
+      .idle    = 0,             /* No idle */
       .pincfg  = PWM_LPTIM1_CH1CFG,
-      .npincfg = PWM_LPTIM1_CH1NCFG,
-    },
+    }
 #endif
+    /* No complementary outputs */
   },
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwmlp1dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 1,
+  .chan_num    = PWM_LPTIM1_NCHANNELS,
+  .channels    = g_pwmlp1channels,
   .timtype     = TIMTYPE_LPTIM1,
   .mode        = STM32L4_TIMMODE_COUNTUP,
+  .lock        = 0,             /* No lock */
+  .t_dts       = 0,             /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = 0,             /* No deadtime */
+#endif
+#if defined(HAVE_TRGO)
+  .trgo        = 0,             /* TRGO not supported for LPTIM1 */
+#endif
+#ifdef CONFIG_PWM_PULSECOUNT
+  .irq         = STM32L4_IRQ_LPTIM1,
+#endif
   .base        = STM32L4_LPTIM1_BASE,
 #if defined(CONFIG_STM32L4_LPTIM1_CLK_APB1)
   .pclk        = STM32L4_PCLK1_FREQUENCY,
@@ -651,25 +1359,54 @@ static struct stm32l4_pwmtimer_s g_pwmlp1dev =
   .pclk        = STM32L4_HSI_FREQUENCY,
 #endif
 };
-#endif
+#endif  /* CONFIG_STM32L4_LPTIM1_PWM */
 
 #ifdef CONFIG_STM32L4_LPTIM2_PWM
-static struct stm32l4_pwmtimer_s g_pwmlp2dev =
+
+static struct stm32l4_pwmchan_s g_pwmlp2channels[] =
 {
-  .ops         = &g_pwmops,
-  .timid       = 2,
-  .channels    =
-  {
+  /* LPTIM2 has 1 channel */
+
 #ifdef CONFIG_STM32L4_LPTIM2_CHANNEL1
+  {
+    .channel = 1,
+    .mode    = 0,
+#ifdef CONFIG_STM32L4_LPTIM2_CH1OUT
+    .out1    =
     {
-      .channel = 1,
+      .in_use  = 1,
+      .pol     = 0,             /* REVISIT: Configure using CONFIG_STM32L4_LPTIM2_CH1POL, */
+      .idle    = 0,             /* No idle */
       .pincfg  = PWM_LPTIM2_CH1CFG,
-      .npincfg = PWM_LPTIM2_CH1NCFG,
-    },
+    }
 #endif
+    /* No complementary outputs */
   },
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwmlp2dev =
+{
+  .ops         = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+  .llops       = &g_llpwmops,
+#endif
+  .timid       = 2,
+  .chan_num    = PWM_LPTIM2_NCHANNELS,
+  .channels    = g_pwmlp2channels,
   .timtype     = TIMTYPE_LPTIM2,
   .mode        = STM32L4_TIMMODE_COUNTUP,
+  .lock        = 0,             /* No lock */
+  .t_dts       = 0,             /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+  .deadtime    = 0,             /* No deadtime */
+#endif
+#if defined(HAVE_TRGO)
+  .trgo        = 0,             /* TRGO not supported for LPTIM2 */
+#endif
+#ifdef CONFIG_PWM_PULSECOUNT
+  .irq         = STM32L4_IRQ_LPTIM2,
+#endif
   .base        = STM32L4_LPTIM2_BASE,
 #if defined(CONFIG_STM32L4_LPTIM2_CLK_APB1)
   .pclk        = STM32L4_PCLK1_FREQUENCY,
@@ -681,14 +1418,14 @@ static struct stm32l4_pwmtimer_s g_pwmlp2dev =
   .pclk        = STM32L4_HSI_FREQUENCY,
 #endif
 };
-#endif
+#endif  /* CONFIG_STM32L4_LPTIM2_PWM */
 
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: stm32l4pwm_getreg
+ * Name: pwm_getreg
  *
  * Description:
  *   Read the value of an PWM timer register.
@@ -702,13 +1439,13 @@ static struct stm32l4_pwmtimer_s g_pwmlp2dev =
  *
  ****************************************************************************/
 
-static uint16_t stm32l4pwm_getreg(struct stm32l4_pwmtimer_s *priv, int offset)
+static uint16_t pwm_getreg(struct stm32l4_pwmtimer_s *priv, int offset)
 {
   return getreg16(priv->base + offset);
 }
 
 /****************************************************************************
- * Name: stm32l4pwm_putreg
+ * Name: pwm_putreg
  *
  * Description:
  *   Read the value of an PWM timer register.
@@ -722,7 +1459,7 @@ static uint16_t stm32l4pwm_getreg(struct stm32l4_pwmtimer_s *priv, int offset)
  *
  ****************************************************************************/
 
-static void stm32l4pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
+static void pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
                               uint16_t value)
 {
   if (priv->timtype == TIMTYPE_GENERAL32 &&
@@ -748,7 +1485,50 @@ static void stm32l4pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
 }
 
 /****************************************************************************
- * Name: stm32l4pwm_dumpregs
+ * Name: pwm_modifyreg
+ *
+ * Description:
+ *   Modify PWM register (32-bit or 16-bit)
+ *
+ * Input Parameters:
+ *   priv    - A reference to the PWM block status
+ *   offset  - The offset to the register to read
+ *   clrbits - The bits to clear
+ *   setbits - The bits to set
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void pwm_modifyreg(struct stm32l4_pwmtimer_s *priv, uint32_t offset,
+                          uint32_t clearbits, uint32_t setbits)
+{
+  if (priv->timtype == TIMTYPE_GENERAL32 &&
+      (offset == STM32L4_GTIM_CNT_OFFSET ||
+       offset == STM32L4_GTIM_ARR_OFFSET ||
+       offset == STM32L4_GTIM_CCR1_OFFSET ||
+       offset == STM32L4_GTIM_CCR2_OFFSET ||
+       offset == STM32L4_GTIM_CCR3_OFFSET ||
+       offset == STM32L4_GTIM_CCR4_OFFSET))
+    {
+      /* a 32 bit access is required for a 32 bit register:
+       * if only a 16 bit write would be performed, then the
+       * upper 16 bits of the 32 bit register will be a copy of
+       * the lower 16 bits.
+       */
+
+      modifyreg32(priv->base + offset, clearbits, setbits);
+    }
+  else
+    {
+      modifyreg16(priv->base + offset, (uint16_t)clearbits,
+                  (uint16_t)setbits);
+    }
+}
+
+/****************************************************************************
+ * Name: pwm_dumpregs
  *
  * Description:
  *   Dump all timer registers.
@@ -762,136 +1542,373 @@ static void stm32l4pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
  ****************************************************************************/
 
 #ifdef CONFIG_DEBUG_PWM_INFO
-static void stm32l4pwm_dumpregs(struct stm32l4_pwmtimer_s *priv,
-                                FAR const char *msg)
+static void pwm_dumpregs(FAR struct pwm_lowerhalf_s *dev,
+                         FAR const char *msg)
 {
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
   if (priv->timtype == TIMTYPE_LOWPOWER)
     {
       pwminfo("%s:\n", msg);
       pwminfo("  CFGR: %04x CR:  %04x CMP:  %04x ARR:  %04x\n",
-              stm32l4pwm_getreg(priv, STM32L4_LPTIM_CFGR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_LPTIM_CMP_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_LPTIM_ARR_OFFSET));
+              pwm_getreg(priv, STM32L4_LPTIM_CFGR_OFFSET),
+              pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET),
+              pwm_getreg(priv, STM32L4_LPTIM_CMP_OFFSET),
+              pwm_getreg(priv, STM32L4_LPTIM_ARR_OFFSET));
       pwminfo("  ISR:  %04x CNT: %04x\n",
-              stm32l4pwm_getreg(priv, STM32L4_LPTIM_ISR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_LPTIM_CNT_OFFSET));
+              pwm_getreg(priv, STM32L4_LPTIM_ISR_OFFSET),
+              pwm_getreg(priv, STM32L4_LPTIM_CNT_OFFSET));
     }
   else
     {
       pwminfo("%s:\n", msg);
       pwminfo("  CR1: %04x CR2:  %04x SMCR:  %04x DIER:  %04x\n",
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CR2_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_SMCR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_DIER_OFFSET));
+              pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_CR2_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_SMCR_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_DIER_OFFSET));
       pwminfo("   SR: %04x EGR:  %04x CCMR1: %04x CCMR2: %04x\n",
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_SR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_EGR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CCMR1_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CCMR2_OFFSET));
+              pwm_getreg(priv, STM32L4_GTIM_SR_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_EGR_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_CCMR1_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_CCMR2_OFFSET));
       pwminfo(" CCER: %04x CNT:  %04x PSC:   %04x ARR:   %04x\n",
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CNT_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_PSC_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_ARR_OFFSET));
+              pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_CNT_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_PSC_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_ARR_OFFSET));
       pwminfo(" CCR1: %04x CCR2: %04x CCR3:  %04x CCR4:  %04x\n",
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CCR1_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CCR2_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CCR3_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_CCR4_OFFSET));
+              pwm_getreg(priv, STM32L4_GTIM_CCR1_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_CCR2_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_CCR3_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_CCR4_OFFSET));
 #if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
       if (priv->timtype == TIMTYPE_ADVANCED)
         {
           pwminfo("  RCR: %04x BDTR: %04x DCR:   %04x DMAR:  %04x\n",
-              stm32l4pwm_getreg(priv, STM32L4_ATIM_RCR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_ATIM_DCR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_ATIM_DMAR_OFFSET));
+              pwm_getreg(priv, STM32L4_ATIM_RCR_OFFSET),
+              pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET),
+              pwm_getreg(priv, STM32L4_ATIM_DCR_OFFSET),
+              pwm_getreg(priv, STM32L4_ATIM_DMAR_OFFSET));
         }
       else
 #endif
         {
           pwminfo("  DCR: %04x DMAR: %04x\n",
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_DCR_OFFSET),
-              stm32l4pwm_getreg(priv, STM32L4_GTIM_DMAR_OFFSET));
+              pwm_getreg(priv, STM32L4_GTIM_DCR_OFFSET),
+              pwm_getreg(priv, STM32L4_GTIM_DMAR_OFFSET));
         }
     }
 }
 #endif
 
 /****************************************************************************
- * Name: stm32l4pwm_timer
- *
- * Description:
- *   (Re-)initialize the timer resources and start the pulsed output
- *
- * Input Parameters:
- *   priv - A reference to the lower half PWM driver state structure
- *   info - A reference to the characteristics of the pulsed output
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
+ * Name: pwm_ccr_update
  ****************************************************************************/
 
-static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
-                            FAR const struct pwm_info_s *info)
-{
-#ifdef CONFIG_PWM_MULTICHAN
-  int      i;
-#endif
+static int pwm_ccr_update(FAR struct pwm_lowerhalf_s *dev, uint8_t index,
+                          uint32_t ccr)
 
-  /* Calculated values */
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint32_t offset = 0;
 
-  uint32_t prescaler;
-  uint32_t timclk;
-  uint32_t reload;
-  uint32_t ccr;
+#ifdef HAVE_LPTIM
+  if (priv->timtype == TIMTYPE_LOWPOWER)
+    {
+      /* REVISIT: What about index? Is it necessary for LPTIM? */
 
-  /* Register contents */
+      offset = STM32L4_LPTIM_CMP_OFFSET;
+      pwm_putreg(priv, offset, ccr);
 
-  uint16_t cr1;
-  uint16_t ccer;
-  uint16_t cr2;
-  uint32_t ccmr1;
-  uint32_t ccmr2;
+      return OK;
+    }
+#endif
 
-  /* New timer register bit settings */
+  /* Only ADV timers have CC5 and CC6 */
 
-  uint16_t ccenable;
-  uint16_t ccnenable;
-  uint32_t ocmode1;
-  uint32_t ocmode2;
+  if (priv->timtype != TIMTYPE_ADVANCED && (index == 5 || index == 6))
+    {
+      pwmerr("ERROR: No such CCR: %u\n", index);
+      return -EINVAL;
+    }
 
-  DEBUGASSERT(priv != NULL && info != NULL);
+  /* REVISIT: start index from 0? */
 
-#if defined(CONFIG_PWM_MULTICHAN)
-  pwminfo("TIM%u frequency: %u\n",
-          priv->timid, info->frequency);
-#elif defined(CONFIG_PWM_PULSECOUNT)
-  pwminfo("TIM%u channel: %u frequency: %u duty: %08x count: %u\n",
-          priv->timid, priv->channels[0].channel, info->frequency,
-          info->duty, info->count);
-#else
-  pwminfo("TIM%u channel: %u frequency: %u duty: %08x\n",
-          priv->timid, priv->channels[0].channel, info->frequency, info->duty);
-#endif
+  switch (index)
+    {
+      case STM32L4_PWM_CHAN1:
+        {
+          offset = STM32L4_GTIM_CCR1_OFFSET;
+          break;
+        }
 
-  DEBUGASSERT(info->frequency > 0);
-#ifndef CONFIG_PWM_MULTICHAN
-  DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100));
-#endif
+      case STM32L4_PWM_CHAN2:
+        {
+          offset = STM32L4_GTIM_CCR2_OFFSET;
+          break;
+        }
 
-  /* Disable all interrupts and DMA requests, clear all pending status */
+      case STM32L4_PWM_CHAN3:
+        {
+          offset = STM32L4_GTIM_CCR3_OFFSET;
+          break;
+        }
 
-#ifdef CONFIG_PWM_PULSECOUNT
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0);
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
+      case STM32L4_PWM_CHAN4:
+        {
+          offset = STM32L4_GTIM_CCR4_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN5:
+        {
+          offset = STM32L4_ATIM_CCR5_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN6:
+        {
+          offset = STM32L4_ATIM_CCR6_OFFSET;
+          break;
+        }
+
+      default:
+        {
+          pwmerr("ERROR: No such CCR: %u\n", index);
+          return -EINVAL;
+        }
+    }
+
+  /* Update CCR register */
+
+  pwm_putreg(priv, offset, ccr);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_ccr_get
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+static uint32_t pwm_ccr_get(FAR struct pwm_lowerhalf_s *dev, uint8_t index)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint32_t offset = 0;
+
+  switch (index)
+    {
+      case STM32L4_PWM_CHAN1:
+        {
+          offset = STM32L4_GTIM_CCR1_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN2:
+        {
+          offset = STM32L4_GTIM_CCR2_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN3:
+        {
+          offset = STM32L4_GTIM_CCR3_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN4:
+        {
+          offset = STM32L4_GTIM_CCR4_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN5:
+        {
+          offset = STM32L4_ATIM_CCR5_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN6:
+        {
+          offset = STM32L4_ATIM_CCR6_OFFSET;
+          break;
+        }
+
+      default:
+        {
+          pwmerr("ERROR: No such CCR: %u\n", index);
+          return -EINVAL;
+        }
+    }
+
+  /* Return CCR register */
+
+  return pwm_getreg(priv, offset);
+}
+#endif  /* CONFIG_STM32L4_PWM_LL_OPS */
+
+/****************************************************************************
+ * Name: pwm_arr_update
+ ****************************************************************************/
+
+static int pwm_arr_update(FAR struct pwm_lowerhalf_s *dev, uint32_t arr)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+  /* Update ARR register */
+
+  if (priv->timtype == TIMTYPE_LOWPOWER)
+    {
+      pwm_putreg(priv, STM32L4_LPTIM_ARR_OFFSET, arr);
+    }
+  else
+    {
+      pwm_putreg(priv, STM32L4_GTIM_ARR_OFFSET, arr);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_arr_get
+ ****************************************************************************/
+
+static uint32_t pwm_arr_get(FAR struct pwm_lowerhalf_s *dev)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+  if (priv->timtype == TIMTYPE_LOWPOWER)
+    {
+      return pwm_getreg(priv, STM32L4_LPTIM_ARR_OFFSET);
+    }
+  else
+    {
+      return pwm_getreg(priv, STM32L4_GTIM_ARR_OFFSET);
+    }
+}
+
+/****************************************************************************
+ * Name: pwm_duty_update
+ *
+ * Description:
+ *   Try to change only channel duty
+ *
+ * Input Parameters:
+ *   dev     - A reference to the lower half PWM driver state structure
+ *   channel - Channel to by updated
+ *   duty    - New duty
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_duty_update(FAR struct pwm_lowerhalf_s *dev, uint8_t channel,
+                           ub16_t duty)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint32_t reload = 0;
+  uint32_t ccr    = 0;
+
+  /* We don't want compilation warnings if no DEBUGASSERT */
+
+  UNUSED(priv);
+
+  DEBUGASSERT(priv != NULL);
+
+  pwminfo("TIM%u channel: %u duty: %08x\n",
+          priv->timid, channel, duty);
+
+#ifndef CONFIG_STM32L4_PWM_MULTICHAN
+  DEBUGASSERT(channel == priv->channels[0].channel);
+  DEBUGASSERT(duty >= 0 && duty < uitoub16(100));
+#endif
+
+  /* Get the reload values */
+
+  reload = pwm_arr_get(dev);
+
+  /* Duty cycle:
+   *
+   * duty cycle = ccr / reload (fractional value)
+   */
+
+  ccr = b16toi(duty * reload + b16HALF);
+
+  pwminfo("ccr: %u\n", ccr);
+
+  /* Write coresponding CCR register */
+
+  pwm_ccr_update(dev, channel, ccr);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_timer_enable
+ ****************************************************************************/
+
+static int pwm_timer_enable(FAR struct pwm_lowerhalf_s *dev, bool state)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+#ifdef HAVE_LPTIM
+  if (priv->timtype != TIMTYPE_LOWPOWER)
+    {
+#endif
+      if (state == true)
+        {
+          /* Enable timer counter */
+
+          pwm_modifyreg(priv, STM32L4_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN);
+        }
+      else
+        {
+          /* Disable timer counter */
+
+          pwm_modifyreg(priv, STM32L4_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0);
+        }
+#ifdef HAVE_LPTIM
+    }
+  else
+    {
+      if (state == true)
+        {
+          /* Enable timer counter */
+
+          pwm_modifyreg(priv, STM32L4_LPTIM_CR_OFFSET, 0, LPTIM_CR_ENABLE);
+        }
+      else
+        {
+          /* Disable timer counter */
+
+          pwm_modifyreg(priv, STM32L4_LPTIM_CR_OFFSET, LPTIM_CR_ENABLE, 0);
+        }
+    }
 #endif
 
-  /* Calculate optimal values for the timer prescaler and for the timer reload
-   * register.  If 'frequency' is the desired frequency, then
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_frequency_update
+ *
+ * Description:
+ *   Update a PWM timer frequency
+ *
+ ****************************************************************************/
+
+static int pwm_frequency_update(FAR struct pwm_lowerhalf_s *dev,
+                                uint32_t frequency)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint32_t reload    = 0;
+  uint32_t timclk    = 0;
+  uint32_t prescaler = 0;
+
+  /* Calculate optimal values for the timer prescaler and for the timer
+   * reload register. If 'frequency' is the desired frequency, then
    *
    *   reload = timclk / frequency
    *   timclk = pclk / presc
@@ -923,7 +1940,18 @@ static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
    *            = 60,000
    */
 
-  prescaler = (priv->pclk / info->frequency + 65534) / 65535;
+  /* If timer mode is center aligned the frequency of PWM is the half of
+   * intended so multiply by x2
+   */
+
+  if ((priv->mode == STM32L4_TIMMODE_CENTER1) ||
+      (priv->mode == STM32L4_TIMMODE_CENTER2) ||
+      (priv->mode == STM32L4_TIMMODE_CENTER3))
+    {
+      frequency = frequency * 2;
+    }
+
+  prescaler = (priv->pclk / frequency + 65534) / 65535;
   if (prescaler < 1)
     {
       prescaler = 1;
@@ -935,7 +1963,7 @@ static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
 
   timclk = priv->pclk / prescaler;
 
-  reload = timclk / info->frequency;
+  reload = timclk / frequency;
   if (reload < 2)
     {
       reload = 1;
@@ -950,774 +1978,1387 @@ static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
     }
 
   pwminfo("TIM%u PCLK: %u frequency: %u TIMCLK: %u prescaler: %u reload: %u\n",
-          priv->timid, priv->pclk, info->frequency, timclk, prescaler, reload);
-
-  /* Set up the timer CR1 register:
-   *
-   * 1,8   CKD[1:0] ARPE CMS[1:0] DIR OPM URS UDIS CEN
-   * 2-5   CKD[1:0] ARPE CMS      DIR OPM URS UDIS CEN
-   * 6-7            ARPE              OPM URS UDIS CEN
-   * 9-14  CKD[1:0] ARPE                  URS UDIS CEN
-   * 15-17 CKD[1:0] ARPE              OPM URS UDIS CEN
-   */
+          priv->timid, priv->pclk, frequency, timclk, prescaler, reload);
 
-  cr1 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET);
+  /* Set the reload and prescaler values */
 
-  /* Disable the timer until we get it configured */
+  pwm_arr_update(dev, reload);
+  pwm_putreg(priv, STM32L4_GTIM_PSC_OFFSET, (uint16_t)(prescaler - 1));
 
-  cr1 &= ~GTIM_CR1_CEN;
+  return OK;
+}
 
-  /* Set the counter mode for the advanced timers (1,8) and most general
-   * purpose timers (all 2-5, but not 9-17), i.e., all but TIMTYPE_COUNTUP16
-   * and TIMTYPE_BASIC
-   */
+/****************************************************************************
+ * Name: pwm_lp_frequency_update
+ *
+ * Description:
+ *   Update a PWM timer frequency
+ *
+ ****************************************************************************/
 
-#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM2_PWM) || \
-    defined(CONFIG_STM32L4_TIM3_PWM) || defined(CONFIG_STM32L4_TIM4_PWM) || \
-    defined(CONFIG_STM32L4_TIM5_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
+#ifdef HAVE_LPTIM
+static int pwm_lp_frequency_update(FAR struct pwm_lowerhalf_s *dev,
+                                uint32_t frequency)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
 
-  if (priv->timtype != TIMTYPE_BASIC && priv->timtype != TIMTYPE_COUNTUP16)
-    {
-      /* Select the Counter Mode:
-       *
-       * GTIM_CR1_EDGE: The counter counts up or down depending on the
-       *   direction bit (DIR).
-       * GTIM_CR1_CENTER1, GTIM_CR1_CENTER2, GTIM_CR1_CENTER3: The counter
-       *   counts up then down.
-       * GTIM_CR1_DIR: 0: count up, 1: count down
-       */
+  /* Calculated values */
 
-      cr1 &= ~(GTIM_CR1_DIR | GTIM_CR1_CMS_MASK);
+  uint8_t prescaler;
+  uint32_t timclk;
+  uint32_t reload;
 
-      switch (priv->mode)
-        {
-          case STM32L4_TIMMODE_COUNTUP:
-            cr1 |= GTIM_CR1_EDGE;
-            break;
+  /* Register contents */
 
-          case STM32L4_TIMMODE_COUNTDOWN:
-            cr1 |= GTIM_CR1_EDGE | GTIM_CR1_DIR;
-            break;
+  uint32_t cfgr;
 
-          case STM32L4_TIMMODE_CENTER1:
-            cr1 |= GTIM_CR1_CENTER1;
-            break;
+  /* LPTIM only has 8 possible prescaler values, from /1 to /128
+   * We will attempt to find the lowest prescaler that results
+   * in a maximum reload value which can be represented in 16 bit.
+   * For certain desired frequencies it is possible that the clock
+   * is too high and other one needs to be selected.
+   */
 
-          case STM32L4_TIMMODE_CENTER2:
-            cr1 |= GTIM_CR1_CENTER2;
-            break;
+  for (prescaler = 0; prescaler < 8; prescaler++)
+    {
+      timclk = priv->pclk / (1 << prescaler);
+      reload = timclk / frequency;
 
-          case STM32L4_TIMMODE_CENTER3:
-            cr1 |= GTIM_CR1_CENTER3;
-            break;
+      if (reload <= 65535)
+        {
+          /* The reload counter is feasible, go with it */
 
-          default:
-            pwmerr("ERROR: No such timer mode: %u\n", (unsigned int)priv->mode);
-            return -EINVAL;
+          break;
         }
     }
-#endif
 
-  /* Set the clock division to zero for all (but the basic timers, but there
-   * should be no basic timers in this context
-   */
+  if (reload < 2)
+    {
+      reload = 1;
+    }
+  else if (reload > 65535)
+    {
+      reload = 65535;
+    }
 
-  cr1 &= ~GTIM_CR1_CKD_MASK;
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
+  /* TODO: if the desired frequency is not possible this should give an error
+   * and not simply return the feasible frequency without complaining.
+   */
 
-  /* Set the reload and prescaler values */
+  pwminfo("LPTIM%u PCLK: %u frequency: %u TIMCLK: %u prescaler: %u reload: %u\n",
+          priv->timid, priv->pclk, frequency, timclk, prescaler, reload);
 
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_ARR_OFFSET, (uint16_t)reload);
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_PSC_OFFSET, (uint16_t)(prescaler - 1));
+  /* Set the reload register value */
 
-  /* Set the advanced timer's repetition counter */
+  pwm_arr_update(dev, reload);
 
-#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
-  if (priv->timtype == TIMTYPE_ADVANCED)
+  /* Set the prescaler value */
+
+  cfgr = pwm_getreg(priv, STM32L4_LPTIM_CFGR_OFFSET);
+
+  cfgr &= ~LPTIM_CFGR_PRESC_MASK;
+  cfgr |= (prescaler << LPTIM_CFGR_PRESC_SHIFT);
+
+  pwm_putreg(priv, STM32L4_LPTIM_CFGR_OFFSET, cfgr);
+
+  return OK;
+}
+#endif /* HAVE_LPTIM */
+
+/****************************************************************************
+ * Name: pwm_timer_configure
+ *
+ * Description:
+ *   Initial configuration for PWM timer
+ *
+ ****************************************************************************/
+
+static int pwm_timer_configure(FAR struct stm32l4_pwmtimer_s *priv)
+{
+  uint16_t cr1 = 0;
+  int      ret = OK;
+
+  /* Set up the timer CR1 register:
+   *
+   * 1,8   CKD[1:0] ARPE CMS[1:0] DIR OPM URS UDIS CEN
+   * 2-5   CKD[1:0] ARPE CMS      DIR OPM URS UDIS CEN
+   * 6-7            ARPE              OPM URS UDIS CEN
+   * 9-14  CKD[1:0] ARPE                  URS UDIS CEN
+   * 15-17 CKD[1:0] ARPE              OPM URS UDIS CEN
+   */
+
+  cr1 = pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET);
+
+  /* Set the counter mode for the advanced timers (1,8) and most general
+   * purpose timers (all 2-5, but not 9-17), i.e., all but TIMTYPE_COUNTUP16
+   * and TIMTYPE_BASIC
+   */
+
+  if (priv->timtype != TIMTYPE_BASIC && priv->timtype != TIMTYPE_COUNTUP16)
     {
-      /* If a non-zero repetition count has been selected, then set the
-       * repitition counter to the count-1 (stm32l4pwm_start() has already
-       * assured us that the count value is within range).
+      /* Select the Counter Mode:
+       *
+       * GTIM_CR1_EDGE: The counter counts up or down depending on the
+       *   direction bit (DIR).
+       * GTIM_CR1_CENTER1, GTIM_CR1_CENTER2, GTIM_CR1_CENTER3: The counter
+       *   counts up then down.
+       * GTIM_CR1_DIR: 0: count up, 1: count down
        */
 
-#ifdef CONFIG_PWM_PULSECOUNT
-      if (info->count > 0)
+      cr1 &= ~(GTIM_CR1_DIR | GTIM_CR1_CMS_MASK);
+
+      switch (priv->mode)
+        {
+          case STM32L4_TIMMODE_COUNTUP:
+            {
+              cr1 |= GTIM_CR1_EDGE;
+              break;
+            }
+
+          case STM32L4_TIMMODE_COUNTDOWN:
+            {
+              cr1 |= GTIM_CR1_EDGE | GTIM_CR1_DIR;
+              break;
+            }
+
+          case STM32L4_TIMMODE_CENTER1:
+            {
+              cr1 |= GTIM_CR1_CENTER1;
+              break;
+            }
+
+          case STM32L4_TIMMODE_CENTER2:
+            {
+              cr1 |= GTIM_CR1_CENTER2;
+              break;
+            }
+
+          case STM32L4_TIMMODE_CENTER3:
+            {
+              cr1 |= GTIM_CR1_CENTER3;
+              break;
+            }
+
+          default:
+            {
+              pwmerr("ERROR: No such timer mode: %u\n",
+                     (unsigned int)priv->mode);
+              ret = -EINVAL;
+              goto errout;
+            }
+        }
+    }
+
+  /* Enable ARR Preload
+   * TODO: this should be configurable
+   */
+
+  cr1 |= GTIM_CR1_ARPE;
+
+  /* Write CR1 */
+
+  pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: pwm_mode_configure
+ *
+ * Description:
+ *   Configure a PWM mode for given channel
+ *
+ ****************************************************************************/
+
+static int pwm_mode_configure(FAR struct pwm_lowerhalf_s *dev,
+                              uint8_t channel, uint32_t mode)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint32_t chanmode = 0;
+  uint32_t ocmode   = 0;
+  uint32_t ccmr     = 0;
+  uint32_t offset   = 0;
+  int      ret      = OK;
+  bool     ocmbit   = false;
+
+  /* Only advanced timers have channels 5-6 */
+
+  if (channel > 4 && priv->timtype != TIMTYPE_ADVANCED)
+    {
+      pwmerr("ERROR: No such channel: %u\n", channel);
+      ret = -EINVAL;
+      goto errout;
+    }
+
+  /* Get channel mode
+   * TODO: configurable preload for CCxR
+   */
+
+  switch (mode)
+    {
+      case STM32L4_CHANMODE_FRZN:
+        {
+          chanmode = GTIM_CCMR_MODE_FRZN;
+          break;
+        }
+
+      case STM32L4_CHANMODE_CHACT:
+        {
+          chanmode = GTIM_CCMR_MODE_CHACT;
+          break;
+        }
+
+      case STM32L4_CHANMODE_CHINACT:
+        {
+          chanmode = GTIM_CCMR_MODE_CHINACT;
+          break;
+        }
+
+      case STM32L4_CHANMODE_OCREFTOG:
+        {
+          chanmode = GTIM_CCMR_MODE_OCREFTOG;
+          break;
+        }
+
+      case STM32L4_CHANMODE_OCREFLO:
+        {
+          chanmode = GTIM_CCMR_MODE_OCREFLO;
+          break;
+        }
+
+      case STM32L4_CHANMODE_OCREFHI:
+        {
+          chanmode = GTIM_CCMR_MODE_OCREFHI;
+          break;
+        }
+
+      case STM32L4_CHANMODE_PWM1:
+        {
+          chanmode = ATIM_CCMR_MODE_PWM1;
+          break;
+        }
+
+      case STM32L4_CHANMODE_PWM2:
+        {
+          chanmode = ATIM_CCMR_MODE_PWM2;
+          break;
+        }
+
+      case STM32L4_CHANMODE_COMBINED1:
+        {
+          chanmode = ATIM_CCMR_MODE_COMBINED1;
+          ocmbit   = true;
+          break;
+        }
+
+      case STM32L4_CHANMODE_COMBINED2:
+        {
+          chanmode = ATIM_CCMR_MODE_COMBINED2;
+          ocmbit   = true;
+          break;
+        }
+
+      case STM32L4_CHANMODE_ASYMMETRIC1:
+        {
+          chanmode = ATIM_CCMR_MODE_ASYMMETRIC1;
+          ocmbit   = true;
+          break;
+        }
+
+      case STM32L4_CHANMODE_ASYMMETRIC2:
+        {
+          chanmode = ATIM_CCMR_MODE_ASYMMETRIC2;
+          ocmbit   = true;
+          break;
+        }
+
+      default:
+        {
+          pwmerr("ERROR: No such mode: %u\n", (unsigned int)mode);
+          ret = -EINVAL;
+          goto errout;
+        }
+    }
+
+  /* PWM mode configuration */
+
+  switch (channel)
+    {
+      /* Get CCMR offset */
+
+      case STM32L4_PWM_CHAN1:
+      case STM32L4_PWM_CHAN2:
+        {
+          offset = STM32L4_GTIM_CCMR1_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN3:
+      case STM32L4_PWM_CHAN4:
+        {
+          offset = STM32L4_GTIM_CCMR2_OFFSET;
+          break;
+        }
+
+      case STM32L4_PWM_CHAN5:
+      case STM32L4_PWM_CHAN6:
+        {
+          offset = STM32L4_ATIM_CCMR3_OFFSET;
+          break;
+        }
+
+      default:
+        {
+          pwmerr("ERROR: No such channel: %u\n", channel);
+          ret = -EINVAL;
+          goto errout;
+        }
+    }
+
+  /* Get current registers */
+
+  ccmr = pwm_getreg(priv, offset);
+
+  /* PWM mode configuration.
+   * NOTE: The CCMRx registers are identical if the channels are outputs.
+   */
+
+  switch (channel)
+    {
+      /* Configure channel 1/3/5 */
+
+      case STM32L4_PWM_CHAN1:
+      case STM32L4_PWM_CHAN3:
+      case STM32L4_PWM_CHAN5:
+        {
+          /* Reset current channel 1/3/5 mode configuration */
+
+          ccmr &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK |
+                     ATIM_CCMR1_OC1PE);
+
+          /* Configure CC1/3/5 as output */
+
+          ocmode |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT);
+
+          /* Configure Compare 1/3/5 mode */
+
+          ocmode |= (chanmode << ATIM_CCMR1_OC1M_SHIFT);
+
+          /* Enable CCR1/3/5 preload */
+
+          ocmode |= ATIM_CCMR1_OC1PE;
+
+          /* Reset current OC bit */
+
+          ccmr &= ~(ATIM_CCMR1_OC1M);
+
+          /* Set an additional OC1/3/5M bit */
+
+          if (ocmbit)
+            {
+              ocmode |= ATIM_CCMR1_OC1M;
+            }
+          break;
+        }
+
+      /* Configure channel 2/4/6 */
+
+      case STM32L4_PWM_CHAN2:
+      case STM32L4_PWM_CHAN4:
+      case STM32L4_PWM_CHAN6:
+        {
+          /* Reset current channel 2/4/6 mode configuration */
+
+          ccmr &= ~(ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK |
+                     ATIM_CCMR1_OC2PE);
+
+          /* Configure CC2/4/6 as output */
+
+          ocmode |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT);
+
+          /* Configure Compare 2/4/6 mode */
+
+          ocmode |= (chanmode << ATIM_CCMR1_OC2M_SHIFT);
+
+          /* Enable CCR2/4/6 preload */
+
+          ocmode |= ATIM_CCMR1_OC2PE;
+
+          /* Reset current OC bit */
+
+          ccmr &= ~(ATIM_CCMR1_OC2M);
+
+          /* Set an additioneal OC2/4/6M bit */
+
+          if (ocmbit)
+            {
+              ocmode |= ATIM_CCMR1_OC2M;
+            }
+          break;
+        }
+    }
+
+  /* Set the selected output compare mode */
+
+  ccmr |= ocmode;
+
+  /* Write CCMRx registers */
+
+  pwm_putreg(priv, offset, ccmr);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: pwm_output_configure
+ *
+ * Description:
+ *   Configure PWM output for given channel
+ *
+ ****************************************************************************/
+
+static int pwm_output_configure(FAR struct stm32l4_pwmtimer_s *priv,
+                                uint8_t channel)
+{
+  uint32_t cr2  = 0;
+  uint32_t ccer = 0;
+
+  /* Get current registers state */
+
+  cr2  = pwm_getreg(priv, STM32L4_GTIM_CR2_OFFSET);
+  ccer = pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET);
+
+  /* | OISx/OISxN  | IDLE | for ADVANCED and COUNTUP16 | CR2 register
+   * | CCxP/CCxNP  | POL  | all PWM timers             | CCER register
+   */
+
+  /* Configure output polarity (all PWM timers) */
+
+  if (priv->channels[channel - 1].out1.pol == STM32L4_POL_NEG)
+    {
+      ccer |= (GTIM_CCER_CC1P << ((channel - 1) * 4));
+    }
+  else
+    {
+      ccer &= ~(GTIM_CCER_CC1P << ((channel - 1) * 4));
+    }
+
+#ifdef HAVE_ADVTIM
+  if (priv->timtype == TIMTYPE_ADVANCED ||
+      priv->timtype == TIMTYPE_COUNTUP16_N)
+    {
+      /* Configure output IDLE State */
+
+      if (priv->channels[channel - 1].out1.idle == STM32L4_IDLE_ACTIVE)
+        {
+          cr2 |= (ATIM_CR2_OIS1 << ((channel - 1) * 2));
+        }
+      else
+        {
+          cr2 &= ~(ATIM_CR2_OIS1 << ((channel - 1) * 2));
+        }
+
+#ifdef HAVE_PWM_COMPLEMENTARY
+      /* Configure complementary output IDLE state */
+
+      if (priv->channels[channel - 1].out2.idle == STM32L4_IDLE_ACTIVE)
+        {
+          cr2 |= (ATIM_CR2_OIS1N << ((channel - 1) * 2));
+        }
+      else
         {
-          /* Save the remaining count and the number of counts that will have
-           * elapsed on the first interrupt.
-           */
+          cr2 &= ~(ATIM_CR2_OIS1N << ((channel - 1)* 2));
+        }
+
+      /* Configure complementary output polarity */
+
+      if (priv->channels[channel - 1].out2.pol == STM32L4_POL_NEG)
+        {
+          ccer |= (ATIM_CCER_CC1NP << ((channel - 1) * 4));
+        }
+      else
+        {
+          ccer &= ~(ATIM_CCER_CC1NP << ((channel - 1) * 4));
+        }
+#endif  /* HAVE_PWM_COMPLEMENTARY */
+
+      /* TODO: OIS5 and OIS6 */
+
+      cr2 &= ~(ATIM_CR2_OIS5 | ATIM_CR2_OIS6);
+
+      /* TODO: CC5P and CC6P */
+
+      ccer &= ~(ATIM_CCER_CC5P | ATIM_CCER_CC6P);
+    }
+#ifdef HAVE_GTIM_CCXNP
+  else
+#endif  /* HAVE_GTIM_CCXNP */
+#endif  /* HAVE_ADVTIM */
+#ifdef HAVE_GTIM_CCXNP
+    {
+      /* CCxNP must be cleared if not ADVANCED timer.
+       *
+       * REVISIT: not all families have CCxNP bits for GTIM,
+       *          which causes an ugly condition above
+       */
+
+      ccer &= ~(GTIM_CCER_CC1NP << ((channel - 1) * 4));
+    }
+#endif  /* HAVE_GTIM_CCXNP */
+
+  /* Write registers */
+
+  pwm_modifyreg(priv, STM32L4_GTIM_CR2_OFFSET, 0, cr2);
+  pwm_modifyreg(priv, STM32L4_GTIM_CCER_OFFSET, 0, ccer);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_outputs_enable
+ *
+ * Description:
+ *   Enable/disable given timer PWM outputs.
+ *
+ *   NOTE: This is bulk operation - we can enable/disable many outputs
+ *   at one time
+ *
+ * Input Parameters:
+ *   dev     - A reference to the lower half PWM driver state structure
+ *   outputs - outputs to set (look at enum stm32l4_chan_e in stm32l4_pwm.h)
+ *   state   - Enable/disable operation
+ *
+ ****************************************************************************/
+
+static int pwm_outputs_enable(FAR struct pwm_lowerhalf_s *dev,
+                              uint16_t outputs, bool state)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint32_t ccer   = 0;
+  uint32_t regval = 0;
+
+  /* Get curren register state */
 
-          /* If the first interrupt occurs at the end end of the first
-           * repetition count, then the count will be the same as the RCR
-           * value.
-           */
+  ccer = pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET);
 
-          priv->prev  = stm32l4pwm_pulsecount(info->count);
-          stm32l4pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->prev - 1);
+  /* Get outputs configuration */
 
-          /* Generate an update event to reload the prescaler.  This should
-           * preload the RCR into active repetition counter.
-           */
+  regval |= ((outputs & STM32L4_PWM_OUT1)  ? ATIM_CCER_CC1E  : 0);
+  regval |= ((outputs & STM32L4_PWM_OUT1N) ? ATIM_CCER_CC1NE : 0);
+  regval |= ((outputs & STM32L4_PWM_OUT2)  ? ATIM_CCER_CC2E  : 0);
+  regval |= ((outputs & STM32L4_PWM_OUT2N) ? ATIM_CCER_CC2NE : 0);
+  regval |= ((outputs & STM32L4_PWM_OUT3)  ? ATIM_CCER_CC3E  : 0);
+  regval |= ((outputs & STM32L4_PWM_OUT3N) ? ATIM_CCER_CC3NE : 0);
+  regval |= ((outputs & STM32L4_PWM_OUT4)  ? ATIM_CCER_CC4E  : 0);
 
-          stm32l4pwm_putreg(priv, STM32L4_GTIM_EGR_OFFSET, ATIM_EGR_UG);
+  /* NOTE: CC4N does not exist, but some docs show configuration bits for it */
 
-          /* Now set the value of the RCR that will be loaded on the next
-           * update event.
-           */
+  regval |= ((outputs & STM32L4_PWM_OUT5)  ? ATIM_CCER_CC5E  : 0);
+  regval |= ((outputs & STM32L4_PWM_OUT6)  ? ATIM_CCER_CC6E  : 0);
 
-          priv->count = info->count;
-          priv->curr  = stm32l4pwm_pulsecount(info->count - priv->prev);
-          stm32l4pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1);
+  if (state == true)
+    {
+      /* Enable outpus - set bits */
+
+      ccer |= regval;
+    }
+  else
+    {
+      /* Disable outputs - reset bits */
+
+      ccer &= ~regval;
+    }
+
+  /* Write register */
+
+  pwm_putreg(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
+
+  return OK;
+}
+
+#if defined(HAVE_PWM_COMPLEMENTARY) && defined(CONFIG_STM32L4_PWM_LL_OPS)
+
+/****************************************************************************
+ * Name: pwm_deadtime_update
+ ****************************************************************************/
+
+static int pwm_deadtime_update(FAR struct pwm_lowerhalf_s *dev, uint8_t dt)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint32_t bdtr = 0;
+  int      ret  = OK;
+
+  /* Check if locked */
+
+  if (priv->lock > 0)
+    {
+      ret = -EACCES;
+      goto errout;
+    }
+
+  /* Get current register state */
+
+  bdtr = pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET);
+
+  /* TODO: check if BDTR not locked */
+
+  /* Update deadtime */
+
+  bdtr &= ~(ATIM_BDTR_DTG_MASK);
+  bdtr |= (dt << ATIM_BDTR_DTG_SHIFT);
+
+  /* Write BDTR register */
+
+  pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, bdtr);
+
+errout:
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: pwm_soft_update
+ *
+ * Description:
+ *   Generate an software update event
+ *
+ ****************************************************************************/
+
+static int pwm_soft_update(FAR struct pwm_lowerhalf_s *dev)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+  pwm_putreg(priv, STM32L4_GTIM_EGR_OFFSET, ATIM_EGR_UG);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_soft_break
+ *
+ * Description:
+ *   Generate an software break event
+ *
+ *   Outputs are enabled if state is false.
+ *   Outputs are disabled if state is true.
+ *
+ *   NOTE: only timers with complementary outputs have BDTR register and
+ *         support software break.
+ *
+ ****************************************************************************/
+
+static int pwm_soft_break(FAR struct pwm_lowerhalf_s *dev, bool state)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+  if (state == true)
+    {
+      /* Reset MOE bit */
+
+      pwm_modifyreg(priv, STM32L4_ATIM_BDTR_OFFSET, ATIM_BDTR_MOE, 0);
+    }
+  else
+    {
+      /* Set MOE bit */
+
+      pwm_modifyreg(priv, STM32L4_ATIM_BDTR_OFFSET, 0, ATIM_BDTR_MOE);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_outputs_from_channels
+ *
+ * Description:
+ *   Get enabled outputs configuration from the PWM timer state
+ *
+ ****************************************************************************/
+
+static uint16_t pwm_outputs_from_channels(FAR struct stm32l4_pwmtimer_s *priv)
+{
+  uint16_t outputs = 0;
+  uint8_t  channel = 0;
+  uint8_t  i       = 0;
+
+  for (i = 0; i < priv->chan_num; i += 1)
+    {
+      /* Get channel */
+
+      channel = priv->channels[i].channel;
+
+      /* Set outputs if channel configured */
+
+      if (channel != 0)
+        {
+          /* Enable output if confiugred */
+
+          if (priv->channels[i].out1.in_use == 1)
+            {
+              outputs |= (STM32L4_PWM_OUT1 << ((channel - 1) * 2));
+            }
+
+#ifdef HAVE_PWM_COMPLEMENTARY
+          /* Enable complementary output if configured */
+
+          if (priv->channels[i].out2.in_use == 1)
+            {
+              outputs |= (STM32L4_PWM_OUT1N << ((channel - 1) * 2));
+            }
+#endif
         }
+    }
+
+  return outputs;
+}
+
+#ifdef HAVE_ADVTIM
+
+/****************************************************************************
+ * Name: pwm_break_dt_configure
+ *
+ * Description:
+ *   Configure break and deadtime
+ *
+ * NOTE: we have to configure all BDTR registers at once due to possible
+ *       lock configuration
+ *
+ ****************************************************************************/
 
-      /* Otherwise, just clear the repetition counter */
+static int pwm_break_dt_configure(FAR struct stm32l4_pwmtimer_s *priv)
+{
+  uint32_t bdtr = 0;
 
-      else
-#endif
-        {
-          /* Set the repetition counter to zero */
+  /* Set the clock division to zero for all (but the basic timers, but there
+   * should be no basic timers in this context
+   */
 
-          stm32l4pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, 0);
+  pwm_modifyreg(priv, STM32L4_GTIM_CR1_OFFSET, GTIM_CR1_CKD_MASK,
+                priv->t_dts << GTIM_CR1_CKD_SHIFT);
 
-          /* Generate an update event to reload the prescaler */
+#ifdef HAVE_PWM_COMPLEMENTARY
+  /* Initialize deadtime */
 
-          stm32l4pwm_putreg(priv, STM32L4_GTIM_EGR_OFFSET, ATIM_EGR_UG);
-        }
-    }
-  else
+  bdtr |= (priv->deadtime << ATIM_BDTR_DTG_SHIFT);
 #endif
-    {
-      /* Generate an update event to reload the prescaler (all timers) */
 
-      stm32l4pwm_putreg(priv, STM32L4_GTIM_EGR_OFFSET, ATIM_EGR_UG);
-    }
-
-  /* Handle channel specific setup */
+#ifdef HAVE_BREAK
+  /* Configure Break 1 */
 
-  ccenable  = 0;
-  ccnenable = 0;
-  ocmode1   = 0;
-  ocmode2   = 0;
-
-#ifdef CONFIG_PWM_MULTICHAN
-  for (i = 0; i < CONFIG_PWM_NCHANNELS; i++)
-#endif
+  if (priv->brk.en1 == 1)
     {
-      ub16_t                duty;
-      uint32_t              chanmode;
-      uint32_t              compout; /* Complementary output config */
-      bool                  ocmbit = false;
-      uint8_t               channel;
-#ifdef CONFIG_PWM_MULTICHAN
-      int                   j;
-#endif
-      enum stm32l4_chanmode_e mode;
-
-#ifdef CONFIG_PWM_MULTICHAN
-      duty = info->channels[i].duty;
-      channel = info->channels[i].channel;
+      /* Enable Break 1 */
 
-      /* A value of zero means to skip this channel */
-
-      if (channel == 0)
-        {
-          continue;
-        }
+      bdtr |= ATIM_BDTR_BKE;
 
-      /* Find the channel */
+      /* Set Break 1 polarity */
 
-      for (j = 0; j < PWM_NCHANNELS; j++)
-        {
-          if (priv->channels[j].channel == channel)
-            {
-              mode = priv->channels[j].mode;
-              compout = priv->channels[j].npincfg;
-              break;
-            }
-        }
+      bdtr |= (priv->brk.pol1 == STM32L4_POL_NEG ? ATIM_BDTR_BKP : 0);
+    }
 
-      if (j >= PWM_NCHANNELS)
-        {
-          pwmerr("ERROR: No such channel: %u\n", channel);
-          return -EINVAL;
-        }
-#else
-      duty = info->duty;
-      channel = priv->channels[0].channel;
-      mode = priv->channels[0].mode;
-      compout = priv->channels[0].npincfg;
-#endif
+  /* Configure Break 1 */
 
-      /* Duty cycle:
-       *
-       * duty cycle = ccr / reload (fractional value)
-       */
+  if (priv->brk.en2 == 1)
+    {
+      /* Enable Break 2 */
 
-      ccr = b16toi(duty * reload + b16HALF);
+      bdtr |= ATIM_BDTR_BK2E;
 
-      pwminfo("ccr: %u\n", ccr);
+      /* Set Break 2 polarity */
 
-      switch (mode)
-        {
-          case STM32L4_CHANMODE_PWM1:
-            chanmode = ATIM_CCMR_MODE_PWM1;
-            break;
+      bdtr |= (priv->brk.pol2 == STM32L4_POL_NEG ? ATIM_BDTR_BK2P : 0);
 
-          case STM32L4_CHANMODE_PWM2:
-            chanmode = ATIM_CCMR_MODE_PWM2;
-            break;
+      /* Configure BRK2 filter */
 
-          case STM32L4_CHANMODE_COMBINED1:
-            chanmode = ATIM_CCMR_MODE_COMBINED1;
-            ocmbit = true;
-            break;
+      bdtr |= (priv->brk.flt2 << ATIM_BDTR_BK2F_SHIFT);
+    }
 
-          case STM32L4_CHANMODE_COMBINED2:
-            chanmode = ATIM_CCMR_MODE_COMBINED2;
-            ocmbit = true;
-            break;
+#endif  /* HAVE_BREAK */
 
-          case STM32L4_CHANMODE_ASYMMETRIC1:
-            chanmode = ATIM_CCMR_MODE_ASYMMETRIC1;
-            ocmbit = true;
-            break;
+  /* Clear the OSSI and OSSR bits in the BDTR register.
+   *
+   * REVISIT: this should be configurable
+   */
 
-          case STM32L4_CHANMODE_ASYMMETRIC2:
-            chanmode = ATIM_CCMR_MODE_ASYMMETRIC2;
-            ocmbit = true;
-            break;
+  bdtr &= ~(ATIM_BDTR_OSSI | ATIM_BDTR_OSSR);
 
-          default:
-            pwmerr("ERROR: No such mode: %u\n", (unsigned int)mode);
-            return -EINVAL;
-        }
+  /* Configure lock */
 
-      switch (channel)
-        {
-          case 1:  /* PWM Mode configuration: Channel 1 */
-            {
-              /* Select the CCER enable bit for this channel */
+  bdtr |= priv->lock << ATIM_BDTR_LOCK_SHIFT;
 
-              ccenable |= ATIM_CCER_CC1E;
+  /* Write BDTR register at once */
 
-              /* Conditionally enable the complementary output */
+  pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, bdtr);
 
-              if (compout)
-                {
-                  ccnenable |= ATIM_CCER_CC1NE;
-                }
+  return OK;
+}
 
-              /* Set the CCMR1 mode values (leave CCMR2 zero) */
+#endif /* HAVE_ADVTIM */
 
-              ocmode1  |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT) |
-                          (chanmode << ATIM_CCMR1_OC1M_SHIFT) |
-                          ATIM_CCMR1_OC1PE;
+/****************************************************************************
+ * Name: pwm_configure
+ *
+ * Description:
+ *   Configure PWM timer in normal mode (no PULSECOUNT)
+ *
+ ****************************************************************************/
 
-              if (ocmbit)
-                {
-                  ocmode1 |= ATIM_CCMR1_OC1M;
-                }
+static int pwm_configure(FAR struct pwm_lowerhalf_s *dev)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint16_t outputs = 0;
+  uint8_t j        = 0;
+  int     ret      = OK;
 
-              /* Set the duty cycle by writing to the CCR register for this channel */
+  /* NOTE: leave timer counter disabled and all outputs disabled! */
 
-              stm32l4pwm_putreg(priv, STM32L4_GTIM_CCR1_OFFSET, (uint16_t)ccr);
-            }
-            break;
+  /* Disable the timer until we get it configured */
 
-          case 2:  /* PWM Mode configuration: Channel 2 */
-            {
-              /* Select the CCER enable bit for this channel */
+  pwm_timer_enable(dev, false);
 
-              ccenable |= ATIM_CCER_CC2E;
+  /* Get configured outputs */
 
-              /* Conditionally enable the complementary output */
+  outputs = pwm_outputs_from_channels(priv);
 
-              if (compout)
-                {
-                  ccnenable |= ATIM_CCER_CC2NE;
-                }
+  /* Disable outputs */
 
-              /* Set the CCMR1 mode values (leave CCMR2 zero) */
+  ret = pwm_outputs_enable(dev, outputs, false);
+  if (ret < 0)
+    {
+      pwmerr("ERROR on pwm_outputs_enable()\n");
+      goto errout;
+    }
 
-              ocmode1  |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT) |
-                          (chanmode << ATIM_CCMR1_OC2M_SHIFT) |
-                          ATIM_CCMR1_OC2PE;
+  /* Initial timer configuration */
 
-              if (ocmbit)
-                {
-                  ocmode1 |= ATIM_CCMR1_OC2M;
-                }
+  ret = pwm_timer_configure(priv);
+  if (ret < 0)
+    {
+      pwmerr("ERROR on pwm_timer_configure()\n");
+      goto errout;
+    }
 
-              /* Set the duty cycle by writing to the CCR register for this channel */
+  /* Some special setup for advanced timers */
 
-              stm32l4pwm_putreg(priv, STM32L4_GTIM_CCR2_OFFSET, (uint16_t)ccr);
-            }
-            break;
+#ifdef HAVE_ADVTIM
+  if (priv->timtype == TIMTYPE_ADVANCED ||
+      priv->timtype == TIMTYPE_COUNTUP16_N)
+    {
+      /* Configure break and deadtime register */
 
-          case 3:  /* PWM Mode configuration: Channel 3 */
-            {
-              /* Select the CCER enable bit for this channel */
+      ret = pwm_break_dt_configure(priv);
+      if (ret < 0)
+        {
+          pwmerr("ERROR on pwm_break_dt_configure()\n");
+          goto errout;
+        }
 
-              ccenable |= ATIM_CCER_CC3E;
+#ifdef HAVE_TRGO
+      /* Configure TRGO/TRGO2 */
 
-              /* Conditionally enable the complementary output */
+      ret = pwm_sync_configure(priv, priv->trgo);
+      if (ret < 0)
+        {
+          pwmerr("ERROR on pwm_sync_configure()\n");
+          goto errout;
+        }
+#endif
+    }
+#endif
 
-              if (compout)
-                {
-                  ccnenable |= ATIM_CCER_CC3NE;
-                }
+  /* Configure timer channels */
 
-              /* Set the CCMR2 mode values (leave CCMR1 zero) */
+  for (j = 0; j < priv->chan_num; j++)
+    {
+      /* Skip channle if not in use */
 
-              ocmode2  |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC3S_SHIFT) |
-                          (chanmode << ATIM_CCMR2_OC3M_SHIFT) |
-                          ATIM_CCMR2_OC3PE;
+      if (priv->channels[j].channel != 0)
+        {
+          /* Update PWM mode */
 
-              if (ocmbit)
-                {
-                  ocmode2 |= ATIM_CCMR2_OC3M;
-                }
+          ret = pwm_mode_configure(dev, priv->channels[j].channel,
+                                   priv->channels[j].mode);
+          if (ret < 0)
+            {
+              pwmerr("ERROR on pwm_mode_configure()\n");
+              goto errout;
+            }
 
-              /* Set the duty cycle by writing to the CCR register for this channel */
+          /* PWM outputs configuration */
 
-              stm32l4pwm_putreg(priv, STM32L4_GTIM_CCR3_OFFSET, (uint16_t)ccr);
+          ret = pwm_output_configure(priv, priv->channels[j].channel);
+          if (ret < 0)
+            {
+              pwmerr("ERROR on pwm_output_configure()\n");
+              goto errout;
             }
-            break;
+        }
+    }
 
-          case 4:  /* PWM Mode configuration: Channel 4 */
-            {
-              /* Select the CCER enable bit for this channel */
+  /* Disable software break at the end of the outputs configuration (enablei
+   * outputs).
+   *
+   * NOTE: Only timers with complementary outputs have BDTR register and
+   *       support software break.
+   */
 
-              ccenable |= ATIM_CCER_CC4E;
+  if (priv->timtype == TIMTYPE_ADVANCED ||
+      priv->timtype == TIMTYPE_COUNTUP16_N)
+    {
+      pwminfo("pwm_soft_break(dev, false)\n");
+      ret = pwm_soft_break(dev, false);
+      if (ret < 0)
+        {
+          pwmerr("ERROR on pwm_soft_break()\n");
+          goto errout;
+        }
+    }
 
-              /* Set the CCMR2 mode values (leave CCMR1 zero) */
+errout:
+  return ret;
+}
 
-              ocmode2  |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC4S_SHIFT) |
-                          (chanmode << ATIM_CCMR2_OC4M_SHIFT) |
-                          ATIM_CCMR2_OC4PE;
+#ifdef CONFIG_PWM_PULSECOUNT
 
-              if (ocmbit)
-                {
-                  ocmode2 |= ATIM_CCMR2_OC4M;
-                }
+/****************************************************************************
+ * Name: pwm_pulsecount_timer
+ *
+ * Description:
+ *   (Re-)initialize the timer resources and start the pulsed output
+ *
+ * Input Parameters:
+ *   dev  - A reference to the lower half PWM driver state structure
+ *   info - A reference to the characteristics of the pulsed output
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ * TODO: PWM_PULSECOUNT should be configurable for each timer instance
+ * TODO: PULSECOUNT doesnt work with MULTICHAN at this moment
+ *
+ ****************************************************************************/
 
-              /* Set the duty cycle by writing to the CCR register for this channel */
+static int pwm_pulsecount_timer(FAR struct pwm_lowerhalf_s *dev,
+                                FAR const struct pwm_info_s *info)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  ub16_t    duty    = 0;
+  uint8_t   channel = 0;
+  uint16_t  outputs = 0;
+  int       ret     = OK;
 
-              stm32l4pwm_putreg(priv, STM32L4_GTIM_CCR4_OFFSET, (uint16_t)ccr);
-            }
-            break;
+  /* If we got here it means that timer instance support pulsecount mode! */
 
-          default:
-            pwmerr("ERROR: No such channel: %u\n", channel);
-            return -EINVAL;
-        }
-    }
+  DEBUGASSERT(priv != NULL && info != NULL);
 
-  /* Disable the Channel by resetting the CCxE Bit in the CCER register */
+  pwminfo("TIM%u channel: %u frequency: %u duty: %08x count: %u\n",
+          priv->timid, priv->channels[0].channel, info->frequency,
+          info->duty, info->count);
 
-  ccer = stm32l4pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET);
-  ccer &= ~ccenable;
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
+  DEBUGASSERT(info->frequency > 0);
 
-  /* Fetch the CR2, CCMR1, and CCMR2 register (already have cr1 and ccer) */
+  /* Channel specific setup */
 
-  cr2   = stm32l4pwm_getreg(priv, STM32L4_GTIM_CR2_OFFSET);
-  ccmr1 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CCMR1_OFFSET);
-  ccmr2 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CCMR2_OFFSET);
+  duty    = info->duty;
+  channel = priv->channels[0].channel;
 
-  /* Reset the Output Compare Mode Bits and set the select output compare mode */
+  /* Disable all interrupts and DMA requests, clear all pending status */
 
-  ccmr1 &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | ATIM_CCMR1_OC1PE |
-             ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | ATIM_CCMR1_OC2PE
-             | ATIM_CCMR1_OC1M | ATIM_CCMR1_OC2M
-             );
-  ccmr2 &= ~(ATIM_CCMR2_CC3S_MASK | ATIM_CCMR2_OC3M_MASK | ATIM_CCMR2_OC3PE |
-             ATIM_CCMR2_CC4S_MASK | ATIM_CCMR2_OC4M_MASK | ATIM_CCMR2_OC4PE
-             | ATIM_CCMR2_OC3M | ATIM_CCMR2_OC4M
-             );
-  ccmr1 |= ocmode1;
-  ccmr2 |= ocmode2;
+  pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0);
+  pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
 
-  /* Reset the output polarity level of all channels (selects high polarity)*/
+  /* Set timer frequency */
 
-  ccer &= ~(ATIM_CCER_CC1P | ATIM_CCER_CC2P | ATIM_CCER_CC3P | ATIM_CCER_CC4P);
+  ret = pwm_frequency_update(dev, info->frequency);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  /* Enable the output state of the selected channels */
+  /* Update duty cycle */
 
-  ccer &= ~(ATIM_CCER_CC1E | ATIM_CCER_CC2E | ATIM_CCER_CC3E | ATIM_CCER_CC4E);
-  ccer |= ccenable;
+  ret = pwm_duty_update(dev, channel, duty);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  /* Some special setup for advanced timers */
+  /* If a non-zero repetition count has been selected, then set the
+   * repitition counter to the count-1 (pwm_pulsecount_start() has already
+   * assured us that the count value is within range).
+   */
 
-#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
-  if (priv->timtype == TIMTYPE_ADVANCED)
+  if (info->count > 0)
     {
-      uint16_t bdtr;
-
-      /* Reset output N polarity level, output N state, output compare state,
-       * output compare N idle state.
+      /* Save the remaining count and the number of counts that will have
+       * elapsed on the first interrupt.
        */
 
-      ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | ATIM_CCER_CC2NE |
-                ATIM_CCER_CC2NP | ATIM_CCER_CC3NE | ATIM_CCER_CC3NP);
+      /* If the first interrupt occurs at the end end of the first
+       * repetition count, then the count will be the same as the RCR
+       * value.
+       */
 
-      ccer |= ccnenable;
+      priv->prev  = stm32l4pwm_pulsecount(info->count);
+      pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->prev - 1);
 
-      /* Reset the output compare and output compare N IDLE State */
+      /* Generate an update event to reload the prescaler.  This should
+       * preload the RCR into active repetition counter.
+       */
 
-      cr2 &= ~(ATIM_CR2_OIS1 | ATIM_CR2_OIS1N | ATIM_CR2_OIS2 | ATIM_CR2_OIS2N |
-               ATIM_CR2_OIS3 | ATIM_CR2_OIS3N | ATIM_CR2_OIS4);
+      pwm_soft_update(dev);
 
-      /* Set the main output enable (MOE) bit and clear the OSSI and OSSR
-       * bits in the BDTR register.
+      /* Now set the value of the RCR that will be loaded on the next
+       * update event.
        */
 
-      bdtr  = stm32l4pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET);
-      bdtr &= ~(ATIM_BDTR_OSSI | ATIM_BDTR_OSSR);
-      bdtr |= ATIM_BDTR_MOE;
-      stm32l4pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, bdtr);
+      priv->count = info->count;
+      priv->curr  = stm32l4pwm_pulsecount(info->count - priv->prev);
+      pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1);
     }
-  else
-#if defined(CONFIG_STM32L4_TIM15_PWM) || defined(CONFIG_STM32L4_TIM16_PWM) || \
-    defined(CONFIG_STM32L4_TIM17_PWM)
-  if (priv->timtype == TIMTYPE_COUNTUP16)
-    {
-      /* Reset output N polarity level, output N state, output compare state,
-       * output compare N idle state.
-       */
 
-      ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP);
-      ccer |= ccnenable;
-    }
+  /* Otherwise, just clear the repetition counter */
+
   else
-#endif
-#endif
     {
-      ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP); /* Not sure why? */
+      /* Set the repetition counter to zero */
+
+      pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, 0);
+
+      /* Generate an update event to reload the prescaler */
+
+      pwm_soft_update(dev);
     }
 
-  /* Save the modified register values */
+  /* Get configured outputs */
 
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_CR2_OFFSET, cr2);
-  putreg32(ccmr1, priv->base + STM32L4_GTIM_CCMR1_OFFSET);
-  putreg32(ccmr2, priv->base + STM32L4_GTIM_CCMR2_OFFSET);
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
+  outputs = pwm_outputs_from_channels(priv);
 
-  /* Set the ARR Preload Bit */
+  /* Enable output */
 
-  cr1 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET);
-  cr1 |= GTIM_CR1_ARPE;
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
+  ret = pwm_outputs_enable(dev, outputs, true);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
   /* Setup update interrupt.  If info->count is > 0, then we can be
-   * assured that stm32l4pwm_start() has already verified: (1) that this is an
-   * advanced timer, and that (2) the repetition count is within range.
+   * assured that pwm_pulsecount_start() has already verified: (1) that this
+   * is an advanced timer, and that (2) the repetition count is within range.
    */
 
-#ifdef CONFIG_PWM_PULSECOUNT
   if (info->count > 0)
     {
       /* Clear all pending interrupts and enable the update interrupt. */
 
-      stm32l4pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
-      stm32l4pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, ATIM_DIER_UIE);
+      pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
+      pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, ATIM_DIER_UIE);
 
       /* Enable the timer */
 
-      cr1 |= GTIM_CR1_CEN;
-      stm32l4pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
+      pwm_timer_enable(dev, true);
 
       /* And enable timer interrupts at the NVIC */
 
       up_enable_irq(priv->irq);
     }
-  else
-#endif
-    {
-      /* Just enable the timer, leaving all interrupts disabled */
 
-      cr1 |= GTIM_CR1_CEN;
-      stm32l4pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
-    }
+  pwm_dumpregs(dev, "After starting");
 
-  stm32l4pwm_dumpregs(priv, "After starting");
-  return OK;
+errout:
+  return ret;
 }
 
+#else  /* !CONFIG_PWM_PULSECOUNT */
+
 /****************************************************************************
- * Name: stm32l4pwm_lptimer
+ * Name: pwm_duty_channels_update
  *
  * Description:
- *   (Re-)initialize the low-power timer resources and start the
- *   pulsed output
- *
- * Input Parameters:
- *   priv - A reference to the lower half PWM driver state structure
- *   info - A reference to the characteristics of the pulsed output
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
+ *   Update duty cycle for given channels
  *
  ****************************************************************************/
 
-static int stm32l4pwm_lptimer(FAR struct stm32l4_pwmtimer_s *priv,
-                              FAR const struct pwm_info_s *info)
+static int pwm_duty_channels_update(FAR struct pwm_lowerhalf_s *dev,
+                                    FAR const struct pwm_info_s *info)
 {
-  /* Calculated values */
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint8_t   channel = 0;
+  ub16_t    duty    = 0;
+  int       ret     = OK;
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
+  int       i       = 0;
+  int       j       = 0;
+#endif
 
-  uint8_t prescaler;
-  uint32_t timclk;
-  uint32_t reload;
-  uint32_t ccr;
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
+  for (i = 0; i < CONFIG_PWM_NCHANNELS; i++)
+#endif
+    {
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
+      duty    = info->channels[i].duty;
+      channel = info->channels[i].channel;
 
-  /* Register contents */
+      /* A value of zero means to skip this channel */
 
-  uint16_t cr;
-  uint32_t cfgr;
+      if (channel != 0)
+        {
+          /* Find the channel */
 
-  DEBUGASSERT(priv != NULL && info != NULL);
+          for (j = 0; j < priv->chan_num; j++)
+            {
+              if (priv->channels[j].channel == channel)
+                {
+                  break;
+                }
+            }
 
-  pwminfo("LPTIM%u frequency: %u duty: %08x\n",
-#ifdef CONFIG_PWM_MULTICHAN
-          priv->timid, info->frequency, info->channels[0].duty);
+          /* Check range */
+
+          if (j >= priv->chan_num)
+            {
+              pwmerr("ERROR: No such channel: %u\n", channel);
+              ret = -EINVAL;
+              goto errout;
+            }
 #else
-          priv->timid, info->frequency, info->duty);
+          duty = info->duty;
+          channel = priv->channels[0].channel;
 #endif
 
-  DEBUGASSERT(info->frequency > 0);
-  DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100));
-
-  /* LPTIM only has 8 possible prescaler values, from /1 to /128
-   * We will attempt to find the lowest prescaler that results
-   * in a maximum reload value which can be represented in 16 bit.
-   * For certain desired frequencies it is possible that the clock
-   * is too high and other one needs to be selected.
-   */
-
-  for (prescaler = 0; prescaler < 8; prescaler++)
-    {
-      timclk = priv->pclk / (1 << prescaler);
-      reload = timclk / info->frequency;
-
-      if (reload <= 65535)
-        {
-          /* The reload counter is feasible, go with it */
+          /* Update duty cycle */
 
-          break;
+          ret = pwm_duty_update(dev, channel, duty);
+          if (ret < 0)
+            {
+              goto errout;
+            }
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
         }
+#endif
     }
 
-  if (reload < 2)
-    {
-      reload = 1;
-    }
-  else if (reload > 65535)
-    {
-      reload = 65535;
-    }
-
-  /* TODO: if the desired frequency is not possible this should give an error and
-   * not simply return the feasible frequency without complaining.
-   */
-
-  pwminfo("LPTIM%u PCLK: %u frequency: %u TIMCLK: %u prescaler: %u reload: %u\n",
-          priv->timid, priv->pclk, info->frequency, timclk, prescaler, reload);
-
-  /* Disable the timer to set the prescaler */
-
-  cr = stm32l4pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET);
+errout:
+  return OK;
+}
 
-  cr &= ~LPTIM_CR_ENABLE;
-  stm32l4pwm_putreg(priv, STM32L4_LPTIM_CR_OFFSET, cr);
+/****************************************************************************
+ * Name: pwm_timer
+ *
+ * Description:
+ *   (Re-)initialize the timer resources and start the pulsed output
+ *
+ * Input Parameters:
+ *   dev  - A reference to the lower half PWM driver state structure
+ *   info - A reference to the characteristics of the pulsed output
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
 
-  /* We have to way two counter clocks before the clock is actually enabled */
+static int pwm_timer(FAR struct pwm_lowerhalf_s *dev,
+                     FAR const struct pwm_info_s *info)
+{
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint16_t outputs = 0;
+  int      ret     = OK;
 
-  up_udelay(2 * USEC_PER_SEC / timclk);
+  DEBUGASSERT(priv != NULL && info != NULL);
 
-  /* Set the prescaler value and choose high polarity */
+#if defined(CONFIG_STM32L4_PWM_MULTICHAN)
+  pwminfo("TIM%u frequency: %u\n",
+          priv->timid, info->frequency);
+#else
+  pwminfo("TIM%u channel: %u frequency: %u duty: %08x\n",
+          priv->timid, priv->channels[0].channel,
+          info->frequency, info->duty);
+#endif
 
-  cfgr = getreg32(priv->base + STM32L4_LPTIM_CFGR_OFFSET);
+  DEBUGASSERT(info->frequency > 0);
+#ifndef CONFIG_STM32L4_PWM_MULTICHAN
+  DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100));
+#endif
 
-  cfgr &= ~LPTIM_CFGR_PRESC_MASK;
-  cfgr |= (prescaler << LPTIM_CFGR_PRESC_SHIFT) | LPTIM_CFGR_WAVPOL;
+  /* TODO: what if we have pwm running and we want disable some channels ? */
 
-  putreg32(cfgr, priv->base + STM32L4_LPTIM_CFGR_OFFSET);
+  /* Set timer frequency */
 
-  /* Enable again, ARR and CMP need to be written while enabled */
+  ret = pwm_frequency_update(dev, info->frequency);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  cr |= LPTIM_CR_ENABLE;
-  stm32l4pwm_putreg(priv, STM32L4_LPTIM_CR_OFFSET, cr);
+  /* Channel specific configuration */
 
-  /* Compute reload value */
+  ret = pwm_duty_channels_update(dev, info);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-#ifdef CONFIG_PWM_MULTICHAN
-  ub16_t duty = info->channels[0].duty;
-#else
-  ub16_t duty = info->duty;
-#endif
+  /* Set the advanced timer's repetition counter */
 
-  /* Duty cycle:
-   *
-   * duty cycle = ccr / reload (fractional value)
-   */
+#ifdef HAVE_ADVTIM
+  if (priv->timtype == TIMTYPE_ADVANCED ||
+      priv->timtype == TIMTYPE_COUNTUP16_N)
+    {
+      /* If a non-zero repetition count has been selected, then set the
+       * repitition counter to the count-1 (pwm_start() has already
+       * assured us that the count value is within range).
+       */
 
-  ccr = b16toi(duty * reload + b16HALF);
+      /* Set the repetition counter to zero */
 
-  pwminfo("ccr: %u\n", ccr);
+      pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, 0);
 
-  /* Set reload register */
+      /* Generate an update event to reload the prescaler */
 
-  stm32l4pwm_putreg(priv, STM32L4_LPTIM_ARR_OFFSET, (uint16_t)reload);
+      pwm_soft_update(dev);
+    }
+  else
+#endif
+    {
+      /* Generate an update event to reload the prescaler (all timers) */
 
-  /* Wait for write to complete */
+      pwm_soft_update(dev);
+    }
 
-  while (!(getreg32(priv->base + STM32L4_LPTIM_ISR_OFFSET) & LPTIM_ISR_ARROK));
+  /* Get configured outputs */
 
-  /* Set compare register */
+  outputs = pwm_outputs_from_channels(priv);
 
-  stm32l4pwm_putreg(priv, STM32L4_LPTIM_CMP_OFFSET, (uint16_t)ccr);
+  /* Enable outputs */
 
-  /* Wait for write to complete */
+  ret = pwm_outputs_enable(dev, outputs, true);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  while (!(getreg32(priv->base + STM32L4_LPTIM_ISR_OFFSET) & LPTIM_ISR_CMPOK));
+  /* Just enable the timer, leaving all interrupts disabled */
 
-  /* Start counter */
+  pwm_timer_enable(dev, true);
 
-  cr = stm32l4pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET);
-  cr |= LPTIM_CR_CNTSTRT;
-  stm32l4pwm_putreg(priv, STM32L4_LPTIM_CR_OFFSET, cr);
+  pwm_dumpregs(dev, "After starting");
 
-  stm32l4pwm_dumpregs(priv, "After starting");
-  return OK;
+errout:
+  return ret;
 }
 
-#ifndef CONFIG_PWM_PULSECOUNT
 /****************************************************************************
- * Name: stm32l4pwm_update_duty
+ * Name: pwm_lptimer
  *
  * Description:
- *   Try to change only channel duty.
+ *   (Re-)initialize the low-power timer resources and start the
+ *   pulsed output
  *
  * Input Parameters:
- *   priv    - A reference to the lower half PWM driver state structure
- *   channel - Channel to by updated
- *   duty    - New duty.
+ *   priv - A reference to the lower half PWM driver state structure
+ *   info - A reference to the characteristics of the pulsed output
  *
  * Returned Value:
  *   Zero on success; a negated errno value on failure
  *
  ****************************************************************************/
 
-static  int stm32l4pwm_update_duty(FAR struct stm32l4_pwmtimer_s *priv,
-                                   uint8_t channel, ub16_t duty)
+#ifdef HAVE_LPTIM
+static int pwm_lptimer(FAR struct pwm_lowerhalf_s *dev,
+                       FAR const struct pwm_info_s *info)
 {
-  /* Register offset */
-
-  int ccr_offset;
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+  uint16_t cr;
+  int      ret     = OK;
 
-  /* Calculated values */
+  DEBUGASSERT(priv != NULL && info != NULL);
 
-  uint32_t reload;
-  uint32_t ccr;
+#if defined(CONFIG_STM32L4_PWM_MULTICHAN)
+  pwminfo("LPTIM%u frequency: %u\n",
+          priv->timid, info->frequency);
+#else
+  pwminfo("LPTIM%u channel: %u frequency: %u duty: %08x\n",
+          priv->timid, priv->channels[0].channel,
+          info->frequency, info->duty);
+#endif
 
-  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(info->frequency > 0);
+#ifndef CONFIG_STM32L4_PWM_MULTICHAN
+  DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100));
+#endif
 
-  pwminfo("%s%u channel: %u duty: %08x\n",
-          priv->timtype == TIMTYPE_LOWPOWER ? "LPTIM" : "TIM",
-          priv->timid, channel, duty);
+  /* Enable again, ARR and CMP need to be written while enabled */
 
-#ifndef CONFIG_PWM_MULTICHAN
-  DEBUGASSERT(channel == priv->channels[0].channel);
-  DEBUGASSERT(duty >= 0 && duty < uitoub16(100));
-#endif
+  pwm_timer_enable(dev, true);
 
-  /* Get the reload values */
+  /* Set timer frequency */
 
-  if (priv->timtype == TIMTYPE_LOWPOWER)
-    {
-      reload = stm32l4pwm_getreg(priv, STM32L4_LPTIM_ARR_OFFSET);
-    }
-  else
+  ret = pwm_lp_frequency_update(dev, info->frequency);
+  if (ret < 0)
     {
-      reload = stm32l4pwm_getreg(priv, STM32L4_GTIM_ARR_OFFSET);
+      goto errout;
     }
 
-  /* Duty cycle:
-   *
-   * duty cycle = ccr / reload (fractional value)
-   */
-
-  ccr = b16toi(duty * reload + b16HALF);
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
+  ub16_t duty = info->channels[0].duty;
+#else
+  ub16_t duty = info->duty;
+#endif
 
-  pwminfo("ccr: %u\n", ccr);
+  /* Update duty cycle */
 
-  if (priv->timtype == TIMTYPE_LOWPOWER)
+  ret = pwm_duty_update(dev, priv->channels[0].channel, duty);
+  if (ret < 0)
     {
-      /* Low-power timers only have a compare register */
-
-      ccr_offset = STM32L4_LPTIM_CMP_OFFSET;
+      goto errout;
     }
-  else
-    {
-      switch (channel)
-        {
-          case 1:  /* Register offset for Channel 1 */
-            ccr_offset = STM32L4_GTIM_CCR1_OFFSET;
-            break;
-
-          case 2:  /* Register offset for Channel 2 */
-            ccr_offset = STM32L4_GTIM_CCR2_OFFSET;
-            break;
 
-          case 3:  /* Register offset for Channel 3 */
-            ccr_offset = STM32L4_GTIM_CCR3_OFFSET;
-            break;
+  /* Start counter */
 
-          case 4:  /* Register offset for Channel 4 */
-            ccr_offset = STM32L4_GTIM_CCR4_OFFSET;
-            break;
+  cr = pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET);
+  cr |= LPTIM_CR_CNTSTRT;
+  pwm_putreg(priv, STM32L4_LPTIM_CR_OFFSET, cr);
 
-          default:
-            pwmerr("ERROR: No such channel: %u\n", channel);
-            return -EINVAL;
-        }
-    }
+  pwm_dumpregs(dev, "After starting");
 
-  /* Set the duty cycle by writing to the CCR register for this channel */
+errout:
+  return ret;
+}
+#endif /* HAVE_LPTIM */
 
-  stm32l4pwm_putreg(priv, ccr_offset, (uint16_t)ccr);
+#endif  /* CONFIG_PWM_PULSECOUNT */
 
-  return OK;
-}
-#endif
+#ifdef HAVE_PWM_INTERRUPT
 
 /****************************************************************************
- * Name: stm32l4pwm_interrupt
+ * Name: pwm_interrupt
  *
  * Description:
  *   Handle timer interrupts.
  *
  * Input Parameters:
- *   priv - A reference to the lower half PWM driver state structure
+ *   dev - A reference to the lower half PWM driver state structure
  *
  * Returned Value:
  *   Zero on success; a negated errno value on failure
  *
  ****************************************************************************/
 
-#if defined(CONFIG_PWM_PULSECOUNT) && (defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM))
-static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv)
+static int pwm_interrupt(FAR struct pwm_lowerhalf_s *dev)
 {
+  FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
   uint16_t regval;
 
   /* Verify that this is an update interrupt.  Nothing else is expected. */
 
-  regval = stm32l4pwm_getreg(priv, STM32L4_ATIM_SR_OFFSET);
+  regval = pwm_getreg(priv, STM32L4_ATIM_SR_OFFSET);
   DEBUGASSERT((regval & ATIM_SR_UIF) != 0);
 
   /* Clear the UIF interrupt bit */
 
-  stm32l4pwm_putreg(priv, STM32L4_ATIM_SR_OFFSET, regval & ~ATIM_SR_UIF);
+  pwm_putreg(priv, STM32L4_ATIM_SR_OFFSET, regval & ~ATIM_SR_UIF);
 
   /* Calculate the new count by subtracting the number of pulses
    * since the last interrupt.
@@ -1729,13 +3370,13 @@ static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv)
        * quickly as possible.
        */
 
-      regval  = stm32l4pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET);
+      regval  = pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET);
       regval &= ~ATIM_BDTR_MOE;
-      stm32l4pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, regval);
+      pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, regval);
 
       /* Disable first interrtups, stop and reset the timer */
 
-      stm32l4pwm_stop((FAR struct pwm_lowerhalf_s *)priv);
+      pwm_stop(dev);
 
       /* Then perform the callback into the upper half driver */
 
@@ -1762,17 +3403,18 @@ static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv)
 
       priv->prev = priv->curr;
       priv->curr = stm32l4pwm_pulsecount(priv->count - priv->prev);
-      stm32l4pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1);
+      pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1);
     }
 
-  /* Now all of the time critical stuff is done so we can do some debug output */
+  /* Now all of the time critical stuff is done so we can do some debug
+   * output
+   */
 
   pwminfo("Update interrupt SR: %04x prev: %u curr: %u count: %u\n",
           regval, priv->prev, priv->curr, priv->count);
 
   return OK;
 }
-#endif
 
 /****************************************************************************
  * Name: pwm_tim1/8interrupt
@@ -1788,19 +3430,19 @@ static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv)
  *
  ****************************************************************************/
 
-#if defined(CONFIG_PWM_PULSECOUNT) && defined(CONFIG_STM32L4_TIM1_PWM)
-static int stm32l4pwm_tim1interrupt(int irq, void *context, FAR void *arg)
+#ifdef CONFIG_STM32L4_TIM1_PWM
+static int pwm_tim1interrupt(int irq, void *context, FAR void *arg)
 {
-  return stm32l4pwm_interrupt(&g_pwm1dev);
+  return pwm_interrupt((FAR struct pwm_lowerhalf_s *)&g_pwm1dev);
 }
-#endif
+#endif /* CONFIG_STM32L4_TIM1_PWM */
 
-#if defined(CONFIG_PWM_PULSECOUNT) && defined(CONFIG_STM32L4_TIM8_PWM)
-static int stm32l4pwm_tim8interrupt(int irq, void *context, FAR void *arg)
+#ifdef CONFIG_STM32L4_TIM8_PWM
+static int pwm_tim8interrupt(int irq, void *context, FAR void *arg)
 {
-  return stm32l4pwm_interrupt(&g_pwm8dev);
+  return pwm_interrupt((FAR struct pwm_lowerhalf_s *)&g_pwm8dev);
 }
-#endif
+#endif /* CONFIG_STM32L4_TIM8_PWM */
 
 /****************************************************************************
  * Name: stm32l4pwm_pulsecount
@@ -1816,7 +3458,6 @@ static int stm32l4pwm_tim8interrupt(int irq, void *context, FAR void *arg)
  *
  ****************************************************************************/
 
-#if defined(CONFIG_PWM_PULSECOUNT) && (defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM))
 static uint8_t stm32l4pwm_pulsecount(uint32_t count)
 {
   /* The the remaining pulse count is less than or equal to the maximum, the
@@ -1825,7 +3466,7 @@ static uint8_t stm32l4pwm_pulsecount(uint32_t count)
 
   if (count <= ATIM_RCR_REP_MAX)
     {
-      return count;
+      return (uint8_t)count;
     }
 
   /* Otherwise, we have to be careful.  We do not want a small number of
@@ -1837,17 +3478,17 @@ static uint8_t stm32l4pwm_pulsecount(uint32_t count)
 
   else if (count < (3 * ATIM_RCR_REP_MAX / 2))
     {
-      return (ATIM_RCR_REP_MAX + 1) >> 1;
+      return (uint8_t)((ATIM_RCR_REP_MAX + 1) >> 1);
     }
 
   /* Otherwise, return the maximum.  The final count will be 64 or more */
 
   else
     {
-      return ATIM_RCR_REP_MAX;
+      return (uint8_t)ATIM_RCR_REP_MAX;
     }
 }
-#endif
+#endif /* HAVE_PWM_INTERRUPT */
 
 /****************************************************************************
  * Name: stm32l4pwm_setapbclock
@@ -1861,10 +3502,12 @@ static uint8_t stm32l4pwm_pulsecount(uint32_t count)
  *
  ****************************************************************************/
 
-static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
+static int stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv,
+                                  bool on)
 {
   uint32_t en_bit;
   uint32_t regaddr;
+  int      ret     = OK;
 
   /* Determine which timer to configure */
 
@@ -1874,60 +3517,91 @@ static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
         {
 #ifdef CONFIG_STM32L4_TIM1_PWM
           case 1:
-            regaddr  = STM32L4_RCC_APB2ENR;
-            en_bit   = RCC_APB2ENR_TIM1EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB2ENR;
+              en_bit   = RCC_APB2ENR_TIM1EN;
+              break;
+            }
 #endif
+
 #ifdef CONFIG_STM32L4_TIM2_PWM
           case 2:
-            regaddr  = STM32L4_RCC_APB1ENR1;
-            en_bit   = RCC_APB1ENR1_TIM2EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB1ENR1;
+              en_bit   = RCC_APB1ENR1_TIM2EN;
+              break;
+            }
 #endif
+
 #ifdef CONFIG_STM32L4_TIM3_PWM
           case 3:
-            regaddr  = STM32L4_RCC_APB1ENR1;
-            en_bit   = RCC_APB1ENR1_TIM3EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB1ENR1;
+              en_bit   = RCC_APB1ENR1_TIM3EN;
+              break;
+            }
 #endif
+
 #ifdef CONFIG_STM32L4_TIM4_PWM
           case 4:
-            regaddr  = STM32L4_RCC_APB1ENR1;
-            en_bit   = RCC_APB1ENR1_TIM4EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB1ENR1;
+              en_bit   = RCC_APB1ENR1_TIM4EN;
+              break;
+            }
 #endif
+
 #ifdef CONFIG_STM32L4_TIM5_PWM
           case 5:
-            regaddr  = STM32L4_RCC_APB1ENR1;
-            en_bit   = RCC_APB1ENR1_TIM5EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB1ENR1;
+              en_bit   = RCC_APB1ENR1_TIM5EN;
+              break;
+            }
 #endif
+
 #ifdef CONFIG_STM32L4_TIM8_PWM
           case 8:
-            regaddr  = STM32L4_RCC_APB2ENR;
-            en_bit   = RCC_APB2ENR_TIM8EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB2ENR;
+              en_bit   = RCC_APB2ENR_TIM8EN;
+              break;
+            }
 #endif
+
 #ifdef CONFIG_STM32L4_TIM15_PWM
           case 15:
-            regaddr  = STM32L4_RCC_APB2ENR;
-            en_bit   = RCC_APB2ENR_TIM15EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB2ENR;
+              en_bit   = RCC_APB2ENR_TIM15EN;
+              break;
+            }
 #endif
+
 #ifdef CONFIG_STM32L4_TIM16_PWM
           case 16:
-            regaddr  = STM32L4_RCC_APB2ENR;
-            en_bit   = RCC_APB2ENR_TIM16EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB2ENR;
+              en_bit   = RCC_APB2ENR_TIM16EN;
+              break;
+            }
 #endif
+
 #ifdef CONFIG_STM32L4_TIM17_PWM
           case 17:
-            regaddr  = STM32L4_RCC_APB2ENR;
-            en_bit   = RCC_APB2ENR_TIM17EN;
-            break;
+            {
+              regaddr  = STM32L4_RCC_APB2ENR;
+              en_bit   = RCC_APB2ENR_TIM17EN;
+              break;
+          }
 #endif
+
           default:
-            return;
+          {
+            pwmerr("ERROR: No such timer configured %d\n", priv->timid);
+            ret = -EINVAL;
+            goto errout;
+          }
         }
 
       /* Enable/disable APB 1/2 clock for timer */
@@ -1941,6 +3615,7 @@ static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
           modifyreg32(regaddr, en_bit, 0);
         }
     }
+#ifdef HAVE_LPTIM
   else
     {
       uint32_t clock_bits;
@@ -1949,67 +3624,86 @@ static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
         {
 #ifdef CONFIG_STM32L4_LPTIM1_PWM
           case 1:
+            {
 #if defined(CONFIG_STM32L4_LPTIM1_CLK_APB1)
-            /* Enable APB clock for LPTIM1 */
-
-            if (on)
-              {
-                modifyreg32(STM32L4_RCC_APB1ENR1, 0, RCC_APB1ENR1_LPTIM1EN);
-              }
-            else
-              {
-                modifyreg32(STM32L4_RCC_APB1ENR1, RCC_APB1ENR1_LPTIM1EN, 0);
-              }
-
-            clock_bits = RCC_CCIPR_LPTIM1SEL_PCLK;
+              /* Enable APB clock for LPTIM1 */
+
+              if (on)
+                {
+                  modifyreg32(STM32L4_RCC_APB1ENR1,
+                              0, RCC_APB1ENR1_LPTIM1EN);
+                }
+              else
+                {
+                  modifyreg32(STM32L4_RCC_APB1ENR1,
+                              RCC_APB1ENR1_LPTIM1EN, 0);
+                }
+
+              clock_bits = RCC_CCIPR_LPTIM1SEL_PCLK;
 #elif defined(CONFIG_STM32L4_LPTIM1_CLK_LSI)
-            clock_bits = RCC_CCIPR_LPTIM1SEL_LSI;
+              clock_bits = RCC_CCIPR_LPTIM1SEL_LSI;
 #elif defined(CONFIG_STM32L4_LPTIM1_CLK_LSE)
-            clock_bits = RCC_CCIPR_LPTIM1SEL_LSE;
+              clock_bits = RCC_CCIPR_LPTIM1SEL_LSE;
 #elif defined(CONFIG_STM32L4_LPTIM1_CLK_HSI)
-            clock_bits = RCC_CCIPR_LPTIM1SEL_HSI;
+              clock_bits = RCC_CCIPR_LPTIM1SEL_HSI;
 #endif
-            /* Choose which clock will be used for LPTIM1 */
+              /* Choose which clock will be used for LPTIM1 */
 
-            modifyreg32(STM32L4_RCC_CCIPR, RCC_CCIPR_LPTIM1SEL_MASK, clock_bits);
-            break;
+              modifyreg32(STM32L4_RCC_CCIPR, RCC_CCIPR_LPTIM1SEL_MASK,
+                          clock_bits);
+              break;
+            }
 #endif
 
 #ifdef CONFIG_STM32L4_LPTIM2_PWM
           case 2:
+            {
 #if defined(CONFIG_STM32L4_LPTIM2_CLK_APB1)
-            /* Enable APB clock for LPTIM2 */
-
-            if (on)
-              {
-                modifyreg32(STM32L4_RCC_APB1ENR2, 0, RCC_APB1ENR2_LPTIM2EN);
-              }
-            else
-              {
-                modifyreg32(STM32L4_RCC_APB1ENR2, RCC_APB1ENR2_LPTIM2EN, 0);
-              }
-
-            clock_bits = RCC_CCIPR_LPTIM2SEL_PCLK;
+              /* Enable APB clock for LPTIM2 */
+
+              if (on)
+                {
+                  modifyreg32(STM32L4_RCC_APB1ENR2,
+                              0, RCC_APB1ENR2_LPTIM2EN);
+                }
+              else
+                {
+                  modifyreg32(STM32L4_RCC_APB1ENR2,
+                              RCC_APB1ENR2_LPTIM2EN, 0);
+                }
+
+              clock_bits = RCC_CCIPR_LPTIM2SEL_PCLK;
 #elif defined(CONFIG_STM32L4_LPTIM2_CLK_LSI)
-            clock_bits = RCC_CCIPR_LPTIM2SEL_LSI;
+              clock_bits = RCC_CCIPR_LPTIM2SEL_LSI;
 #elif defined(CONFIG_STM32L4_LPTIM2_CLK_LSE)
-            clock_bits = RCC_CCIPR_LPTIM2SEL_LSE;
+              clock_bits = RCC_CCIPR_LPTIM2SEL_LSE;
 #elif defined(CONFIG_STM32L4_LPTIM2_CLK_HSI)
-            clock_bits = RCC_CCIPR_LPTIM2SEL_HSI;
+              clock_bits = RCC_CCIPR_LPTIM2SEL_HSI;
 #endif
-            /* Choose which clock will be used for LPTIM2 */
+              /* Choose which clock will be used for LPTIM2 */
+
+              modifyreg32(STM32L4_RCC_CCIPR, RCC_CCIPR_LPTIM2SEL_MASK,
+                          clock_bits);
+              break;
+            }
 
-            modifyreg32(STM32L4_RCC_CCIPR, RCC_CCIPR_LPTIM2SEL_MASK, clock_bits);
-            break;
 #endif
           default:
-            return;
+            {
+              pwmerr("ERROR: No such timer configured %d\n", priv->timid);
+              ret = -EINVAL;
+              goto errout;
+            }
         }
     }
+
+#endif /* HAVE_LPTIM */
+errout:
+  return ret;
 }
 
 /****************************************************************************
- * Name: stm32l4pwm_setup
+ * Name: pwm_setup
  *
  * Description:
  *   This method is called when the driver is opened.  The lower half driver
@@ -2028,10 +3722,11 @@ static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
  *
  ****************************************************************************/
 
-static int stm32l4pwm_setup(FAR struct pwm_lowerhalf_s *dev)
+static int pwm_setup(FAR struct pwm_lowerhalf_s *dev)
 {
   FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
   uint32_t pincfg;
+  int ret;
   int i;
 
   if (priv->timtype == TIMTYPE_LOWPOWER)
@@ -2043,42 +3738,55 @@ static int stm32l4pwm_setup(FAR struct pwm_lowerhalf_s *dev)
       pwminfo("TIM%u\n", priv->timid);
     }
 
-  stm32l4pwm_dumpregs(priv, "Initially");
-
   /* Enable APB1/2 clocking for timer. */
 
   stm32l4pwm_setapbclock(priv, true);
 
+  pwm_dumpregs(dev, "Initially");
+
   /* Configure the PWM output pins, but do not start the timer yet */
 
-  for (i = 0; i < PWM_NCHANNELS; i++)
+  for (i = 0; i < priv->chan_num; i++)
     {
-      pincfg = priv->channels[i].pincfg;
-      if (pincfg != 0)
+      if (priv->channels[i].out1.in_use == 1)
         {
+          pincfg = priv->channels[i].out1.pincfg;
           pwminfo("pincfg: %08x\n", pincfg);
 
           stm32l4_configgpio(pincfg);
+          pwm_dumpgpio(pincfg, "PWM setup");
         }
 
-      /* Enable complementary channel if available */
-
-      pincfg = priv->channels[i].npincfg;
-      if (pincfg != 0)
+#ifdef HAVE_PWM_COMPLEMENTARY
+      if (priv->channels[i].out2.in_use == 1)
         {
-          pwminfo("npincfg: %08x\n", pincfg);
+          pincfg = priv->channels[i].out2.pincfg;
+          pwminfo("pincfg: %08x\n", pincfg);
 
           stm32l4_configgpio(pincfg);
+          pwm_dumpgpio(pincfg, "PWM setup");
         }
+#endif
+    }
+
+  /* Configure PWM timer with the selected configuration.
+   *
+   * NOTE: We configure PWM here during setup, but leave timer with disabled
+   *       counter, disabled outputs, not configured frequency and duty cycle
+   */
 
-      pwm_dumpgpio(pincfg, "PWM setup");
+  ret = pwm_configure(dev);
+  if (ret < 0)
+    {
+      pwmerr("failed to configure PWM %d\n", priv->timid);
+      return ERROR;
     }
 
   return OK;
 }
 
 /****************************************************************************
- * Name: stm32l4pwm_shutdown
+ * Name: pwm_shutdown
  *
  * Description:
  *   This method is called when the driver is closed.  The lower half driver
@@ -2093,27 +3801,39 @@ static int stm32l4pwm_setup(FAR struct pwm_lowerhalf_s *dev)
  *
  ****************************************************************************/
 
-static int stm32l4pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
+static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
 {
   FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
-  uint32_t pincfg;
-  int i;
+  uint32_t pincfg = 0;
+  int      i      = 0;
+  int      ret    = OK;
 
-  pwminfo("TIM%u\n", priv->timid);
+  if (priv->timtype == TIMTYPE_LOWPOWER)
+    {
+      pwminfo("LPTIM%u\n", priv->timid);
+    }
+  else
+    {
+      pwminfo("TIM%u\n", priv->timid);
+    }
 
   /* Make sure that the output has been stopped */
 
-  stm32l4pwm_stop(dev);
+  pwm_stop(dev);
 
   /* Disable APB1/2 clocking for timer. */
 
-  stm32l4pwm_setapbclock(priv, false);
+  ret = stm32l4pwm_setapbclock(priv, false);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
   /* Then put the GPIO pins back to the default state */
 
-  for (i = 0; i < PWM_NCHANNELS; i++)
+  for (i = 0; i < priv->chan_num; i++)
     {
-      pincfg = priv->channels[i].pincfg;
+      pincfg = priv->channels[i].out1.pincfg;
       if (pincfg != 0)
         {
           pwminfo("pincfg: %08x\n", pincfg);
@@ -2124,23 +3844,26 @@ static int stm32l4pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
           stm32l4_configgpio(pincfg);
         }
 
-      pincfg = priv->channels[i].npincfg;
+#ifdef HAVE_PWM_COMPLEMENTARY
+      pincfg = priv->channels[i].out2.pincfg;
       if (pincfg != 0)
         {
-          pwminfo("npincfg: %08x\n", pincfg);
+          pwminfo("pincfg: %08x\n", pincfg);
 
           pincfg &= (GPIO_PORT_MASK | GPIO_PIN_MASK);
           pincfg |= GPIO_INPUT | GPIO_FLOAT;
 
           stm32l4_configgpio(pincfg);
         }
+#endif
     }
 
-  return OK;
+errout:
+  return ret;
 }
 
 /****************************************************************************
- * Name: stm32l4pwm_start
+ * Name: pwm_start
  *
  * Description:
  *   (Re-)initialize the timer resources and start the pulsed output
@@ -2155,7 +3878,7 @@ static int stm32l4pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
  ****************************************************************************/
 
 #ifdef CONFIG_PWM_PULSECOUNT
-static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
                      FAR const struct pwm_info_s *info,
                      FAR void *handle)
 {
@@ -2181,17 +3904,11 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
 
   /* Start the time */
 
-  if (priv->timtype == TIMTYPE_LOWPOWER)
-    {
-      return stm32l4pwm_lptimer(priv, info);
-    }
-  else
-    {
-      return stm32l4pwm_timer(priv, info);
-    }
+  return pwm_pulsecount_timer(dev, info);
 }
-#else
-static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
+#else /* !CONFIG_PWM_PULSECOUNT */
+
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
                      FAR const struct pwm_info_s *info)
 {
   int ret = OK;
@@ -2201,7 +3918,7 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
 
   if (info->frequency == priv->frequency)
     {
-#ifdef CONFIG_PWM_MULTICHAN
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
       int i;
 
       for (i = 0; ret == OK && i < CONFIG_PWM_NCHANNELS; i++)
@@ -2210,25 +3927,26 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
 
           if (info->channels[i].channel != 0)
             {
-              ret = stm32l4pwm_update_duty(priv, info->channels[i].channel,
-                                           info->channels[i].duty);
+              ret = pwm_duty_update(dev, info->channels[i].channel,
+                                    info->channels[i].duty);
             }
         }
-
 #else
-      ret = stm32l4pwm_update_duty(priv, priv->channels[0].channel, info->duty);
-#endif
+      ret = pwm_duty_update(dev, priv->channels[0].channel, info->duty);
+#endif /* CONFIG_STM32L4_PWM_MULTICHAN */
     }
   else
     {
-      if (priv->timtype == TIMTYPE_LOWPOWER)
+      if (priv->timtype != TIMTYPE_LOWPOWER)
         {
-          ret = stm32l4pwm_lptimer(priv, info);
+          ret = pwm_timer(dev, info);
         }
+#ifdef HAVE_LPTIM
       else
         {
-          ret = stm32l4pwm_timer(priv, info);
+          ret = pwm_lptimer(dev, info);
         }
+#endif
 
       /* Save current frequency */
 
@@ -2240,10 +3958,10 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
 
   return ret;
 }
-#endif
+#endif /* CONFIG_PWM_PULSECOUNT */
 
 /****************************************************************************
- * Name: stm32l4pwm_stop
+ * Name: pwm_stop
  *
  * Description:
  *   Stop the pulsed output and reset the timer resources
@@ -2261,7 +3979,7 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
  *
  ****************************************************************************/
 
-static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
+static int pwm_stop(FAR struct pwm_lowerhalf_s *dev)
 {
   FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
   uint32_t resetbit = 0;
@@ -2278,21 +3996,6 @@ static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
       pwminfo("TIM%u\n", priv->timid);
     }
 
-  /* Disable interrupts momentary to stop any ongoing timer processing and
-   * to prevent any concurrent access to the reset register.
-   */
-
-  flags = enter_critical_section();
-
-  /* Stopped so frequency is zero */
-
-  priv->frequency = 0;
-
-  /* Disable further interrupts and stop the timer */
-
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0);
-  stm32l4pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
-
   /* Determine which timer to reset */
 
   if (priv->timtype != TIMTYPE_LOWPOWER)
@@ -2367,11 +4070,30 @@ static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
             resetbit = RCC_APB1RSTR2_LPTIM2RST;
             break;
 #endif
+          default:
+            return -EINVAL;
         }
     }
 
+  /* Disable interrupts momentary to stop any ongoing timer processing and
+   * to prevent any concurrent access to the reset register.
+   */
+
+  flags = enter_critical_section();
+
+#ifndef CONFIG_PWM_PULSECOUNT
+  /* Stopped so frequency is zero */
+
+  priv->frequency = 0;
+#endif
+
+  /* Disable further interrupts and stop the timer */
+
+  pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0);
+  pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
+
   /* Reset the timer - stopping the output and putting the timer back
-   * into a state where stm32l4pwm_start() can be called.
+   * into a state where pwm_start() can be called.
    */
 
   regval  = getreg32(regaddr);
@@ -2383,12 +4105,12 @@ static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
   leave_critical_section(flags);
 
   pwminfo("regaddr: %08x resetbit: %08x\n", regaddr, resetbit);
-  stm32l4pwm_dumpregs(priv, "After stop");
+  pwm_dumpregs(dev, "After stop");
   return OK;
 }
 
 /****************************************************************************
- * Name: stm32l4pwm_ioctl
+ * Name: pwm_ioctl
  *
  * Description:
  *   Lower-half logic may support platform-specific ioctl commands
@@ -2403,8 +4125,8 @@ static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
  *
  ****************************************************************************/
 
-static int stm32l4pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd,
-                            unsigned long arg)
+static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd,
+                     unsigned long arg)
 {
 #ifdef CONFIG_DEBUG_PWM_INFO
   FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
@@ -2538,6 +4260,7 @@ FAR struct pwm_lowerhalf_s *stm32l4_pwminitialize(int timer)
  *
  ****************************************************************************/
 
+#ifdef HAVE_LPTIM
 FAR struct pwm_lowerhalf_s *stm32l4_lp_pwminitialize(int timer)
 {
   FAR struct stm32l4_pwmtimer_s *lower;
@@ -2565,5 +4288,6 @@ FAR struct pwm_lowerhalf_s *stm32l4_lp_pwminitialize(int timer)
 
   return (FAR struct pwm_lowerhalf_s *)lower;
 }
+#endif /* HAVE_LPTIM */
 
 #endif /* CONFIG_STM32L4_TIMn_PWM, n = 1,...,17 */
diff --git a/arch/arm/src/stm32l4/stm32l4_pwm.h b/arch/arm/src/stm32l4/stm32l4_pwm.h
index c7a639d..01832e2 100644
--- a/arch/arm/src/stm32l4/stm32l4_pwm.h
+++ b/arch/arm/src/stm32l4/stm32l4_pwm.h
@@ -1,4 +1,4 @@
-/************************************************************************************
+/****************************************************************************
  * arch/arm/src/stm32l4/stm32l4_pwm.h
  *
  *   Copyright (C) 2011, 2015 Gregory Nutt. All rights reserved.
@@ -33,36 +33,38 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ************************************************************************************/
+ ****************************************************************************/
 
 #ifndef __ARCH_ARM_SRC_STM32L4_STM32L4_PWM_H
 #define __ARCH_ARM_SRC_STM32L4_STM32L4_PWM_H
 
-/* The STM32L4 does not have dedicated PWM hardware.  Rather, pulsed output control
- * is a capability of the STM32L4 timers.  The logic in this file implements the
- * lower half of the standard, NuttX PWM interface using the STM32L4 timers.  That
- * interface is described in include/nuttx/timers/pwm.h.
+/* The STM32L4 does not have dedicated PWM hardware.  Rather, pulsed output
+ * control is a capability of the STM32L4 timers.  The logic in this file
+ * implements the lower half of the standard, NuttX PWM interface using the
+ * STM32L4 timers. That interface is described in include/nuttx/timers/pwm.h.
  */
 
-/************************************************************************************
+/****************************************************************************
  * Included Files
- ************************************************************************************/
+ ****************************************************************************/
 
 #include <nuttx/config.h>
 
+#include <nuttx/timers/pwm.h>
+
 #include "chip.h"
 
-/************************************************************************************
+/****************************************************************************
  * Pre-processor Definitions
- ************************************************************************************/
+ ****************************************************************************/
 
-/* Configuration ********************************************************************/
+/* Configuration ************************************************************/
 
 /* Timer devices may be used for different purposes.  One special purpose is
  * to generate modulated outputs for such things as motor control.  If
- * CONFIG_STM32L4_TIMn is defined then the CONFIG_STM32L4_TIMn_PWM must also be
- * defined to indicate that timer "n" is intended to be used for pulsed output
- * signal generation.
+ * CONFIG_STM32L4_TIMn is defined then the CONFIG_STM32L4_TIMn_PWM must also
+ * be defined to indicate that timer "n" is intended to be used for pulsed
+ * output signal generation.
  */
 
 #ifndef CONFIG_STM32L4_TIM1
@@ -99,7 +101,9 @@
 #  undef CONFIG_STM32L4_LPTIM2_PWM
 #endif
 
-/* The basic timers (timer 6 and 7) are not capable of generating output pulses */
+/* The basic timers (timer 6 and 7) are not capable of generating output
+ *  pulses.
+ */
 
 #undef CONFIG_STM32L4_TIM6_PWM
 #undef CONFIG_STM32L4_TIM7_PWM
@@ -117,7 +121,9 @@
 #include "hardware/stm32l4_tim.h"
 #include "hardware/stm32l4_lptim.h"
 
-#ifdef CONFIG_PWM_MULTICHAN
+/* PWM driver channels configuration */
+
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
 
 #ifdef CONFIG_STM32L4_TIM1_CHANNEL1
 #  ifdef CONFIG_STM32L4_TIM1_CH1OUT
@@ -502,33 +508,19 @@
 #endif
 #define PWM_LPTIM2_NCHANNELS PWM_LPTIM2_CHANNEL1
 
-#define PWM_MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define PWM_NCHANNELS PWM_MAX(PWM_TIM1_NCHANNELS, \
-                      PWM_MAX(PWM_TIM2_NCHANNELS, \
-                      PWM_MAX(PWM_TIM3_NCHANNELS, \
-                      PWM_MAX(PWM_TIM4_NCHANNELS, \
-                      PWM_MAX(PWM_TIM5_NCHANNELS, \
-                      PWM_MAX(PWM_TIM8_NCHANNELS, \
-                      PWM_MAX(PWM_TIM15_NCHANNELS, \
-                      PWM_MAX(PWM_TIM16_NCHANNELS, \
-                      PWM_MAX(PWM_TIM17_NCHANNELS, \
-                      PWM_MAX(PWM_LPTIM1_NCHANNELS, \
-                              PWM_LPTIM2_NCHANNELS))))))))))
-
-#else
+#else /* !CONFIG_STM32L4_PWM_MULTICHAN */
 
-/* For each timer that is enabled for PWM usage, we need the following additional
- * configuration settings:
+/* For each timer that is enabled for PWM usage, we need the following
+ * additional configuration settings:
  *
  * CONFIG_STM32L4_TIMx_CHANNEL - Specifies the timer output channel {1,..,4}
- * PWM_TIMx_CHn - One of the values defined in chip/stm32*_pinmap.h.  In the case
- *   where there are multiple pin selections, the correct setting must be provided
- *   in the arch/board/board.h file.
+ * PWM_TIMx_CHn - One of the values defined in chip/stm32*_pinmap.h.  In the
+ *   case where there are multiple pin selections, the correct setting must be
+ *   provided in the arch/board/board.h file.
  *
- * NOTE: The STM32L4 timers are each capable of generating different signals on
- * each of the four channels with different duty cycles.  That capability is
- * not supported by this driver:  Only one output channel per timer.
+ * NOTE: The STM32L4 timers are each capable of generating different signals
+ * on each of the four channels with different duty cycles.  That capability
+ * is not supported by this driver:  Only one output channel per timer.
  */
 
 #ifdef CONFIG_STM32L4_TIM1_PWM
@@ -537,25 +529,46 @@
 #  elif CONFIG_STM32L4_TIM1_CHANNEL == 1
 #    define CONFIG_STM32L4_TIM1_CHANNEL1 1
 #    define CONFIG_STM32L4_TIM1_CH1MODE  CONFIG_STM32L4_TIM1_CHMODE
-#    define PWM_TIM1_CH1CFG            GPIO_TIM1_CH1OUT
-#    define PWM_TIM1_CH1NCFG           0
+#    ifdef CONFIG_STM32L4_TIM1_CH1OUT
+#      define PWM_TIM1_CH1CFG            GPIO_TIM1_CH1OUT
+#    endif
+#    ifdef CONFIG_STM32L4_TIM1_CH1NOUT
+#      define PWM_TIM1_CH1NCFG           GPIO_TIM1_CH1NOUT
+#    else
+#      define PWM_TIM1_CH1NCFG           0
+#    endif
 #  elif CONFIG_STM32L4_TIM1_CHANNEL == 2
 #    define CONFIG_STM32L4_TIM1_CHANNEL2 1
 #    define CONFIG_STM32L4_TIM1_CH2MODE  CONFIG_STM32L4_TIM1_CHMODE
-#    define PWM_TIM1_CH2CFG            GPIO_TIM1_CH2OUT
-#    define PWM_TIM1_CH2NCFG           0
+#    ifdef CONFIG_STM32L4_TIM1_CH2OUT
+#      define PWM_TIM1_CH2CFG            GPIO_TIM1_CH2OUT
+#    endif
+#    ifdef CONFIG_STM32L4_TIM1_CH2NOUT
+#      define PWM_TIM1_CH2NCFG           GPIO_TIM1_CH2NOUT
+#    else
+#      define PWM_TIM1_CH2NCFG           0
+#    endif
 #  elif CONFIG_STM32L4_TIM1_CHANNEL == 3
 #    define CONFIG_STM32L4_TIM1_CHANNEL3 1
 #    define CONFIG_STM32L4_TIM1_CH3MODE  CONFIG_STM32L4_TIM1_CHMODE
-#    define PWM_TIM1_CH3CFG            GPIO_TIM1_CH3OUT
-#    define PWM_TIM1_CH3NCFG           0
+#    ifdef CONFIG_STM32L4_TIM1_CH3OUT
+#      define PWM_TIM1_CH3CFG            GPIO_TIM1_CH3OUT
+#    endif
+#    ifdef CONFIG_STM32L4_TIM1_CH3NOUT
+#      define PWM_TIM1_CH3NCFG           GPIO_TIM1_CH3NOUT
+#    else
+#      define PWM_TIM1_CH3NCFG           0
+#    endif
 #  elif CONFIG_STM32L4_TIM1_CHANNEL == 4
 #    define CONFIG_STM32L4_TIM1_CHANNEL4 1
 #    define CONFIG_STM32L4_TIM1_CH4MODE  CONFIG_STM32L4_TIM1_CHMODE
-#    define PWM_TIM1_CH4CFG            GPIO_TIM1_CH4OUT
+#    ifdef CONFIG_STM32L4_TIM1_CH4OUT
+#      define PWM_TIM1_CH4CFG            GPIO_TIM1_CH4OUT
+#    endif
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM1_CHANNEL"
 #  endif
+#  define PWM_TIM1_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_TIM2_PWM
@@ -580,6 +593,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM2_CHANNEL"
 #  endif
+#  define PWM_TIM2_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_TIM3_PWM
@@ -604,6 +618,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM3_CHANNEL"
 #  endif
+#  define PWM_TIM3_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_TIM4_PWM
@@ -628,6 +643,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM4_CHANNEL"
 #  endif
+#  define PWM_TIM4_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_TIM5_PWM
@@ -652,6 +668,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM5_CHANNEL"
 #  endif
+#  define PWM_TIM5_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_TIM8_PWM
@@ -679,6 +696,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM8_CHANNEL"
 #  endif
+#  define PWM_TIM8_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_TIM15_PWM
@@ -696,6 +714,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM15_CHANNEL"
 #  endif
+#  define PWM_TIM15_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_TIM16_PWM
@@ -709,6 +728,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM16_CHANNEL"
 #  endif
+#  define PWM_TIM16_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_TIM17_PWM
@@ -722,6 +742,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_TIM17_CHANNEL"
 #  endif
+#  define PWM_TIM17_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_LPTIM1_PWM
@@ -734,6 +755,7 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_LPTIM1_CHANNEL"
 #  endif
+#  define PWM_LPTIM1_NCHANNELS 1
 #endif
 
 #ifdef CONFIG_STM32L4_LPTIM2_PWM
@@ -746,19 +768,258 @@
 #  else
 #    error "Unsupported value of CONFIG_STM32L4_LPTIM2_CHANNEL"
 #  endif
+#  define PWM_LPTIM2_NCHANNELS 1
+#endif
+
+#endif
+
+/* Complementary outputs support */
+
+#if defined(CONFIG_STM32L4_TIM1_CH1NOUT) || defined(CONFIG_STM32L4_TIM1_CH2NOUT) || \
+    defined(CONFIG_STM32L4_TIM1_CH3NOUT)
+#  define HAVE_TIM1_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_TIM8_CH1NOUT) || defined(CONFIG_STM32L4_TIM8_CH2NOUT) || \
+    defined(CONFIG_STM32L4_TIM8_CH3NOUT)
+#  define HAVE_TIM8_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_TIM15_CH1NOUT)
+#  define HAVE_TIM15_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_TIM16_CH1NOUT)
+#  define HAVE_TIM16_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_TIM17_CH1NOUT)
+#  define HAVE_TIM17_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_LPTIM1_CH1NOUT)
+#  define HAVE_LPTIM1_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_LPTIM2_CH1NOUT)
+#  define HAVE_LPTIM2_COMPLEMENTARY
+#endif
+#if defined(HAVE_TIM1_COMPLEMENTARY) || defined(HAVE_TIM8_COMPLEMENTARY) ||   \
+    defined(HAVE_TIM15_COMPLEMENTARY) || defined(HAVE_TIM16_COMPLEMENTARY) || \
+    defined(HAVE_TIM17_COMPLEMENTARY) || defined(HAVE_LPTIM1_COMPLEMENTARY) || \
+    defined(HAVE_LPTIM2_COMPLEMENTARY)
+#  define HAVE_PWM_COMPLEMENTARY
 #endif
 
-#define PWM_NCHANNELS 1
+/* Low-level ops helpers ************************************************************/
 
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+
+/* NOTE: low-level ops accept pwm_lowerhalf_s as first argument, but llops
+ *       access can be found in stm32l4_pwm_dev_s
+ */
+
+#define PWM_SETUP(dev)                                                             \
+        (dev)->ops->setup((FAR struct pwm_lowerhalf_s *)dev)
+#define PWM_SHUTDOWN(dev)                                                          \
+        (dev)->ops->shutdown((FAR struct pwm_lowerhalf_s *)dev)
+#define PWM_CCR_UPDATE(dev, index, ccr)                                            \
+        (dev)->llops->ccr_update((FAR struct pwm_lowerhalf_s *)dev, index, ccr)
+#define PWM_MODE_UPDATE(dev, index, mode)                                          \
+        (dev)->llops->mode_update((FAR struct pwm_lowerhalf_s *)dev, index, mode)
+#define PWM_CCR_GET(dev, index)                                                    \
+        (dev)->llops->ccr_get((FAR struct pwm_lowerhalf_s *)dev, index)
+#define PWM_ARR_UPDATE(dev, arr)                                                   \
+        (dev)->llops->arr_update((FAR struct pwm_lowerhalf_s *)dev, arr)
+#define PWM_ARR_GET(dev)                                                           \
+        (dev)->llops->arr_get((FAR struct pwm_lowerhalf_s *)dev)
+#define PWM_OUTPUTS_ENABLE(dev, out, state)                                        \
+        (dev)->llops->outputs_enable((FAR struct pwm_lowerhalf_s *)dev, out, state)
+#define PWM_SOFT_UPDATE(dev)                                                       \
+        (dev)->llops->soft_update((FAR struct pwm_lowerhalf_s *)dev)
+#define PWM_CONFIGURE(dev)                                                         \
+        (dev)->llops->configure((FAR struct pwm_lowerhalf_s *)dev)
+#define PWM_SOFT_BREAK(dev, state)                                                 \
+        (dev)->llops->soft_break((FAR struct pwm_lowerhalf_s *)dev, state)
+#define PWM_FREQ_UPDATE(dev, freq)                                                 \
+        (dev)->llops->freq_update((FAR struct pwm_lowerhalf_s *)dev, freq)
+#define PWM_TIM_ENABLE(dev, state)                                                 \
+        (dev)->llops->tim_enable((FAR struct pwm_lowerhalf_s *)dev, state)
+#ifdef CONFIG_DEBUG_STM32L4_PWM_INFO
+#  define PWM_DUMP_REGS(dev, msg)                                                  \
+        (dev)->llops->dump_regs((FAR struct pwm_lowerhalf_s *)dev, msg)
+#else
+#  define PWM_DUMP_REGS(dev, msg)
+#endif
+#define PWM_DT_UPDATE(dev, dt)                                                     \
+        (dev)->llops->dt_update((FAR struct pwm_lowerhalf_s *)dev, dt)
 #endif
 
-/************************************************************************************
+/****************************************************************************
  * Public Types
- ************************************************************************************/
+ ****************************************************************************/
+
+/* Timer mode */
+
+enum stm32l4_timmode_e
+{
+  STM32L4_TIMMODE_COUNTUP   = 0,
+  STM32L4_TIMMODE_COUNTDOWN = 1,
+  STM32L4_TIMMODE_CENTER1   = 2,
+  STM32L4_TIMMODE_CENTER2   = 3,
+  STM32L4_TIMMODE_CENTER3   = 4,
+};
+
+/* Timer output polarity */
+
+enum stm32l4_pwm_pol_e
+{
+  STM32L4_POL_POS  = 0,
+  STM32L4_POL_NEG  = 1,
+};
+
+/* Timer output IDLE state */
+
+enum stm32l4_pwm_idle_e
+{
+  STM32L4_IDLE_INACTIVE = 0,
+  STM32L4_IDLE_ACTIVE   = 1
+};
+
+/* PWM channel mode */
+
+enum stm32l4_chanmode_e
+{
+  STM32L4_CHANMODE_FRZN        = 0,  /* CCRx matches has no effects on outputs */
+  STM32L4_CHANMODE_CHACT       = 1,  /* OCxREF active on match */
+  STM32L4_CHANMODE_CHINACT     = 2,  /* OCxREF inactive on match */
+  STM32L4_CHANMODE_OCREFTOG    = 3,  /* OCxREF toggles when TIMy_CNT=TIMyCCRx */
+  STM32L4_CHANMODE_OCREFLO     = 4,  /* OCxREF is forced low */
+  STM32L4_CHANMODE_OCREFHI     = 5,  /* OCxREF is forced high */
+  STM32L4_CHANMODE_PWM1        = 6,  /* PWM mode 1 */
+  STM32L4_CHANMODE_PWM2        = 7,  /* PWM mode 2 */
+  STM32L4_CHANMODE_COMBINED1   = 8,  /* Combined PWM mode 1 */
+  STM32L4_CHANMODE_COMBINED2   = 9,  /* Combined PWM mode 2 */
+  STM32L4_CHANMODE_ASYMMETRIC1 = 10, /* Asymmetric PWM mode 1 */
+  STM32L4_CHANMODE_ASYMMETRIC2 = 11, /* Asymmetric PWM mode 2 */
+};
+
+/* PWM timer channel */
+
+enum stm32l4_pwm_chan_e
+{
+  STM32L4_PWM_CHAN1  = 1,
+  STM32L4_PWM_CHAN2  = 2,
+  STM32L4_PWM_CHAN3  = 3,
+  STM32L4_PWM_CHAN4  = 4,
+  STM32L4_PWM_CHAN5  = 5,
+  STM32L4_PWM_CHAN6  = 6,
+};
+
+/* PWM timer channel output */
 
-/************************************************************************************
+enum stm32l4_pwm_output_e
+{
+  STM32L4_PWM_OUT1  = (1 << 0),
+  STM32L4_PWM_OUT1N = (1 << 1),
+  STM32L4_PWM_OUT2  = (1 << 2),
+  STM32L4_PWM_OUT2N = (1 << 3),
+  STM32L4_PWM_OUT3  = (1 << 4),
+  STM32L4_PWM_OUT3N = (1 << 5),
+  STM32L4_PWM_OUT4  = (1 << 6),
+  /* 1 << 7 reserved - no complementary output for CH4 */
+  /* Only available inside micro */
+  STM32L4_PWM_OUT5  = (1 << 8),
+  /* 1 << 9 reserved - no complementary output for CH5 */
+  STM32L4_PWM_OUT6  = (1 << 10),
+  /* 1 << 11 reserved - no complementary output for CH6 */
+};
+
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+
+/* This structure provides the publicly visable representation of the
+ * "lower-half" PWM driver structure.
+ */
+
+struct stm32l4_pwm_dev_s
+{
+  /* The first field of this state structure must be a pointer to the PWM
+   * callback structure to be consistent with upper-half PWM driver.
+   */
+
+  FAR const struct pwm_ops_s *ops;
+
+  /* Publicly visible portion of the "lower-half" PWM driver structure */
+
+  FAR const struct stm32l4_pwm_ops_s *llops;
+
+  /* Require cast-compatibility with private "lower-half" PWM strucutre */
+};
+
+/* Low-level operations for PWM */
+
+struct pwm_lowerhalf_s;
+struct stm32l4_pwm_ops_s
+{
+  /* Update CCR register */
+
+  int (*ccr_update)(FAR struct pwm_lowerhalf_s *dev,
+                    uint8_t index, uint32_t ccr);
+
+  /* Update PWM mode */
+
+  int (*mode_update)(FAR struct pwm_lowerhalf_s *dev,
+                     uint8_t index, uint32_t mode);
+
+  /* Get CCR register */
+
+  uint32_t (*ccr_get)(FAR struct pwm_lowerhalf_s *dev, uint8_t index);
+
+  /* Update ARR register */
+
+  int (*arr_update)(FAR struct pwm_lowerhalf_s *dev, uint32_t arr);
+
+  /* Get ARR register */
+
+  uint32_t (*arr_get)(FAR struct pwm_lowerhalf_s *dev);
+
+  /* Enable outputs */
+
+  int (*outputs_enable)(FAR struct pwm_lowerhalf_s *dev,
+                        uint16_t outputs, bool state);
+
+  /* Software update */
+
+  int (*soft_update)(FAR struct pwm_lowerhalf_s *dev);
+
+  /* PWM configure */
+
+  int (*configure)(FAR struct pwm_lowerhalf_s *dev);
+
+  /* Software break */
+
+  int (*soft_break)(FAR struct pwm_lowerhalf_s *dev, bool state);
+
+  /* Update frequency */
+
+  int (*freq_update)(FAR struct pwm_lowerhalf_s *dev, uint32_t frequency);
+
+  /* Enable timer counter */
+
+  int (*tim_enable)(FAR struct pwm_lowerhalf_s *dev, bool state);
+
+#ifdef CONFIG_DEBUG_PWM_INFO
+  /* Dump timer registers */
+
+  void (*dump_regs)(FAR struct pwm_lowerhalf_s *dev, FAR const char *msg);
+#endif
+
+#ifdef HAVE_PWM_COMPLEMENTARY
+  /* Deadtime update */
+
+  int (*dt_update)(FAR struct pwm_lowerhalf_s *dev, uint8_t dt);
+#endif
+};
+
+#endif  /* CONFIG_STM32L4_PWM_LL_OPS */
+
+/****************************************************************************
  * Public Data
- ************************************************************************************/
+ ****************************************************************************/
 
 #ifndef __ASSEMBLY__
 
@@ -771,11 +1032,11 @@ extern "C"
 #define EXTERN extern
 #endif
 
-/************************************************************************************
+/****************************************************************************
  * Public Functions
- ************************************************************************************/
+ ****************************************************************************/
 
-/************************************************************************************
+/****************************************************************************
  * Name: stm32l4_pwminitialize
  *
  * Description:
@@ -790,7 +1051,7 @@ extern "C"
  *   On success, a pointer to the STM32 lower half PWM driver is returned.
  *   NULL is returned on any failure.
  *
- ************************************************************************************/
+ ****************************************************************************/
 
 FAR struct pwm_lowerhalf_s *stm32l4_pwminitialize(int timer);
 
diff --git a/boards/arm/stm32l4/nucleo-l432kc/Kconfig b/boards/arm/stm32l4/nucleo-l432kc/Kconfig
index f913f96..353f988 100644
--- a/boards/arm/stm32l4/nucleo-l432kc/Kconfig
+++ b/boards/arm/stm32l4/nucleo-l432kc/Kconfig
@@ -107,4 +107,38 @@ endchoice
 
 endmenu
 
+menuconfig NUCLEOL432KC_SPWM
+	bool "Sinusoidal PWM generator example"
+	default n
+
+if NUCLEOL432KC_SPWM
+
+choice
+	prompt "Sinusoidal PWM source"
+	default NUCLEOL432KC_SPWM_USE_TIM1
+
+config NUCLEOL432KC_SPWM_USE_TIM1
+	bool "Use TIM1 as PWM source"
+
+endchoice
+
+config NUCLEOL432KC_SPWM_PWM_FREQ
+	int "PWM frequency in Hz"
+	default 100000
+
+config NUCLEOL432KC_SPWM_SAMPLES
+	int "Sine samples"
+	default 100
+
+config NUCLEOL432KC_SPWM_FREQ
+	int "Waveform frequency in Hz"
+	default 60
+
+config NUCLEOL432KC_SPWM_PHASE_NUM
+	int "Number of phases"
+	default 1
+	range 1 4 if NUCLEOL432KC_SPWM_USE_TIM1
+
+endif
+
 endif # ARCH_BOARD_NUCLEO_L432KC
diff --git a/boards/arm/stm32l4/nucleo-l432kc/README.txt b/boards/arm/stm32l4/nucleo-l432kc/README.txt
index 5f19b4e..aac5e14 100644
--- a/boards/arm/stm32l4/nucleo-l432kc/README.txt
+++ b/boards/arm/stm32l4/nucleo-l432kc/README.txt
@@ -535,3 +535,14 @@ Configurations
        Pin 33 PA10 USART1_TX    some RS-232 converters
        Pin 20 GND
        Pin 8  U5V
+
+  spwm
+  ----
+
+    Configures the sinusoidal PWM (SPWM) example which presents a simple use case
+    of the STM32L4 PWM lower-half driver without generic upper-half PWM logic.
+
+    It uses TIM1 to generate PWM and TIM6 to change waveform samples
+
+    At the moment, the waveform parameters are hardcoded, but it should be easy to
+    modify this example and make it more functional.
\ No newline at end of file
diff --git a/boards/arm/stm32l4/nucleo-l432kc/configs/spwm/defconfig b/boards/arm/stm32l4/nucleo-l432kc/configs/spwm/defconfig
new file mode 100755
index 0000000..6c2ce2b
--- /dev/null
+++ b/boards/arm/stm32l4/nucleo-l432kc/configs/spwm/defconfig
@@ -0,0 +1,1360 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Nuttx/ Configuration
+#
+
+#
+# Build Setup
+#
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_DEFAULT_SMALL is not set
+CONFIG_HOST_LINUX=y
+# CONFIG_HOST_MACOS is not set
+# CONFIG_HOST_WINDOWS is not set
+# CONFIG_HOST_OTHER is not set
+
+#
+# Build Configuration
+#
+CONFIG_APPS_DIR="../apps"
+CONFIG_BUILD_FLAT=y
+# CONFIG_BUILD_2PASS is not set
+
+#
+# Binary Output Formats
+#
+# CONFIG_CXD56_BINARY is not set
+CONFIG_INTELHEX_BINARY=y
+# CONFIG_MOTOROLA_SREC is not set
+CONFIG_RAW_BINARY=y
+# CONFIG_UBOOT_UIMAGE is not set
+# CONFIG_DFU_BINARY is not set
+
+#
+# Customize Header Files
+#
+# CONFIG_ARCH_HAVE_STDINT_H is not set
+# CONFIG_ARCH_HAVE_STDBOOL_H is not set
+# CONFIG_ARCH_HAVE_MATH_H is not set
+CONFIG_ARCH_FLOAT_H=y
+CONFIG_ARCH_HAVE_STDARG_H=y
+# CONFIG_ARCH_STDARG_H is not set
+CONFIG_ARCH_HAVE_SETJMP=y
+# CONFIG_ARCH_SETJMP_H is not set
+# CONFIG_ARCH_DEBUG_H is not set
+
+#
+# Debug Options
+#
+CONFIG_DEBUG_ALERT=y
+# CONFIG_DEBUG_FEATURES is not set
+CONFIG_ARCH_HAVE_STACKCHECK=y
+# CONFIG_STACK_COLORATION is not set
+CONFIG_ARCH_HAVE_HEAPCHECK=y
+# CONFIG_HEAP_COLORATION is not set
+# CONFIG_DEBUG_SYMBOLS is not set
+CONFIG_ARCH_HAVE_CUSTOMOPT=y
+CONFIG_DEBUG_NOOPT=y
+# CONFIG_DEBUG_CUSTOMOPT is not set
+# CONFIG_DEBUG_FULLOPT is not set
+
+#
+# System Type
+#
+CONFIG_ARCH_ARM=y
+# CONFIG_ARCH_AVR is not set
+# CONFIG_ARCH_HC is not set
+# CONFIG_ARCH_MIPS is not set
+# CONFIG_ARCH_MISOC is not set
+# CONFIG_ARCH_RENESAS is not set
+# CONFIG_ARCH_RISCV is not set
+# CONFIG_ARCH_SIM is not set
+# CONFIG_ARCH_X86 is not set
+# CONFIG_ARCH_XTENSA is not set
+# CONFIG_ARCH_Z16 is not set
+# CONFIG_ARCH_Z80 is not set
+# CONFIG_ARCH_OR1K is not set
+CONFIG_ARCH="arm"
+
+#
+# ARM Options
+#
+# CONFIG_ARCH_CHIP_A1X is not set
+# CONFIG_ARCH_CHIP_AM335X is not set
+# CONFIG_ARCH_CHIP_C5471 is not set
+# CONFIG_ARCH_CHIP_DM320 is not set
+# CONFIG_ARCH_CHIP_EFM32 is not set
+# CONFIG_ARCH_CHIP_IMX1 is not set
+# CONFIG_ARCH_CHIP_IMX6 is not set
+# CONFIG_ARCH_CHIP_IMXRT is not set
+# CONFIG_ARCH_CHIP_KINETIS is not set
+# CONFIG_ARCH_CHIP_KL is not set
+# CONFIG_ARCH_CHIP_LC823450 is not set
+# CONFIG_ARCH_CHIP_LM is not set
+# CONFIG_ARCH_CHIP_LPC17XX_40XX is not set
+# CONFIG_ARCH_CHIP_LPC214X is not set
+# CONFIG_ARCH_CHIP_LPC2378 is not set
+# CONFIG_ARCH_CHIP_LPC31XX is not set
+# CONFIG_ARCH_CHIP_LPC43XX is not set
+# CONFIG_ARCH_CHIP_LPC54XX is not set
+# CONFIG_ARCH_CHIP_MAX326XX is not set
+# CONFIG_ARCH_CHIP_MOXART is not set
+# CONFIG_ARCH_CHIP_NRF52 is not set
+# CONFIG_ARCH_CHIP_NUC1XX is not set
+# CONFIG_ARCH_CHIP_S32K1XX is not set
+# CONFIG_ARCH_CHIP_SAMA5 is not set
+# CONFIG_ARCH_CHIP_SAMD2X is not set
+# CONFIG_ARCH_CHIP_SAML2X is not set
+# CONFIG_ARCH_CHIP_SAMD5X is not set
+# CONFIG_ARCH_CHIP_SAME5X is not set
+# CONFIG_ARCH_CHIP_SAM34 is not set
+# CONFIG_ARCH_CHIP_SAMV7 is not set
+# CONFIG_ARCH_CHIP_STM32 is not set
+# CONFIG_ARCH_CHIP_STM32F0 is not set
+# CONFIG_ARCH_CHIP_STM32L0 is not set
+# CONFIG_ARCH_CHIP_STM32G0 is not set
+# CONFIG_ARCH_CHIP_STM32F7 is not set
+# CONFIG_ARCH_CHIP_STM32H7 is not set
+CONFIG_ARCH_CHIP_STM32L4=y
+# CONFIG_ARCH_CHIP_STR71X is not set
+# CONFIG_ARCH_CHIP_TMS570 is not set
+# CONFIG_ARCH_CHIP_TIVA is not set
+# CONFIG_ARCH_CHIP_XMC4 is not set
+# CONFIG_ARCH_CHIP_CXD56XX is not set
+# CONFIG_ARCH_ARM7TDMI is not set
+# CONFIG_ARCH_ARM920T is not set
+# CONFIG_ARCH_ARM926EJS is not set
+# CONFIG_ARCH_ARM1136J is not set
+# CONFIG_ARCH_ARM1156T2 is not set
+# CONFIG_ARCH_ARM1176JZ is not set
+# CONFIG_ARCH_CORTEXM0 is not set
+# CONFIG_ARCH_CORTEXM23 is not set
+CONFIG_ARCH_ARMV7M=y
+# CONFIG_ARCH_CORTEXM3 is not set
+# CONFIG_ARCH_CORTEXM33 is not set
+CONFIG_ARCH_CORTEXM4=y
+# CONFIG_ARCH_CORTEXM7 is not set
+# CONFIG_ARCH_ARMV7A is not set
+# CONFIG_ARCH_CORTEXA5 is not set
+# CONFIG_ARCH_CORTEXA7 is not set
+# CONFIG_ARCH_CORTEXA8 is not set
+# CONFIG_ARCH_CORTEXA9 is not set
+# CONFIG_ARCH_ARMV7R is not set
+# CONFIG_ARCH_CORTEXR4 is not set
+# CONFIG_ARCH_CORTEXR5 is not set
+# CONFIG_ARCH_CORTEXR7 is not set
+CONFIG_ARCH_FAMILY="armv7-m"
+CONFIG_ARCH_CHIP="stm32l4"
+# CONFIG_ARCH_HAVE_TRUSTZONE is not set
+CONFIG_ARM_HAVE_MPU_UNIFIED=y
+# CONFIG_ARM_MPU is not set
+CONFIG_ARCH_HAVE_HARDFAULT_DEBUG=y
+# CONFIG_DEBUG_HARDFAULT_ALERT is not set
+CONFIG_ARCH_HAVE_MEMFAULT_DEBUG=y
+# CONFIG_ARM_SEMIHOSTING_SYSLOG is not set
+
+#
+# ARMV7M Configuration Options
+#
+# CONFIG_ARMV7M_HAVE_ICACHE is not set
+# CONFIG_ARMV7M_HAVE_DCACHE is not set
+# CONFIG_ARMV7M_LAZYFPU is not set
+CONFIG_ARMV7M_USEBASEPRI=y
+# CONFIG_ARMV7M_HAVE_ITCM is not set
+# CONFIG_ARMV7M_HAVE_DTCM is not set
+# CONFIG_ARMV7M_TOOLCHAIN_IARL is not set
+# CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set
+# CONFIG_ARMV7M_TOOLCHAIN_CODEREDL is not set
+CONFIG_ARMV7M_TOOLCHAIN_CODESOURCERYL=y
+# CONFIG_ARMV7M_TOOLCHAIN_GNU_EABIL is not set
+# CONFIG_ARMV7M_TOOLCHAIN_CLANGL is not set
+CONFIG_ARMV7M_HAVE_STACKCHECK=y
+# CONFIG_ARMV7M_STACKCHECK is not set
+# CONFIG_ARMV7M_ITMSYSLOG is not set
+# CONFIG_USART2_RS485 is not set
+# CONFIG_USART2_RXDMA is not set
+# CONFIG_USART2_TXDMA is not set
+
+#
+# STM32L4 Configuration Options
+#
+# CONFIG_ARCH_CHIP_STM32L412KB is not set
+# CONFIG_ARCH_CHIP_STM32L432KB is not set
+CONFIG_ARCH_CHIP_STM32L432KC=y
+# CONFIG_ARCH_CHIP_STM32L433CB is not set
+# CONFIG_ARCH_CHIP_STM32L433CC is not set
+# CONFIG_ARCH_CHIP_STM32L433RB is not set
+# CONFIG_ARCH_CHIP_STM32L433RC is not set
+# CONFIG_ARCH_CHIP_STM32L433VC is not set
+# CONFIG_ARCH_CHIP_STM32L442KC is not set
+# CONFIG_ARCH_CHIP_STM32L443CC is not set
+# CONFIG_ARCH_CHIP_STM32L443RC is not set
+# CONFIG_ARCH_CHIP_STM32L443VC is not set
+# CONFIG_ARCH_CHIP_STM32L451CC is not set
+# CONFIG_ARCH_CHIP_STM32L451CE is not set
+# CONFIG_ARCH_CHIP_STM32L451RC is not set
+# CONFIG_ARCH_CHIP_STM32L451RE is not set
+# CONFIG_ARCH_CHIP_STM32L451VC is not set
+# CONFIG_ARCH_CHIP_STM32L451VE is not set
+# CONFIG_ARCH_CHIP_STM32L452CC is not set
+# CONFIG_ARCH_CHIP_STM32L452CE is not set
+# CONFIG_ARCH_CHIP_STM32L452RC is not set
+# CONFIG_ARCH_CHIP_STM32L452RE is not set
+# CONFIG_ARCH_CHIP_STM32L452VC is not set
+# CONFIG_ARCH_CHIP_STM32L452VE is not set
+# CONFIG_ARCH_CHIP_STM32L462CE is not set
+# CONFIG_ARCH_CHIP_STM32L462RE is not set
+# CONFIG_ARCH_CHIP_STM32L462VE is not set
+# CONFIG_ARCH_CHIP_STM32L475RG is not set
+# CONFIG_ARCH_CHIP_STM32L475RE is not set
+# CONFIG_ARCH_CHIP_STM32L475RC is not set
+# CONFIG_ARCH_CHIP_STM32L475VG is not set
+# CONFIG_ARCH_CHIP_STM32L475VE is not set
+# CONFIG_ARCH_CHIP_STM32L475VC is not set
+# CONFIG_ARCH_CHIP_STM32L476RG is not set
+# CONFIG_ARCH_CHIP_STM32L476RE is not set
+# CONFIG_ARCH_CHIP_STM32L486RG is not set
+# CONFIG_ARCH_CHIP_STM32L486JG is not set
+# CONFIG_ARCH_CHIP_STM32L486VG is not set
+# CONFIG_ARCH_CHIP_STM32L486QG is not set
+# CONFIG_ARCH_CHIP_STM32L486ZG is not set
+# CONFIG_ARCH_CHIP_STM32L496RE is not set
+# CONFIG_ARCH_CHIP_STM32L496RG is not set
+# CONFIG_ARCH_CHIP_STM32L496VE is not set
+# CONFIG_ARCH_CHIP_STM32L496VG is not set
+# CONFIG_ARCH_CHIP_STM32L496ZE is not set
+# CONFIG_ARCH_CHIP_STM32L496ZG is not set
+# CONFIG_ARCH_CHIP_STM32L496AG is not set
+# CONFIG_ARCH_CHIP_STM32L4A6RG is not set
+# CONFIG_ARCH_CHIP_STM32L4A6VG is not set
+# CONFIG_ARCH_CHIP_STM32L4A6QG is not set
+# CONFIG_ARCH_CHIP_STM32L4A6ZG is not set
+# CONFIG_ARCH_CHIP_STM32L4A6AG is not set
+# CONFIG_ARCH_CHIP_STM32L4R5ZI is not set
+# CONFIG_ARCH_CHIP_STM32L4R9AI is not set
+# CONFIG_STM32L4_STM32L4X1 is not set
+CONFIG_STM32L4_STM32L4X2=y
+CONFIG_STM32L4_STM32L4X3=y
+# CONFIG_STM32L4_STM32L4X5 is not set
+# CONFIG_STM32L4_STM32L4X6 is not set
+# CONFIG_STM32L4_STM32L4XR is not set
+# CONFIG_STM32L4_STM32L412XX is not set
+# CONFIG_STM32L4_STM32L422XX is not set
+# CONFIG_STM32L4_STM32L431XX is not set
+CONFIG_STM32L4_STM32L432XX=y
+# CONFIG_STM32L4_STM32L433XX is not set
+# CONFIG_STM32L4_STM32L442XX is not set
+# CONFIG_STM32L4_STM32L443XX is not set
+# CONFIG_STM32L4_STM32L451XX is not set
+# CONFIG_STM32L4_STM32L452XX is not set
+# CONFIG_STM32L4_STM32L462XX is not set
+# CONFIG_STM32L4_STM32L471XX is not set
+# CONFIG_STM32L4_STM32L475XX is not set
+# CONFIG_STM32L4_STM32L476XX is not set
+# CONFIG_STM32L4_STM32L486XX is not set
+# CONFIG_STM32L4_STM32L496XX is not set
+# CONFIG_STM32L4_STM32L4A6XX is not set
+# CONFIG_STM32L4_STM32L4R5XX is not set
+# CONFIG_STM32L4_STM32L4S5XX is not set
+# CONFIG_STM32L4_STM32L4R7XX is not set
+# CONFIG_STM32L4_STM32L4S7XX is not set
+# CONFIG_STM32L4_STM32L4R9XX is not set
+# CONFIG_STM32L4_STM32L4S9XX is not set
+CONFIG_STM32L4_FLASH_OVERRIDE_DEFAULT=y
+# CONFIG_STM32L4_FLASH_OVERRIDE_8 is not set
+# CONFIG_STM32L4_FLASH_OVERRIDE_B is not set
+# CONFIG_STM32L4_FLASH_OVERRIDE_C is not set
+# CONFIG_STM32L4_FLASH_OVERRIDE_E is not set
+# CONFIG_STM32L4_FLASH_OVERRIDE_G is not set
+# CONFIG_STM32L4_FLASH_OVERRIDE_I is not set
+# CONFIG_STM32L4_FLASH_CONFIG_B is not set
+CONFIG_STM32L4_FLASH_CONFIG_C=y
+# CONFIG_STM32L4_FLASH_CONFIG_E is not set
+CONFIG_STM32L4_IO_CONFIG_K=y
+# CONFIG_STM32L4_IO_CONFIG_T is not set
+# CONFIG_STM32L4_IO_CONFIG_C is not set
+# CONFIG_STM32L4_IO_CONFIG_R is not set
+# CONFIG_STM32L4_IO_CONFIG_J is not set
+# CONFIG_STM32L4_IO_CONFIG_M is not set
+# CONFIG_STM32L4_IO_CONFIG_V is not set
+# CONFIG_STM32L4_IO_CONFIG_Q is not set
+# CONFIG_STM32L4_IO_CONFIG_Z is not set
+# CONFIG_STM32L4_IO_CONFIG_A is not set
+
+#
+# STM32L4 SRAM2 and SRAM3 Options
+#
+CONFIG_STM32L4_SRAM2_HEAP=y
+CONFIG_STM32L4_SRAM2_INIT=y
+
+#
+# STM32L4 Peripherals
+#
+
+#
+# STM32L4 Peripheral Support
+#
+# CONFIG_STM32L4_HAVE_ADC2 is not set
+# CONFIG_STM32L4_HAVE_ADC3 is not set
+# CONFIG_STM32L4_HAVE_AES is not set
+# CONFIG_STM32L4_HAVE_CAN2 is not set
+CONFIG_STM32L4_HAVE_COMP=y
+CONFIG_STM32L4_HAVE_DAC2=y
+# CONFIG_STM32L4_HAVE_DCMI is not set
+# CONFIG_STM32L4_HAVE_DFSDM1 is not set
+# CONFIG_STM32L4_HAVE_DMA2D is not set
+# CONFIG_STM32L4_HAVE_DMAMUX is not set
+# CONFIG_STM32L4_HAVE_FSMC is not set
+# CONFIG_STM32L4_HAVE_HASH is not set
+CONFIG_STM32L4_HAVE_HSI48=y
+# CONFIG_STM32L4_HAVE_I2C4 is not set
+# CONFIG_STM32L4_HAVE_LCD is not set
+# CONFIG_STM32L4_HAVE_LTDC is not set
+CONFIG_STM32L4_HAVE_LPTIM1=y
+CONFIG_STM32L4_HAVE_LPTIM2=y
+# CONFIG_STM32L4_HAVE_OTGFS is not set
+CONFIG_STM32L4_HAVE_USBFS=y
+CONFIG_STM32L4_HAVE_SAI1=y
+# CONFIG_STM32L4_HAVE_SAI2 is not set
+# CONFIG_STM32L4_RTC is not set
+# CONFIG_STM32L4_HAVE_SDMMC1 is not set
+# CONFIG_STM32L4_HAVE_TIM3 is not set
+# CONFIG_STM32L4_HAVE_TIM4 is not set
+# CONFIG_STM32L4_HAVE_TIM5 is not set
+CONFIG_STM32L4_HAVE_TIM7=y
+# CONFIG_STM32L4_HAVE_TIM8 is not set
+# CONFIG_STM32L4_HAVE_TIM17 is not set
+CONFIG_STM32L4_HAVE_USART1=y
+CONFIG_STM32L4_HAVE_USART2=y
+# CONFIG_STM32L4_HAVE_USART3 is not set
+# CONFIG_STM32L4_HAVE_UART4 is not set
+# CONFIG_STM32L4_HAVE_UART5 is not set
+# CONFIG_STM32L4_HAVE_QSPI is not set
+# CONFIG_STM32L4_ADC is not set
+# CONFIG_STM32L4_CAN is not set
+# CONFIG_STM32L4_DAC is not set
+# CONFIG_STM32L4_DFSDM is not set
+CONFIG_STM32L4_DMA=y
+# CONFIG_STM32L4_I2C is not set
+# CONFIG_STM32L4_SAI is not set
+# CONFIG_STM32L4_SPI is not set
+CONFIG_STM32L4_USART=y
+# CONFIG_STM32L4_LPTIM is not set
+# CONFIG_STM32L4_SDMMC is not set
+
+#
+# AHB1 Peripherals
+#
+CONFIG_STM32L4_DMA1=y
+CONFIG_STM32L4_DMA2=y
+# CONFIG_STM32L4_CRC is not set
+# CONFIG_STM32L4_TSC is not set
+
+#
+# AHB2 Peripherals
+#
+# CONFIG_STM32L4_ADC1 is not set
+# CONFIG_STM32L4_RNG is not set
+
+#
+# AHB3 Peripherals
+#
+
+#
+# APB1 Peripherals
+#
+# CONFIG_STM32L4_PWR is not set
+# CONFIG_STM32L4_TIM2 is not set
+CONFIG_STM32L4_TIM6=y
+# CONFIG_STM32L4_TIM7 is not set
+# CONFIG_STM32L4_SPI3 is not set
+CONFIG_STM32L4_USART2=y
+# CONFIG_STM32L4_I2C1 is not set
+# CONFIG_STM32L4_I2C3 is not set
+# CONFIG_STM32L4_CAN1 is not set
+# CONFIG_STM32L4_DAC1 is not set
+# CONFIG_STM32L4_DAC2 is not set
+# CONFIG_STM32L4_OPAMP is not set
+# CONFIG_STM32L4_LPTIM1 is not set
+# CONFIG_STM32L4_LPUART1 is not set
+# CONFIG_STM32L4_SWPMI is not set
+# CONFIG_STM32L4_LPTIM2 is not set
+# CONFIG_STM32L4_USBFS is not set
+
+#
+# APB2 Peripherals
+#
+# CONFIG_STM32L4_SYSCFG is not set
+CONFIG_STM32L4_TIM1=y
+# CONFIG_STM32L4_SPI1 is not set
+# CONFIG_STM32L4_USART1 is not set
+# CONFIG_STM32L4_TIM15 is not set
+# CONFIG_STM32L4_TIM16 is not set
+# CONFIG_STM32L4_COMP is not set
+# CONFIG_STM32L4_SAI1 is not set
+
+#
+# Other Peripherals
+#
+# CONFIG_STM32L4_BKPSRAM is not set
+# CONFIG_STM32L4_IWDG is not set
+# CONFIG_STM32L4_WWDG is not set
+# CONFIG_STM32L4_SAI1PLL is not set
+CONFIG_STM32L4_FLASH_PREFETCH=y
+CONFIG_STM32L4_DISABLE_IDLE_SLEEP_DURING_DEBUG=y
+# CONFIG_ARCH_BOARD_STM32L4_CUSTOM_CLOCKCONFIG is not set
+CONFIG_STM32L4_HAVE_RTC_SUBSECONDS=y
+
+#
+# Timer Configuration
+#
+# CONFIG_STM32L4_ONESHOT is not set
+# CONFIG_STM32L4_FREERUN is not set
+CONFIG_STM32L4_PWM_LL_OPS=y
+CONFIG_STM32L4_TIM1_PWM=y
+CONFIG_STM32L4_TIM1_MODE=0
+CONFIG_STM32L4_TIM1_LOCK=0
+CONFIG_STM32L4_TIM1_TDTS=0
+CONFIG_STM32L4_TIM1_DEADTIME=0
+CONFIG_STM32L4_TIM1_CH1OUT=y
+CONFIG_STM32L4_TIM1_CH1NOUT=y
+CONFIG_STM32L4_TIM1_CHANNEL=1
+CONFIG_STM32L4_TIM1_CHMODE=6
+# CONFIG_STM32L4_PWM_MULTICHAN is not set
+
+#
+# STM32L4 TIMx Outputs Configuration
+#
+CONFIG_STM32L4_TIM1_CH1POL=0
+CONFIG_STM32L4_TIM1_CH1IDLE=0
+CONFIG_STM32L4_TIM1_CH1NPOL=0
+CONFIG_STM32L4_TIM1_CH1NIDLE=0
+CONFIG_STM32L4_SERIALDRIVER=y
+
+#
+# U[S]ART Configuration
+#
+CONFIG_STM32L4_USART2_SERIALDRIVER=y
+# CONFIG_STM32L4_USART2_1WIREDRIVER is not set
+
+#
+# Serial Driver Configuration
+#
+# CONFIG_STM32L4_SERIAL_DISABLE_REORDERING is not set
+# CONFIG_STM32L4_FLOWCONTROL_BROKEN is not set
+# CONFIG_STM32L4_USART_BREAKS is not set
+# CONFIG_STM32L4_USART_SINGLEWIRE is not set
+# CONFIG_STM32L4_USART_INVERT is not set
+# CONFIG_STM32L4_USART_SWAP is not set
+# CONFIG_ARCH_TOOLCHAIN_IAR is not set
+CONFIG_ARCH_TOOLCHAIN_GNU=y
+# CONFIG_ARCH_GNU_NO_WEAKFUNCTIONS is not set
+
+#
+# Architecture Options
+#
+# CONFIG_ARCH_NOINTC is not set
+# CONFIG_ARCH_VECNOTIRQ is not set
+CONFIG_ARCH_HAVE_IRQTRIGGER=y
+CONFIG_ARCH_DMA=y
+CONFIG_ARCH_HAVE_IRQPRIO=y
+# CONFIG_ARCH_ICACHE is not set
+# CONFIG_ARCH_DCACHE is not set
+# CONFIG_ARCH_L2CACHE is not set
+# CONFIG_ARCH_HAVE_ADDRENV is not set
+# CONFIG_ARCH_NEED_ADDRENV_MAPPING is not set
+# CONFIG_ARCH_HAVE_MULTICPU is not set
+CONFIG_ARCH_HAVE_VFORK=y
+CONFIG_ARCH_HAVE_FPU=y
+# CONFIG_ARCH_HAVE_DPFPU is not set
+CONFIG_ARCH_HAVE_LAZYFPU=y
+# CONFIG_ARCH_HAVE_MMU is not set
+CONFIG_ARCH_HAVE_MPU=y
+# CONFIG_ARCH_NAND_HWECC is not set
+# CONFIG_ARCH_HAVE_EXTCLK is not set
+# CONFIG_ARCH_HAVE_POWEROFF is not set
+CONFIG_ARCH_HAVE_PROGMEM=y
+CONFIG_ARCH_HAVE_RESET=y
+CONFIG_ARCH_HAVE_TESTSET=y
+CONFIG_ARCH_HAVE_FETCHADD=y
+CONFIG_ARCH_HAVE_RTC_SUBSECONDS=y
+# CONFIG_ARCH_HAVE_GARBAGE is not set
+# CONFIG_ARCH_GLOBAL_IRQDISABLE is not set
+CONFIG_ARCH_FPU=y
+# CONFIG_ARCH_USE_MPU is not set
+CONFIG_ARCH_IRQPRIO=y
+CONFIG_ARCH_STACKDUMP=y
+# CONFIG_ENDIAN_BIG is not set
+# CONFIG_ARCH_IDLE_CUSTOM is not set
+# CONFIG_ARCH_HAVE_RAMFUNCS is not set
+CONFIG_ARCH_HAVE_RAMVECTORS=y
+CONFIG_ARCH_RAMVECTORS=y
+# CONFIG_ARCH_MINIMAL_VECTORTABLE is not set
+
+#
+# Board Settings
+#
+CONFIG_BOARD_LOOPSPERMSEC=8499
+
+#
+# Interrupt options
+#
+CONFIG_ARCH_HAVE_INTERRUPTSTACK=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_HAVE_HIPRI_INTERRUPT=y
+CONFIG_ARCH_HIPRI_INTERRUPT=y
+
+#
+# Boot options
+#
+# CONFIG_BOOT_RUNFROMEXTSRAM is not set
+CONFIG_BOOT_RUNFROMFLASH=y
+# CONFIG_BOOT_RUNFROMISRAM is not set
+# CONFIG_BOOT_RUNFROMSDRAM is not set
+# CONFIG_BOOT_COPYTORAM is not set
+
+#
+# Boot Memory Configuration
+#
+CONFIG_RAM_START=0x20000000
+CONFIG_RAM_SIZE=65536
+# CONFIG_ARCH_HAVE_SDRAM is not set
+
+#
+# Board Selection
+#
+CONFIG_ARCH_BOARD_NUCLEO_L432KC=y
+# CONFIG_ARCH_BOARD_CUSTOM is not set
+CONFIG_ARCH_BOARD="nucleo-l432kc"
+
+#
+# Common Board Options
+#
+CONFIG_ARCH_HAVE_LEDS=y
+CONFIG_ARCH_LEDS=y
+CONFIG_ARCH_HAVE_BUTTONS=y
+# CONFIG_ARCH_BUTTONS is not set
+CONFIG_ARCH_HAVE_IRQBUTTONS=y
+
+#
+# Board-Specific Options
+#
+
+#
+# U[S]ART Pin Layouts
+#
+
+#
+# USART1 is disabled. (Enable it under: System Type -> STM32L4 Peripheral Support)
+#
+# CONFIG_ARCH_BOARD_USART2_RX_PA3 is not set
+CONFIG_ARCH_BOARD_USART2_RX_PA15=y
+CONFIG_ARCH_BOARD_USART2_TX_PA2=y
+
+#
+# LPUART1 is disabled. (Enable it under: System Type -> STM32L4 Peripheral Support)
+#
+CONFIG_NUCLEOL432KC_SPWM=y
+CONFIG_NUCLEOL432KC_SPWM_USE_TIM1=y
+CONFIG_NUCLEOL432KC_SPWM_PWM_FREQ=200000
+CONFIG_NUCLEOL432KC_SPWM_SAMPLES=100
+CONFIG_NUCLEOL432KC_SPWM_FREQ=60
+CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM=1
+# CONFIG_BOARD_CRASHDUMP is not set
+CONFIG_LIB_BOARDCTL=y
+# CONFIG_BOARDCTL_FINALINIT is not set
+# CONFIG_BOARDCTL_RESET is not set
+# CONFIG_BOARDCTL_UNIQUEID is not set
+CONFIG_BOARDCTL_MKRD=y
+# CONFIG_BOARDCTL_ROMDISK is not set
+# CONFIG_BOARDCTL_APP_SYMTAB is not set
+# CONFIG_BOARDCTL_TESTSET is not set
+# CONFIG_BOARDCTL_IOCTL is not set
+
+#
+# RTOS Features
+#
+CONFIG_DISABLE_OS_API=y
+# CONFIG_DISABLE_POSIX_TIMERS is not set
+# CONFIG_DISABLE_PTHREAD is not set
+# CONFIG_DISABLE_MQUEUE is not set
+# CONFIG_DISABLE_ENVIRON is not set
+
+#
+# Clocks and Timers
+#
+CONFIG_ARCH_HAVE_TICKLESS=y
+# CONFIG_SCHED_TICKLESS is not set
+CONFIG_USEC_PER_TICK=10000
+# CONFIG_SYSTEMTICK_HOOK is not set
+# CONFIG_SYSTEM_TIME64 is not set
+# CONFIG_CLOCK_MONOTONIC is not set
+# CONFIG_ARCH_HAVE_TIMEKEEPING is not set
+# CONFIG_JULIAN_TIME is not set
+CONFIG_START_YEAR=2018
+CONFIG_START_MONTH=1
+CONFIG_START_DAY=1
+CONFIG_MAX_WDOGPARMS=2
+CONFIG_PREALLOC_WDOGS=8
+CONFIG_WDOG_INTRESERVE=1
+CONFIG_PREALLOC_TIMERS=4
+
+#
+# Tasks and Scheduling
+#
+# CONFIG_SPINLOCK is not set
+# CONFIG_IRQCHAIN is not set
+# CONFIG_IRQCOUNT is not set
+# CONFIG_INIT_NONE is not set
+CONFIG_INIT_ENTRYPOINT=y
+# CONFIG_INIT_FILEPATH is not set
+CONFIG_USER_ENTRYPOINT="spwm_main"
+CONFIG_USERMAIN_PRIORITY=100
+CONFIG_RR_INTERVAL=200
+# CONFIG_SCHED_SPORADIC is not set
+CONFIG_TASK_NAME_SIZE=0
+CONFIG_MAX_TASKS=16
+# CONFIG_SCHED_HAVE_PARENT is not set
+CONFIG_SCHED_WAITPID=y
+# CONFIG_SCHED_USER_IDENTITY is not set
+
+#
+# Pthread Options
+#
+CONFIG_NPTHREAD_KEYS=4
+# CONFIG_PTHREAD_MUTEX_TYPES is not set
+CONFIG_PTHREAD_MUTEX_ROBUST=y
+# CONFIG_PTHREAD_MUTEX_UNSAFE is not set
+# CONFIG_PTHREAD_MUTEX_BOTH is not set
+# CONFIG_PTHREAD_CLEANUP is not set
+# CONFIG_CANCELLATION_POINTS is not set
+
+#
+# Performance Monitoring
+#
+# CONFIG_SCHED_SUSPENDSCHEDULER is not set
+# CONFIG_SCHED_RESUMESCHEDULER is not set
+# CONFIG_SCHED_CPULOAD is not set
+# CONFIG_SCHED_INSTRUMENTATION is not set
+
+#
+# Files and I/O
+#
+CONFIG_DEV_CONSOLE=y
+# CONFIG_FDCLONE_DISABLE is not set
+# CONFIG_FDCLONE_STDIO is not set
+CONFIG_SDCLONE_DISABLE=y
+CONFIG_NFILE_DESCRIPTORS=8
+CONFIG_NFILE_STREAMS=8
+CONFIG_NAME_MAX=32
+# CONFIG_PRIORITY_INHERITANCE is not set
+
+#
+# RTOS hooks
+#
+# CONFIG_BOARD_EARLY_INITIALIZE is not set
+# CONFIG_BOARD_LATE_INITIALIZE is not set
+# CONFIG_SCHED_STARTHOOK is not set
+# CONFIG_SCHED_ATEXIT is not set
+# CONFIG_SCHED_ONEXIT is not set
+
+#
+# Signal Configuration
+#
+# CONFIG_SIG_DEFAULT is not set
+
+#
+# Signal Numbers
+#
+
+#
+# Standard Signal Numbers
+#
+CONFIG_SIG_SIGUSR1=1
+CONFIG_SIG_SIGUSR2=2
+CONFIG_SIG_SIGALRM=3
+CONFIG_SIG_PIPE=11
+
+#
+# Non-standard Signal Numbers
+#
+CONFIG_SIG_SIGCONDTIMEDOUT=16
+
+#
+# POSIX Message Queue Options
+#
+CONFIG_PREALLOC_MQ_MSGS=4
+CONFIG_MQ_MAXMSGSIZE=32
+# CONFIG_MODULE is not set
+
+#
+# Work queue support
+#
+# CONFIG_SCHED_WORKQUEUE is not set
+# CONFIG_SCHED_HPWORK is not set
+# CONFIG_SCHED_LPWORK is not set
+
+#
+# Stack and heap information
+#
+CONFIG_IDLETHREAD_STACKSIZE=1024
+CONFIG_USERMAIN_STACKSIZE=2048
+CONFIG_PTHREAD_STACK_MIN=256
+CONFIG_PTHREAD_STACK_DEFAULT=2048
+# CONFIG_LIB_SYSCALL is not set
+
+#
+# Device Drivers
+#
+# CONFIG_DEV_SIMPLE_ADDRENV is not set
+CONFIG_DEV_NULL=y
+# CONFIG_DEV_ZERO is not set
+# CONFIG_DEV_URANDOM is not set
+# CONFIG_DEV_LOOP is not set
+CONFIG_DRVR_MKRD=y
+
+#
+# Buffering
+#
+# CONFIG_DRVR_WRITEBUFFER is not set
+# CONFIG_DRVR_READAHEAD is not set
+# CONFIG_RAMDISK is not set
+# CONFIG_CAN is not set
+CONFIG_ARCH_HAVE_PWM_PULSECOUNT=y
+# CONFIG_ARCH_HAVE_PWM_MULTICHAN is not set
+CONFIG_ARCH_HAVE_I2CRESET=y
+# CONFIG_I2C is not set
+# CONFIG_ARCH_HAVE_SPI_CRCGENERATION is not set
+# CONFIG_ARCH_HAVE_SPI_CS_CONTROL is not set
+CONFIG_ARCH_HAVE_SPI_BITORDER=y
+CONFIG_SPI=y
+# CONFIG_SPI_SLAVE is not set
+CONFIG_SPI_EXCHANGE=y
+# CONFIG_SPI_CMDDATA is not set
+# CONFIG_SPI_CALLBACK is not set
+# CONFIG_SPI_HWFEATURES is not set
+# CONFIG_SPI_BITORDER is not set
+# CONFIG_SPI_CS_DELAY_CONTROL is not set
+# CONFIG_SPI_TRIGGER is not set
+# CONFIG_SPI_DRIVER is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_I2S is not set
+
+#
+# Timer Driver Support
+#
+CONFIG_PWM=y
+# CONFIG_PWM_PULSECOUNT is not set
+# CONFIG_TIMER is not set
+# CONFIG_ONESHOT is not set
+# CONFIG_RTC is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_ANALOG is not set
+# CONFIG_DRIVERS_AUDIO is not set
+# CONFIG_FB_CMAP is not set
+# CONFIG_FB_TRANSPARENCY is not set
+# CONFIG_DRIVERS_VIDEO is not set
+# CONFIG_BCH is not set
+# CONFIG_INPUT is not set
+
+#
+# IO Expander/GPIO Support
+#
+# CONFIG_IOEXPANDER is not set
+# CONFIG_DEV_GPIO is not set
+
+#
+# LCD Driver Support
+#
+# CONFIG_LCD is not set
+
+#
+# Character/Segment LCD Devices
+#
+# CONFIG_SLCD is not set
+
+#
+# Other LCD-related Devices
+#
+# CONFIG_LCD_OTHER is not set
+
+#
+# LED Support
+#
+# CONFIG_USERLED is not set
+# CONFIG_LEDS_APA102 is not set
+# CONFIG_LEDS_MAX7219 is not set
+# CONFIG_RGBLED is not set
+# CONFIG_PCA9635PW is not set
+# CONFIG_NCP5623C is not set
+# CONFIG_ARCH_HAVE_SDIO is not set
+# CONFIG_ARCH_HAVE_SDIOWAIT_WRCOMPLETE is not set
+# CONFIG_ARCH_HAVE_SDIO_PREFLIGHT is not set
+# CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT is not set
+# CONFIG_MMCSD is not set
+# CONFIG_MODEM is not set
+# CONFIG_MTD is not set
+# CONFIG_EEPROM is not set
+# CONFIG_PIPES is not set
+# CONFIG_PM is not set
+# CONFIG_DRIVERS_POWERLED is not set
+# CONFIG_DRIVERS_SMPS is not set
+# CONFIG_DRIVERS_MOTOR is not set
+# CONFIG_POWER is not set
+# CONFIG_SENSORS is not set
+CONFIG_SERIAL=y
+# CONFIG_DEV_LOWCONSOLE is not set
+# CONFIG_SERIAL_REMOVABLE is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_16550_UART is not set
+# CONFIG_OTHER_UART_SERIALDRIVER is not set
+CONFIG_MCU_SERIAL=y
+CONFIG_STANDARD_SERIAL=y
+CONFIG_SERIAL_NPOLLWAITERS=2
+# CONFIG_SERIAL_IFLOWCONTROL is not set
+# CONFIG_SERIAL_RS485CONTROL is not set
+# CONFIG_SERIAL_OFLOWCONTROL is not set
+# CONFIG_SERIAL_TXDMA is not set
+# CONFIG_SERIAL_RXDMA is not set
+CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y
+# CONFIG_SERIAL_TERMIOS is not set
+CONFIG_USART2_SERIAL_CONSOLE=y
+# CONFIG_OTHER_SERIAL_CONSOLE is not set
+# CONFIG_NO_SERIAL_CONSOLE is not set
+# CONFIG_UART_SERIALDRIVER is not set
+# CONFIG_UART0_SERIALDRIVER is not set
+# CONFIG_UART1_SERIALDRIVER is not set
+# CONFIG_UART2_SERIALDRIVER is not set
+# CONFIG_UART3_SERIALDRIVER is not set
+# CONFIG_UART4_SERIALDRIVER is not set
+# CONFIG_UART5_SERIALDRIVER is not set
+# CONFIG_UART6_SERIALDRIVER is not set
+# CONFIG_UART7_SERIALDRIVER is not set
+# CONFIG_UART8_SERIALDRIVER is not set
+# CONFIG_LPUART_SERIALDRIVER is not set
+# CONFIG_LPUART0_SERIALDRIVER is not set
+# CONFIG_LPUART1_SERIALDRIVER is not set
+# CONFIG_LPUART2_SERIALDRIVER is not set
+# CONFIG_LPUART3_SERIALDRIVER is not set
+# CONFIG_LPUART4_SERIALDRIVER is not set
+# CONFIG_LPUART5_SERIALDRIVER is not set
+# CONFIG_LPUART6_SERIALDRIVER is not set
+# CONFIG_LPUART7_SERIALDRIVER is not set
+# CONFIG_LPUART8_SERIALDRIVER is not set
+# CONFIG_USART0_SERIALDRIVER is not set
+# CONFIG_USART1_SERIALDRIVER is not set
+CONFIG_USART2_SERIALDRIVER=y
+# CONFIG_USART3_SERIALDRIVER is not set
+# CONFIG_USART4_SERIALDRIVER is not set
+# CONFIG_USART5_SERIALDRIVER is not set
+# CONFIG_USART6_SERIALDRIVER is not set
+# CONFIG_USART7_SERIALDRIVER is not set
+# CONFIG_USART8_SERIALDRIVER is not set
+# CONFIG_USART9_SERIALDRIVER is not set
+
+#
+# USART2 Configuration
+#
+CONFIG_USART2_RXBUFSIZE=256
+CONFIG_USART2_TXBUFSIZE=256
+CONFIG_USART2_BAUD=115200
+CONFIG_USART2_BITS=8
+CONFIG_USART2_PARITY=0
+CONFIG_USART2_2STOP=0
+# CONFIG_USART2_IFLOWCONTROL is not set
+# CONFIG_USART2_OFLOWCONTROL is not set
+# CONFIG_SCI0_SERIALDRIVER is not set
+# CONFIG_SCI1_SERIALDRIVER is not set
+# CONFIG_SCI2_SERIALDRIVER is not set
+# CONFIG_SCI3_SERIALDRIVER is not set
+# CONFIG_SCI4_SERIALDRIVER is not set
+# CONFIG_SCI5_SERIALDRIVER is not set
+# CONFIG_SCI6_SERIALDRIVER is not set
+# CONFIG_SCI7_SERIALDRIVER is not set
+# CONFIG_SCI8_SERIALDRIVER is not set
+# CONFIG_SCI9_SERIALDRIVER is not set
+# CONFIG_SCI10_SERIALDRIVER is not set
+# CONFIG_SCI11_SERIALDRIVER is not set
+# CONFIG_SCI12_SERIALDRIVER is not set
+# CONFIG_PSEUDOTERM is not set
+# CONFIG_USBDEV is not set
+# CONFIG_USBHOST is not set
+# CONFIG_USBMISC is not set
+# CONFIG_HAVE_USBTRACE is not set
+# CONFIG_DRIVERS_WIRELESS is not set
+# CONFIG_DRIVERS_CONTACTLESS is not set
+# CONFIG_1WIRE is not set
+
+#
+# System Logging
+#
+# CONFIG_ARCH_SYSLOG is not set
+CONFIG_SYSLOG_WRITE=y
+# CONFIG_RAMLOG is not set
+# CONFIG_SYSLOG_BUFFER is not set
+# CONFIG_SYSLOG_INTBUFFER is not set
+# CONFIG_SYSLOG_TIMESTAMP is not set
+# CONFIG_SYSLOG_PREFIX is not set
+CONFIG_SYSLOG_SERIAL_CONSOLE=y
+# CONFIG_SYSLOG_CHAR is not set
+CONFIG_SYSLOG_CONSOLE=y
+# CONFIG_SYSLOG_NONE is not set
+# CONFIG_SYSLOG_FILE is not set
+# CONFIG_SYSLOG_CHARDEV is not set
+# CONFIG_SPECIFIC_DRIVERS is not set
+# CONFIG_DRIVERS_RF is not set
+
+#
+# Networking Support
+#
+# CONFIG_ARCH_HAVE_NET is not set
+# CONFIG_ARCH_HAVE_PHY is not set
+# CONFIG_NET_WRITE_BUFFERS is not set
+# CONFIG_NET_READAHEAD is not set
+# CONFIG_NET_MCASTGROUP is not set
+# CONFIG_NET is not set
+
+#
+# Crypto API
+#
+# CONFIG_CRYPTO is not set
+
+#
+# File Systems
+#
+
+#
+# File system configuration
+#
+# CONFIG_DISABLE_MOUNTPOINT is not set
+# CONFIG_FS_AUTOMOUNTER is not set
+# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set
+# CONFIG_PSEUDOFS_SOFTLINKS is not set
+CONFIG_FS_READABLE=y
+CONFIG_FS_WRITABLE=y
+# CONFIG_FS_NAMED_SEMAPHORES is not set
+CONFIG_FS_MQUEUE_MPATH="/var/mqueue"
+# CONFIG_FS_RAMMAP is not set
+
+#
+# Partition Table
+#
+# CONFIG_PTABLE_PARTITION is not set
+# CONFIG_FS_FAT is not set
+# CONFIG_FS_NXFFS is not set
+# CONFIG_FS_ROMFS is not set
+# CONFIG_FS_CROMFS is not set
+# CONFIG_FS_TMPFS is not set
+# CONFIG_FS_SMARTFS is not set
+# CONFIG_FS_BINFS is not set
+# CONFIG_FS_PROCFS is not set
+# CONFIG_FS_SPIFFS is not set
+# CONFIG_FS_LITTLEFS is not set
+# CONFIG_FS_UNIONFS is not set
+# CONFIG_FS_HOSTFS is not set
+
+#
+# Graphics Support
+#
+# CONFIG_NX is not set
+# CONFIG_NXFONTS is not set
+
+#
+# Font Cache Pixel Depths
+#
+# CONFIG_NXFONTS_DISABLE_1BPP is not set
+# CONFIG_NXFONTS_DISABLE_2BPP is not set
+# CONFIG_NXFONTS_DISABLE_4BPP is not set
+# CONFIG_NXFONTS_DISABLE_8BPP is not set
+# CONFIG_NXFONTS_DISABLE_16BPP is not set
+# CONFIG_NXFONTS_DISABLE_24BPP is not set
+# CONFIG_NXFONTS_DISABLE_32BPP is not set
+CONFIG_NXFONTS_PACKEDMSFIRST=y
+# CONFIG_NXGLIB is not set
+
+#
+# Memory Management
+#
+# CONFIG_MM_SMALL is not set
+CONFIG_MM_REGIONS=2
+# CONFIG_ARCH_HAVE_HEAP2 is not set
+# CONFIG_GRAN is not set
+# CONFIG_MM_FILL_ALLOCATIONS is not set
+
+#
+# Common I/O Buffer Support
+#
+# CONFIG_MM_IOB is not set
+
+#
+# Audio Support
+#
+# CONFIG_AUDIO is not set
+
+#
+# Video Support
+#
+
+#
+# Video subsystem
+#
+# CONFIG_VIDEO is not set
+
+#
+# Wireless Support
+#
+# CONFIG_WIRELESS is not set
+
+#
+# Binary Loader
+#
+# CONFIG_BINFMT_DISABLE is not set
+# CONFIG_BINFMT_LOADABLE is not set
+# CONFIG_PIC is not set
+# CONFIG_NXFLAT is not set
+# CONFIG_ELF is not set
+# CONFIG_SYMTAB_ORDEREDBYNAME is not set
+
+#
+# Library Routines
+#
+
+#
+# Standard C Library Options
+#
+
+#
+# Standard C I/O
+#
+# CONFIG_STDIO_DISABLE_BUFFERING is not set
+CONFIG_STDIO_BUFFER_SIZE=64
+CONFIG_STDIO_LINEBUFFER=y
+CONFIG_NUNGET_CHARS=2
+# CONFIG_LIBC_PRINT_LEGACY is not set
+# CONFIG_LIBC_FLOATINGPOINT is not set
+CONFIG_LIBC_LONG_LONG=y
+# CONFIG_LIBC_NUMBERED_ARGS is not set
+# CONFIG_LIBC_SCANSET is not set
+# CONFIG_EOL_IS_CR is not set
+# CONFIG_EOL_IS_LF is not set
+# CONFIG_EOL_IS_BOTH_CRLF is not set
+CONFIG_EOL_IS_EITHER_CRLF=y
+# CONFIG_MEMCPY_VIK is not set
+CONFIG_LIBM=y
+
+#
+# Architecture-Specific Support
+#
+CONFIG_ARCH_LOWPUTC=y
+# CONFIG_ARCH_ROMGETC is not set
+# CONFIG_LIBC_ARCH_MEMCPY is not set
+# CONFIG_LIBC_ARCH_MEMCMP is not set
+# CONFIG_LIBC_ARCH_MEMMOVE is not set
+# CONFIG_LIBC_ARCH_MEMSET is not set
+# CONFIG_LIBC_ARCH_STRCHR is not set
+# CONFIG_LIBC_ARCH_STRCMP is not set
+# CONFIG_LIBC_ARCH_STRCPY is not set
+# CONFIG_LIBC_ARCH_STRNCPY is not set
+# CONFIG_LIBC_ARCH_STRLEN is not set
+# CONFIG_LIBC_ARCH_STRNLEN is not set
+# CONFIG_LIBC_ARCH_ELF is not set
+# CONFIG_ARMV7M_MEMCPY is not set
+# CONFIG_ARMV7M_LIBM is not set
+# CONFIG_MACHINE_OPTS_ARMV7M is not set
+# CONFIG_LIBM_ARCH_FABSF is not set
+# CONFIG_LIBM_ARCH_SQRTF is not set
+
+#
+# stdlib Options
+#
+CONFIG_LIB_RAND_ORDER=1
+CONFIG_LIB_HOMEDIR="/"
+CONFIG_LIBC_TMPDIR="/tmp"
+CONFIG_LIBC_MAX_TMPFILE=32
+
+#
+# Program Execution Options
+#
+# CONFIG_LIBC_EXECFUNCS is not set
+CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=1024
+CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=2048
+CONFIG_LIB_HOSTNAME=""
+
+#
+# errno Decode Support
+#
+# CONFIG_LIBC_STRERROR is not set
+# CONFIG_LIBC_PERROR_STDOUT is not set
+
+#
+# memcpy/memset Options
+#
+# CONFIG_MEMSET_OPTSPEED is not set
+
+#
+# pthread support
+#
+# CONFIG_LIBC_DLFCN is not set
+# CONFIG_LIBC_MODLIB is not set
+# CONFIG_LIBC_GROUP_FILE is not set
+# CONFIG_LIBC_PASSWD_FILE is not set
+# CONFIG_LIBC_WCHAR is not set
+# CONFIG_LIBC_LOCALE is not set
+# CONFIG_LIBC_LZF is not set
+
+#
+# Time/Time Zone Support
+#
+# CONFIG_LIBC_LOCALTIME is not set
+# CONFIG_TIME_EXTENDED is not set
+CONFIG_ARCH_HAVE_TLS=y
+
+#
+# Thread Local Storage (TLS)
+#
+# CONFIG_TLS is not set
+
+#
+# Network-Related Options
+#
+# CONFIG_LIBC_IPv4_ADDRCONV is not set
+# CONFIG_LIBC_IPv6_ADDRCONV is not set
+# CONFIG_LIBC_NETDB is not set
+
+#
+# NETDB Support
+#
+# CONFIG_LIBC_GAISTRERROR is not set
+# CONFIG_NETDB_HOSTFILE is not set
+# CONFIG_LIBC_IOCTL_VARIADIC is not set
+CONFIG_LIB_SENDFILE_BUFSIZE=512
+
+#
+# Non-standard Library Support
+#
+# CONFIG_LIB_CRC64_FAST is not set
+# CONFIG_LIB_KBDCODEC is not set
+# CONFIG_LIB_SLCDCODEC is not set
+# CONFIG_LIB_ENVPATH is not set
+# CONFIG_LIB_HEX2BIN is not set
+CONFIG_BUILTIN=y
+
+#
+# Basic CXX Support
+#
+# CONFIG_C99_BOOL8 is not set
+CONFIG_HAVE_CXX=y
+# CONFIG_CXX_NEWLONG is not set
+
+#
+# LLVM C++ Library (libcxx)
+#
+# CONFIG_LIBCXX is not set
+
+#
+# uClibc++ Standard C++ Library
+#
+# CONFIG_UCLIBCXX is not set
+# CONFIG_LIBDSP is not set
+
+#
+# Open Asymmetric Multi Processing
+#
+# CONFIG_OPENAMP is not set
+
+#
+# Application Configuration
+#
+
+#
+# Built-In Applications
+#
+CONFIG_BUILTIN_PROXY_STACKSIZE=1024
+
+#
+# CAN Utilities
+#
+
+#
+# Examples
+#
+# CONFIG_EXAMPLES_ABNTCODI is not set
+# CONFIG_EXAMPLES_ADXL372_TEST is not set
+# CONFIG_EXAMPLES_APA102 is not set
+# CONFIG_EXAMPLES_AUDIO_SOUND is not set
+# CONFIG_EXAMPLES_BATTERY is not set
+# CONFIG_EXAMPLES_SIXAXIS is not set
+# CONFIG_EXAMPLES_BUTTONS is not set
+# CONFIG_EXAMPLES_CALIB_UDELAY is not set
+# CONFIG_EXAMPLES_CCTYPE is not set
+# CONFIG_EXAMPLES_CHARGER is not set
+# CONFIG_EXAMPLES_CHAT is not set
+# CONFIG_EXAMPLES_CHRONO is not set
+# CONFIG_EXAMPLES_CONFIGDATA is not set
+# CONFIG_EXAMPLES_DHCPD is not set
+# CONFIG_EXAMPLES_DHTXX is not set
+# CONFIG_EXAMPLES_DSPTEST is not set
+# CONFIG_EXAMPLES_FTPC is not set
+# CONFIG_EXAMPLES_FTPD is not set
+# CONFIG_EXAMPLES_GPS is not set
+# CONFIG_EXAMPLES_HELLO is not set
+# CONFIG_EXAMPLES_HELLOXX is not set
+# CONFIG_EXAMPLES_HIDKBD is not set
+# CONFIG_EXAMPLES_IGMP is not set
+# CONFIG_EXAMPLES_INA219 is not set
+# CONFIG_EXAMPLES_INA226 is not set
+# CONFIG_EXAMPLES_LSM330SPI_TEST is not set
+# CONFIG_EXAMPLES_LVGLDEMO is not set
+# CONFIG_EXAMPLES_MAX31855 is not set
+# CONFIG_EXAMPLES_MEDIA is not set
+# CONFIG_EXAMPLES_MLX90614 is not set
+# CONFIG_EXAMPLES_MM is not set
+# CONFIG_EXAMPLES_MODBUS is not set
+# CONFIG_EXAMPLES_MODBUSMASTER is not set
+# CONFIG_EXAMPLES_MOUNT is not set
+# CONFIG_EXAMPLES_NULL is not set
+# CONFIG_EXAMPLES_NXDEMO is not set
+# CONFIG_EXAMPLES_OBD2 is not set
+# CONFIG_EXAMPLES_PCA9635 is not set
+# CONFIG_EXAMPLES_PDCURSES is not set
+# CONFIG_EXAMPLES_POSIXSPAWN is not set
+# CONFIG_EXAMPLES_POWERLED is not set
+# CONFIG_EXAMPLES_POWERMONITOR is not set
+# CONFIG_EXAMPLES_PPPD is not set
+# CONFIG_EXAMPLES_PWM is not set
+# CONFIG_EXAMPLES_RFID_READUID is not set
+# CONFIG_EXAMPLES_RGBLED is not set
+# CONFIG_EXAMPLES_SENDMAIL is not set
+# CONFIG_EXAMPLES_SERIALBLASTER is not set
+# CONFIG_EXAMPLES_SERIALRX is not set
+# CONFIG_EXAMPLES_SERLOOP is not set
+# CONFIG_EXAMPLES_SLCD is not set
+# CONFIG_EXAMPLES_SMPS is not set
+# CONFIG_EXAMPLES_STAT is not set
+# CONFIG_EXAMPLES_TCPECHO is not set
+# CONFIG_EXAMPLES_TIFF is not set
+# CONFIG_EXAMPLES_TOUCHSCREEN is not set
+# CONFIG_EXAMPLES_UID is not set
+# CONFIG_EXAMPLES_USBSERIAL is not set
+# CONFIG_EXAMPLES_USERFS is not set
+# CONFIG_EXAMPLES_WATCHDOG is not set
+# CONFIG_EXAMPLES_WEBSERVER is not set
+# CONFIG_EXAMPLES_XBC_TEST is not set
+
+#
+# File System Utilities
+#
+# CONFIG_FSUTILS_INIFILE is not set
+# CONFIG_FSUTILS_INIH is not set
+# CONFIG_FSUTILS_PASSWD is not set
+
+#
+# GPS Utilities
+#
+# CONFIG_GPSUTILS_MINMEA_LIB is not set
+
+#
+# Graphics Support
+#
+# CONFIG_GRAPHICS_FT80X is not set
+# CONFIG_GRAPHICS_LVGL is not set
+
+#
+# NxWidgets
+#
+
+#
+# NxWM
+#
+# CONFIG_GRAPHICS_PDCURSES is not set
+# CONFIG_TIFF is not set
+
+#
+# Industrial Applications
+#
+# CONFIG_INDUSTRY_ABNT_CODI_LIB is not set
+
+#
+# Interpreters
+#
+# CONFIG_INTERPRETERS_BAS is not set
+# CONFIG_INTERPRETERS_FICL is not set
+# CONFIG_INTERPRETERS_MINIBASIC is not set
+
+#
+# FreeModBus
+#
+# CONFIG_MODBUS is not set
+
+#
+# Network Utilities
+#
+# CONFIG_NETUTILS_CHAT is not set
+# CONFIG_NETUTILS_CJSON is not set
+# CONFIG_NETUTILS_CODECS is not set
+# CONFIG_NETUTILS_ESP8266 is not set
+# CONFIG_NETUTILS_FTPC is not set
+# CONFIG_NETUTILS_SMTP is not set
+
+#
+# NSH Library
+#
+# CONFIG_NSH_LIBRARY is not set
+
+#
+# Platform-specific Support
+#
+# CONFIG_PLATFORM_CONFIGDATA is not set
+CONFIG_HAVE_CXXINITIALIZE=y
+
+#
+# System Libraries and NSH Add-Ons
+#
+# CONFIG_SYSTEM_CLE is not set
+# CONFIG_SYSTEM_CUTERM is not set
+# CONFIG_SYSTEM_EMBEDLOG is not set
+# CONFIG_SYSTEM_HEX2BIN is not set
+# CONFIG_SYSTEM_HEXED is not set
+# CONFIG_SYSTEM_NSH is not set
+# CONFIG_SYSTEM_RAMTEST is not set
+# CONFIG_READLINE_HAVE_EXTMATCH is not set
+CONFIG_SYSTEM_READLINE=y
+CONFIG_READLINE_ECHO=y
+# CONFIG_READLINE_TABCOMPLETION is not set
+# CONFIG_READLINE_CMD_HISTORY is not set
+# CONFIG_SYSTEM_SETLOGMASK is not set
+# CONFIG_SYSTEM_SPITOOL is not set
+# CONFIG_SYSTEM_TEE is not set
+# CONFIG_SYSTEM_TERMCURSES is not set
+# CONFIG_SYSTEM_UBLOXMODEM is not set
+# CONFIG_SYSTEM_VI is not set
+# CONFIG_SYSTEM_ZMODEM is not set
+
+#
+# Testing
+#
+# CONFIG_TESTING_CXXTEST is not set
+# CONFIG_TESTING_FSTEST is not set
+# CONFIG_TESTING_GETPRIME is not set
+# CONFIG_TESTING_NXFFS is not set
+# CONFIG_TESTING_OSTEST is not set
+# CONFIG_TESTING_SCANFTEST is not set
+# CONFIG_TESTING_SMART is not set
+# CONFIG_TESTING_SMART_TEST is not set
+# CONFIG_TESTING_UNITY is not set
+
+#
+# Wireless Libraries and NSH Add-Ons
+#
+
+#
+# Bluetooth applications
+#
+# CONFIG_BTSAK is not set
+
+#
+# IEEE 802.15.4 applications
+#
+# CONFIG_IEEE802154_I8SAK is not set
+# CONFIG_IEEE802154_LIBMAC is not set
+# CONFIG_IEEE802154_LIBUTILS is not set
diff --git a/boards/arm/stm32l4/nucleo-l432kc/include/nucleo-l432kc.h b/boards/arm/stm32l4/nucleo-l432kc/include/nucleo-l432kc.h
index a9819b8..964fffe 100644
--- a/boards/arm/stm32l4/nucleo-l432kc/include/nucleo-l432kc.h
+++ b/boards/arm/stm32l4/nucleo-l432kc/include/nucleo-l432kc.h
@@ -68,7 +68,8 @@
  * synced MSI.
  *
  *   System Clock source           : PLL (HSI)
- *   SYSCLK(Hz)                    : 80000000      Determined by PLL configuration
+ *   SYSCLK(Hz)                    : 80000000      Determined by PLL
+ *                                                 configuration
  *   HCLK(Hz)                      : 80000000     (STM32L4_RCC_CFGR_HPRE)
  *                                                (Max 80 MHz)
  *   AHB Prescaler                 : 1            (STM32L4_RCC_CFGR_HPRE)
@@ -233,9 +234,9 @@
 /* 'main' PLL config; we use this to generate our system clock via the R
  *  output.  We set it up as 16 MHz / 1 * 10 / 2 = 80 MHz
  *
- * XXX NOTE:  currently the main PLL is implicitly turned on and is implicitly
- * the system clock; this should be configurable since not all applications may
- * want things done this way.
+ * XXX NOTE:  currently the main PLL is implicitly turned on and is
+ * implicitly the system clock; this should be configurable since not all
+ * applications may want things done this way.
  */
 
 #define STM32L4_PLLCFG_PLLN             RCC_PLLCFG_PLLN(10)
@@ -495,6 +496,8 @@
 #define STM32L4_APB1_TIM2_CLKIN   (STM32L4_PCLK1_FREQUENCY)
 #define STM32L4_APB1_TIM6_CLKIN   (STM32L4_PCLK1_FREQUENCY)
 #define STM32L4_APB1_TIM7_CLKIN   (STM32L4_PCLK1_FREQUENCY)
+#define STM32L4_APB1_LPTIM1_CLKIN (STM32L4_PCLK1_FREQUENCY)
+#define STM32L4_APB1_LPTIM2_CLKIN (STM32L4_PCLK1_FREQUENCY)
 
 /* Configure the APB2 prescaler */
 
@@ -507,8 +510,8 @@
 
 #endif
 
-/* The timer clock frequencies are automatically defined by hardware.
- * If the APB prescaler equals 1, the timer clock frequencies are set to the same
+/* The timer clock frequencies are automatically defined by hardware. If the
+ * APB prescaler equals 1, the timer clock frequencies are set to the same
  * frequency as that of the APB domain. Otherwise they are set to twice.
  * Note: TIM1,15,16 are on APB2, others on APB1
  */
diff --git a/boards/arm/stm32l4/nucleo-l432kc/src/Makefile b/boards/arm/stm32l4/nucleo-l432kc/src/Makefile
index 9c0c71b..899191d 100644
--- a/boards/arm/stm32l4/nucleo-l432kc/src/Makefile
+++ b/boards/arm/stm32l4/nucleo-l432kc/src/Makefile
@@ -92,4 +92,8 @@ ifeq ($(CONFIG_LIB_BOARDCTL),y)
 CSRCS += stm32_appinit.c
 endif
 
+ifeq ($(CONFIG_NUCLEOL432KC_SPWM),y)
+CSRCS += stm32_spwm.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm/stm32l4/nucleo-l432kc/src/stm32_spwm.c b/boards/arm/stm32l4/nucleo-l432kc/src/stm32_spwm.c
new file mode 100644
index 0000000..9f10e71
--- /dev/null
+++ b/boards/arm/stm32l4/nucleo-l432kc/src/stm32_spwm.c
@@ -0,0 +1,664 @@
+/****************************************************************************
+ * boards/arm/stm32/nucleo-l432kc/src/stm32_spwm.c
+ *
+ *   Copyright (C) 2018, 2019 Gregory Nutt. All rights reserved.
+ *   Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/signal.h>
+
+#include <arch/irq.h>
+#include <arch/chip/chip.h>
+#include <arch/board/board.h>
+
+#include "up_internal.h"
+#include "ram_vectors.h"
+
+#include "stm32l4_pwm.h"
+#include "stm32l4_tim.h"
+
+#ifdef CONFIG_NUCLEOL432KC_SPWM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Assertions ***************************************************************/
+
+#ifndef CONFIG_ARCH_CHIP_STM32L432KC
+#  warning "This only have been verified with CONFIG_ARCH_CHIP_STM32L432KC"
+#endif
+
+#ifndef CONFIG_ARCH_HIPRI_INTERRUPT
+#  error "CONFIG_ARCH_HIPRI_INTERRUPT is required"
+#endif
+
+#ifndef CONFIG_ARCH_RAMVECTORS
+#  error "CONFIG_ARCH_RAMVECTORS is required"
+#endif
+
+#ifndef CONFIG_ARCH_IRQPRIO
+#  error "CONFIG_ARCH_IRQPRIO is required"
+#endif
+
+#ifndef CONFIG_ARCH_FPU
+#  warning "Set CONFIG_ARCH_FPU for hardware FPU support"
+#endif
+
+/* Check the configuration for TIM1 */
+
+#ifdef CONFIG_NUCLEOL432KC_SPWM_USE_TIM1
+
+/* Phase 1 is TIM1 CH1 */
+
+#  if CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM > 0
+#    ifndef CONFIG_STM32L4_TIM1_CH1OUT
+#      error
+#    endif
+#    ifndef CONFIG_STM32L4_TIM6
+#      error
+#    endif
+#  endif
+
+/* Phase 2 is TIM1 CH2 */
+
+#  if CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM > 1
+#    ifndef CONFIG_STM32L4_TIM1_CH2OUT
+#      error
+#    endif
+#  endif
+
+/* Phase 3 is TIM1 CH3 */
+
+#  if CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM > 2
+#    ifndef CONFIG_STM32L4_TIM1_CH3OUT
+#      error
+#    endif
+#  endif
+
+/* Phase 4 is TIM1 CH4 */
+
+#  if CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM > 3
+#    ifndef CONFIG_STM32L4_TIM1_CH4OUT
+#      error
+#    endif
+#  endif
+
+#  if CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM != PWM_TIM1_NCHANNELS
+#    error
+#  endif
+
+#endif  /* CONFIG_NUCLEOL432KC_SPWM_USE_TIM1 */
+
+/* Configuration ************************************************************/
+
+#ifdef CONFIG_NUCLEOL432KC_SPWM_USE_TIM1
+#  define PWM_TIMERS_IN_USE 1
+#endif
+
+#define SPWM_PHASE_SHIFT ((360.0f/CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM))
+
+#define SAMPLES_NUM CONFIG_NUCLEOL432KC_SPWM_SAMPLES
+#define PHASES_NUM CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* SPWM private data */
+
+struct spwm_s
+{
+  FAR struct stm32l4_pwm_dev_s *pwm;
+#ifdef CONFIG_NUCLEOL432KC_SPWM_USE_TIM1
+  FAR struct stm32l4_tim_dev_s *tim;
+#endif
+  float waveform[SAMPLES_NUM];        /* Waveform samples */
+  float phase_step;                   /* Waveform phase step */
+  float waveform_freq;                /* Waveform frequency */
+  uint16_t cmp[SAMPLES_NUM];          /* PWM TIM compare table */
+  uint16_t per;                       /* PWM TIM period */
+  uint16_t samples;                   /* Modulation waveform samples num */
+  uint16_t phase_shift[PHASES_NUM];   /* Phase offset */
+  volatile uint16_t sample_now[PHASES_NUM];  /* Current sample number for
+                                              * phase */
+  uint8_t phases;                     /* Number of PWM phases */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct spwm_s g_spwm =
+{
+  .waveform_freq = ((float)CONFIG_NUCLEOL432KC_SPWM_FREQ),
+  .phases        = PHASES_NUM,
+  .samples       = SAMPLES_NUM,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static float waveform_func(float x);
+static int waveform_init(FAR struct spwm_s *spwm, float (*f)(float));
+static int spwm_start(FAR struct spwm_s *spwm);
+static int spwm_start(FAR struct spwm_s *spwm);
+static int spwm_stop(FAR struct spwm_s *spwm);
+#ifdef CONFIG_NUCLEOL432KC_SPWM_USE_TIM1
+static int spwm_tim1_setup(FAR struct spwm_s *spwm);
+static int spwm_tim6_setup(FAR struct spwm_s *spwm);
+static int spwm_tim1_start(FAR struct spwm_s *spwm);
+static int spwm_tim6_start(FAR struct spwm_s *spwm);
+static int spwm_tim1_stop(FAR struct spwm_s *spwm);
+static int spwm_tim6_stop(FAR struct spwm_s *spwm);
+#endif  /* CONFIG_NUCLEOL432KC_SPWM_USE_TIM1 */
+static int spwm_setup(FAR struct spwm_s *spwm);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: waveform_func
+ *
+ * Description:
+ *   Modulation function. This function must return values from <0.0, 1.0>!
+ *
+ ****************************************************************************/
+
+static float waveform_func(float x)
+{
+  DEBUGASSERT(x >= 0 && x <= 2 * M_PI);
+
+  /* Sine modulation */
+
+  return (sinf(x) + 1.0f) / 2.0f;
+}
+
+/****************************************************************************
+ * Name: waveform_init
+ *
+ * Description:
+ *   Initialize modulation waveform
+ *
+ ****************************************************************************/
+
+static int waveform_init(FAR struct spwm_s *spwm, float (*f)(float))
+{
+  uint16_t i = 0;
+  int ret = 0;
+
+  printf("Initialize waveform\n");
+
+  /* Get phase step to achieve one sine waveform period */
+
+  spwm->phase_step = (float)(2 * M_PI / spwm->samples);
+
+  /* Initialize sine and PWM compare tables */
+
+  for (i = 0; i < spwm->samples; i += 1)
+    {
+      /* We need sine in range from 0 to 1.0 */
+
+      spwm->waveform[i] = f(spwm->phase_step * i);
+
+      DEBUGASSERT(spwm->waveform[i] >= 0.0 && spwm->waveform[i] <= 2 * M_PI);
+
+      spwm->cmp[i] = (uint16_t)(spwm->waveform[i] * spwm->per);
+    }
+
+  /* Configure phase shift TODO: this should be configurable */
+
+  for (i = 0; i < spwm->phases; i += 1)
+    {
+      spwm->phase_shift[i] =
+        (spwm->samples / CONFIG_NUCLEOL432KC_SPWM_PHASE_NUM) * i;
+    }
+
+  /* Initialize offstes */
+
+  for (i = 0; i < spwm->phases; i += 1)
+    {
+      spwm->sample_now[i] = spwm->phase_shift[i];
+    }
+
+  printf("\tsamples = %d\n", spwm->samples);
+  printf("\tper     = %d\n", spwm->per);
+  printf("\tphase   = %d\n", spwm->phases);
+  for (i = 0; i < spwm->phases; i += 1)
+    {
+      printf("\tsnow%d   = %d\n", i, spwm->sample_now[i]);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: spwm_start
+ *
+ * Description:
+ *   Start SPWM
+ *
+ ****************************************************************************/
+
+static int spwm_start(FAR struct spwm_s *spwm)
+{
+  /* Start TIM1 */
+
+  spwm_tim1_start(spwm);
+
+  /* Start TIM6 */
+
+  spwm_tim6_start(spwm);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: spwm_stop
+ *
+ * Description:
+ *   Stop SPWM
+ *
+ ****************************************************************************/
+
+static int spwm_stop(FAR struct spwm_s *spwm)
+{
+  /* Stop TIM1 */
+
+  spwm_tim1_stop(spwm);
+
+  /* Stop TIM6 */
+
+  spwm_tim6_stop(spwm);
+
+  return OK;
+}
+
+#ifdef CONFIG_NUCLEOL432KC_SPWM_USE_TIM1
+
+/****************************************************************************
+ * Name: tim6_handler
+ ****************************************************************************/
+
+static void tim6_handler(void)
+{
+  FAR struct spwm_s *spwm = &g_spwm;
+  FAR struct stm32l4_pwm_dev_s *pwm = spwm->pwm;
+  FAR struct stm32l4_tim_dev_s *tim = spwm->tim;
+  uint8_t i = 0;
+
+  for (i = 0; i < spwm->phases; i += 1)
+    {
+      /* Set new CMP for timers */
+
+      PWM_CCR_UPDATE(pwm, i + 1, spwm->cmp[spwm->sample_now[i]]);
+
+      /* Increase sample pointer */
+
+      spwm->sample_now[i] += 1;
+
+      if (spwm->sample_now[i] > spwm->samples)
+        {
+          spwm->sample_now[i] = 0;
+        }
+    }
+
+  /* TODO: Software update */
+
+  STM32L4_TIM_ACKINT(tim, ATIM_SR_UIF);
+}
+
+/****************************************************************************
+ * Name: spwm_tim6_setup
+ ****************************************************************************/
+
+static int spwm_tim6_setup(FAR struct spwm_s *spwm)
+{
+  FAR struct stm32l4_tim_dev_s *tim = NULL;
+  uint64_t freq = 0;
+  uint32_t per = 0;
+  int ret = OK;
+
+  /* Get TIM6 interface */
+
+  tim = stm32l4_tim_init(6);
+  if (tim == NULL)
+    {
+      printf("ERROR: Failed to get TIM6 interface\n");
+      ret = -1;
+      goto errout;
+    }
+
+  spwm->tim = tim;
+
+  /* Frequency with which we will change samples.
+   *
+   * tim6_freq = samples_num * waveform_freq.
+   */
+
+  freq = spwm->samples * spwm->waveform_freq;
+  per = BOARD_TIM6_FREQUENCY / freq;
+  if (per > 0xffff)
+    {
+      printf("ERROR: can not achieve TIM6 frequency\n");
+      ret = -1;
+      goto errout;
+    }
+
+  /* TODO: TIM_SETFREQ */
+
+  STM32L4_TIM_SETCLOCK(tim, BOARD_TIM6_FREQUENCY);
+  STM32L4_TIM_SETPERIOD(tim, per);
+
+  /* Attach TIM6 ram vector */
+
+  ret = up_ramvec_attach(STM32L4_IRQ_TIM6, tim6_handler);
+  if (ret < 0)
+    {
+      printf("ERROR: up_ramvec_attach failed: %d\n", ret);
+      ret = -1;
+      goto errout;
+    }
+
+  /* Set the priority of the TIM6 interrupt vector */
+
+  ret = up_prioritize_irq(STM32L4_IRQ_TIM6, NVIC_SYSH_HIGH_PRIORITY);
+  if (ret < 0)
+    {
+      printf("ERROR: up_prioritize_irq failed: %d\n", ret);
+      ret = -1;
+      goto errout;
+    }
+
+  spwm_tim6_stop(spwm);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: spwm_tim6_start
+ ****************************************************************************/
+
+static int spwm_tim6_start(FAR struct spwm_s *spwm)
+{
+  FAR struct stm32l4_tim_dev_s *tim = spwm->tim;
+
+  /* Enable the timer interrupt at the NVIC and at TIM6 */
+
+  up_enable_irq(STM32L4_IRQ_TIM6);
+  STM32L4_TIM_ENABLEINT(tim, BTIM_DIER_UIE);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: spwm_tim6_stop
+ ****************************************************************************/
+
+static int spwm_tim6_stop(FAR struct spwm_s *spwm)
+{
+  FAR struct stm32l4_tim_dev_s *tim = spwm->tim;
+
+  /* Disable the timer interrupt at the NVIC and at TIM6 */
+
+  up_disable_irq(STM32L4_IRQ_TIM6);
+  STM32L4_TIM_DISABLEINT(tim, BTIM_DIER_UIE);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: spwm_tim1_setup
+ ****************************************************************************/
+
+static int spwm_tim1_setup(FAR struct spwm_s *spwm)
+{
+  FAR struct stm32l4_pwm_dev_s *pwm = NULL;
+  int ret = OK;
+
+  /* Get TIM1 PWM interface */
+
+  pwm = (FAR struct stm32l4_pwm_dev_s *)stm32l4_pwminitialize(1);
+  if (pwm == NULL)
+    {
+      printf("ERROR: Failed to get TIM1 PWM interface\n");
+      ret = -1;
+      goto errout;
+    }
+
+  spwm->pwm = pwm;
+
+  /* Initial PWM1 setup */
+
+  ret = PWM_SETUP(pwm);
+  if (ret < 0)
+    {
+      printf("ERROR: Failed to get setup TIM1 PWM\n");
+      ret = -1;
+      goto errout;
+    }
+
+  /* Configure TIM1 PWM frequency */
+
+  ret = PWM_FREQ_UPDATE(pwm, CONFIG_NUCLEOL432KC_SPWM_PWM_FREQ);
+  if (ret < 0)
+    {
+      printf("ERROR: Failed to set TIM1 PWM frequency\n");
+      ret = -1;
+      goto errout;
+    }
+
+  /* Get TIM1 period (ARR) */
+
+  spwm->per = PWM_ARR_GET(pwm);
+
+  spwm_tim1_stop(spwm);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: spwm_tim1_start
+ ****************************************************************************/
+
+static int spwm_tim1_start(FAR struct spwm_s *spwm)
+{
+  FAR struct stm32l4_pwm_dev_s *pwm = spwm->pwm;
+  uint16_t outputs = 0;
+  int i = 0;
+
+  /* Get outputs */
+
+  for (i = 0; i < spwm->phases; i += 1)
+    {
+      outputs |= (1 << (i * 2));
+    }
+
+  /* Enable PWM outputs */
+
+  PWM_OUTPUTS_ENABLE(pwm, outputs, true);
+
+  /* Enable TIM1 */
+
+  PWM_TIM_ENABLE(pwm, true);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: spwm_tim1_stop
+ ****************************************************************************/
+
+static int spwm_tim1_stop(FAR struct spwm_s *spwm)
+{
+  FAR struct stm32l4_pwm_dev_s *pwm = spwm->pwm;
+  uint16_t outputs = 0;
+  int i = 0;
+
+  /* Get outputs */
+
+  for (i = 0; i < spwm->phases; i += 1)
+    {
+      outputs |= (1 << (i * 2));
+    }
+
+  /* Disable PWM outputs */
+
+  PWM_OUTPUTS_ENABLE(pwm, outputs, false);
+
+  /* Disable TIM1 */
+
+  PWM_TIM_ENABLE(pwm, false);
+
+  return OK;
+}
+
+#endif  /* CONFIG_NUCLEOL432KC_SPWM_USE_TIM1 */
+
+/****************************************************************************
+ * Name: spwm_setup
+ ****************************************************************************/
+
+static int spwm_setup(FAR struct spwm_s *spwm)
+{
+  int ret = OK;
+
+  /* TIM1 setup - PWM */
+
+  printf("Setup TIM1 and TIM6\n");
+  ret = spwm_tim1_setup(spwm);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  /* TIM6 setup - IRQ */
+
+  ret = spwm_tim6_setup(spwm);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: spwm_main
+ *
+ * Description:
+ *   Entrypoint for SPWM example.
+ *
+ ****************************************************************************/
+
+int spwm_main(int argc, char *argv[])
+{
+  FAR struct spwm_s *spwm = NULL;
+  int ret = OK;
+  int i = 0;
+
+  spwm = &g_spwm;
+
+  printf("\nspwm_main: Started\n");
+
+  /* Setup SPWM example */
+
+  ret = spwm_setup(spwm);
+  if (ret < 0)
+    {
+      printf("ERROR: failed to setup SPWM %d!\n", ret);
+      goto errout;
+    }
+
+  /* Initialize modulation waveform */
+
+  ret = waveform_init(spwm, waveform_func);
+  if (ret < 0)
+    {
+      printf("ERROR: failed initialize modulation wavefrom %d!\n", ret);
+      goto errout;
+    }
+
+  /* Start SPWM */
+
+  ret = spwm_start(spwm);
+  if (ret < 0)
+    {
+      printf("ERROR: failed start SPWM %d!\n", ret);
+      goto errout;
+    }
+
+  /* Main loop */
+
+  while (1)
+    {
+      /* Print counter */
+
+      printf("%d\n", i);
+
+      /* Increase counter */
+
+      i += 1;
+
+      /* Sleep */
+
+      nxsig_sleep(1);
+    }
+
+errout:
+  spwm_stop(spwm);
+
+  return 0;
+}
+
+#endif  /* CONFIG_NUCLEOL432KC_SPWM */