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

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

commit 5bacc302eb3880ffc485ab1aa66c31f927d0b44b
Author: raiden00pl <[email protected]>
AuthorDate: Sat Apr 11 11:52:48 2026 +0200

    arch/stm32f0l0g0: add qencoder support
    
    add QENCODER support for STM32F0/L0/G0/C0
    
    Signed-off-by: raiden00pl <[email protected]>
---
 arch/arm/src/stm32f0l0g0/CMakeLists.txt            |    4 +
 arch/arm/src/stm32f0l0g0/Kconfig                   |  152 +++
 arch/arm/src/stm32f0l0g0/Make.defs                 |    4 +
 arch/arm/src/stm32f0l0g0/hardware/stm32c0_pinmap.h |  254 +++-
 arch/arm/src/stm32f0l0g0/stm32_qencoder.c          | 1254 ++++++++++++++++++++
 arch/arm/src/stm32f0l0g0/stm32_qencoder.h          |  116 ++
 6 files changed, 1764 insertions(+), 20 deletions(-)

diff --git a/arch/arm/src/stm32f0l0g0/CMakeLists.txt 
b/arch/arm/src/stm32f0l0g0/CMakeLists.txt
index 2d0b6d9cb53..b2cf874c32e 100644
--- a/arch/arm/src/stm32f0l0g0/CMakeLists.txt
+++ b/arch/arm/src/stm32f0l0g0/CMakeLists.txt
@@ -124,4 +124,8 @@ if(CONFIG_STM32F0L0G0_FDCAN)
   endif()
 endif()
 
+if(CONFIG_SENSORS_QENCODER)
+  list(APPEND SRCS stm32_qencoder.c)
+endif()
+
 target_sources(arch PRIVATE ${SRCS})
diff --git a/arch/arm/src/stm32f0l0g0/Kconfig b/arch/arm/src/stm32f0l0g0/Kconfig
index 823254a704c..b4b529d90a1 100644
--- a/arch/arm/src/stm32f0l0g0/Kconfig
+++ b/arch/arm/src/stm32f0l0g0/Kconfig
@@ -2386,6 +2386,13 @@ endif # !STM32F0L0G0_PWM_MULTICHAN
 
 endif # STM32F0L0G0_TIM1_PWM
 
+config STM32F0L0G0_TIM1_QE
+       bool "TIM1 Quadrature Encoder"
+       default n
+       depends on STM32F0L0G0_TIM1
+       ---help---
+               Reserve TIM1 for use by Quadrature Encoder.
+
 config STM32F0L0G0_TIM2_PWM
        bool "TIM2 PWM"
        default n
@@ -2540,6 +2547,13 @@ endif # !STM32F0L0G0_PWM_MULTICHAN
 
 endif # STM32F0L0G0_TIM2_PWM
 
+config STM32F0L0G0_TIM2_QE
+       bool "TIM2 Quadrature Encoder"
+       default n
+       depends on STM32F0L0G0_TIM2
+       ---help---
+               Reserve TIM2 for use by Quadrature Encoder.
+
 config STM32F0L0G0_TIM3_PWM
        bool "TIM3 PWM"
        default n
@@ -2694,6 +2708,144 @@ endif # !STM32F0L0G0_PWM_MULTICHAN
 
 endif # STM32F0L0G0_TIM3_PWM
 
+config STM32F0L0G0_TIM3_QE
+       bool "TIM3 Quadrature Encoder"
+       default n
+       depends on STM32F0L0G0_TIM3
+       ---help---
+               Reserve TIM3 for use by Quadrature Encoder.
+
+config STM32F0L0G0_TIM4_QE
+       bool "TIM3 Quadrature Encoder"
+       default n
+       depends on STM32F0L0G0_TIM4
+       ---help---
+               Reserve TIM4 for use by Quadrature Encoder.
+
+menu "STM32F0L0G0 QEncoder Driver"
+       depends on SENSORS_QENCODER
+       depends on STM32F0L0G0_TIM1 || STM32F0L0G0_TIM2 || STM32F0L0G0_TIM3 || 
STM32F0L0G0_TIM4
+
+config STM32F0L0G0_TIM1_QEPSC
+       int "TIM1 QE pulse prescaler"
+       default 1
+       depends on STM32F0L0G0_TIM1_QE
+       ---help---
+               This prescaler divides the number of recorded encoder pulses,
+               limiting the count rate at the expense of resolution.
+
+config STM32F0L0G0_TIM2_QEPSC
+       int "TIM2 QE pulse prescaler"
+       default 1
+       depends on STM32F0L0G0_TIM2_QE
+       ---help---
+               This prescaler divides the number of recorded encoder pulses,
+               limiting the count rate at the expense of resolution.
+
+config STM32F0L0G0_TIM3_QEPSC
+       int "TIM3 QE pulse prescaler"
+       default 1
+       depends on STM32F0L0G0_TIM3_QE
+       ---help---
+               This prescaler divides the number of recorded encoder pulses,
+               limiting the count rate at the expense of resolution.
+
+config STM32F0L0G0_TIM4_QEPSC
+       int "TIM3 QE pulse prescaler"
+       default 1
+       depends on STM32F0L0G0_TIM4_QE
+       ---help---
+               This prescaler divides the number of recorded encoder pulses,
+               limiting the count rate at the expense of resolution.
+
+config STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+       bool "Disable QEncoder timers extension from 16-bit to 32-bit"
+       default n
+       ---help---
+               Disable the extension of 16-bit timers to 32-bit via 
interrupt-based
+               overflow tracking. When enabled, timers will use their native 
hardware
+               counter width (16-bit or 32-bit). This reduces interrupt 
overhead but
+               limits the position range for 16-bit timers.
+
+config STM32F0L0G0_QENCODER_INDEX_PIN
+       bool "Enable QEncoder timers support for index pin"
+       default n
+       ---help---
+               Enable support for quadrature encoder index pin. The index pin 
can be
+               used to reset the encoder position to a known value when the 
index
+               pulse is detected.
+
+config STM32F0L0G0_QENCODER_FILTER
+       bool "Enable filtering on STM32F0L0G0 QEncoder input"
+       default y
+       ---help---
+               Enable input filtering on quadrature encoder channels to reduce 
noise.
+
+choice
+       depends on STM32F0L0G0_QENCODER_FILTER
+       prompt "Input channel sampling frequency"
+       default STM32F0L0G0_QENCODER_SAMPLE_FDTS_4
+       ---help---
+               Select the sampling frequency for the input filter.
+
+config STM32F0L0G0_QENCODER_SAMPLE_FDTS
+       bool "fDTS"
+
+config STM32F0L0G0_QENCODER_SAMPLE_CKINT
+       bool "fCK_INT"
+
+config STM32F0L0G0_QENCODER_SAMPLE_FDTS_2
+       bool "fDTS/2"
+
+config STM32F0L0G0_QENCODER_SAMPLE_FDTS_4
+       bool "fDTS/4"
+
+config STM32F0L0G0_QENCODER_SAMPLE_FDTS_8
+       bool "fDTS/8"
+
+config STM32F0L0G0_QENCODER_SAMPLE_FDTS_16
+       bool "fDTS/16"
+
+config STM32F0L0G0_QENCODER_SAMPLE_FDTS_32
+       bool "fDTS/32"
+
+endchoice
+
+choice
+       depends on STM32F0L0G0_QENCODER_FILTER
+       prompt "Input channel event count"
+       default STM32F0L0G0_QENCODER_SAMPLE_EVENT_6
+       ---help---
+               Select the number of consecutive events required to validate a 
transition.
+
+config STM32F0L0G0_QENCODER_SAMPLE_EVENT_1
+       depends on STM32F0L0G0_QENCODER_SAMPLE_FDTS
+       bool "1"
+
+config STM32F0L0G0_QENCODER_SAMPLE_EVENT_2
+       depends on STM32F0L0G0_QENCODER_SAMPLE_CKINT
+       bool "2"
+
+config STM32F0L0G0_QENCODER_SAMPLE_EVENT_4
+       depends on STM32F0L0G0_QENCODER_SAMPLE_CKINT
+       bool "4"
+
+config STM32F0L0G0_QENCODER_SAMPLE_EVENT_5
+       depends on STM32F0L0G0_QENCODER_SAMPLE_FDTS_16 || 
STM32F0L0G0_QENCODER_SAMPLE_FDTS_32
+       bool "5"
+
+config STM32F0L0G0_QENCODER_SAMPLE_EVENT_6
+       depends on !STM32F0L0G0_QENCODER_SAMPLE_FDTS && 
!STM32F0L0G0_QENCODER_SAMPLE_CKINT
+       bool "6"
+
+config STM32F0L0G0_QENCODER_SAMPLE_EVENT_8
+       depends on !STM32F0L0G0_QENCODER_SAMPLE_FDTS
+       bool "8"
+
+endchoice
+
+endmenu # STM32F0L0G0 QEncoder Driver
+
 config STM32F0L0G0_TIM14_PWM
        bool "TIM14 PWM"
        default n
diff --git a/arch/arm/src/stm32f0l0g0/Make.defs 
b/arch/arm/src/stm32f0l0g0/Make.defs
index 3b73b01180d..df47027944c 100644
--- a/arch/arm/src/stm32f0l0g0/Make.defs
+++ b/arch/arm/src/stm32f0l0g0/Make.defs
@@ -109,3 +109,7 @@ ifeq ($(CONFIG_STM32F0L0G0_FDCAN_SOCKET),y)
 CHIP_CSRCS += stm32_fdcan_sock.c
 endif
 endif
+
+ifeq ($(CONFIG_SENSORS_QENCODER),y)
+CHIP_CSRCS += stm32_qencoder.c
+endif
diff --git a/arch/arm/src/stm32f0l0g0/hardware/stm32c0_pinmap.h 
b/arch/arm/src/stm32f0l0g0/hardware/stm32c0_pinmap.h
index 476e3691447..4e10209f8a6 100644
--- a/arch/arm/src/stm32f0l0g0/hardware/stm32c0_pinmap.h
+++ b/arch/arm/src/stm32f0l0g0/hardware/stm32c0_pinmap.h
@@ -116,25 +116,239 @@
 
 /* FDCAN1 */
 
-#define GPIO_FDCAN1_RX_1               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTA | GPIO_PIN11)
-#define GPIO_FDCAN1_RX_2               (GPIO_ALT | GPIO_AF3 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN0)
-#define GPIO_FDCAN1_RX_3               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN5)
-#define GPIO_FDCAN1_RX_4               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN12)
-#define GPIO_FDCAN1_RX_5               (GPIO_ALT | GPIO_AF8 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN8)
-#define GPIO_FDCAN1_RX_6               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN2)
-#define GPIO_FDCAN1_RX_7               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN4)
-#define GPIO_FDCAN1_RX_8               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTD | GPIO_PIN0)
-
-#define GPIO_FDCAN1_TX_1               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTA | GPIO_PIN12)
-#define GPIO_FDCAN1_TX_2               (GPIO_ALT | GPIO_AF3 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN1)
-#define GPIO_FDCAN1_TX_3               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN13)
-#define GPIO_FDCAN1_TX_4               (GPIO_ALT | GPIO_AF15 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN6)
-#define GPIO_FDCAN1_TX_5               (GPIO_ALT | GPIO_AF8 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN9)
-#define GPIO_FDCAN1_TX_6               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN3)
-#define GPIO_FDCAN1_TX_7               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN5)
-#define GPIO_FDCAN1_TX_8               (GPIO_ALT | GPIO_AF13 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN14)
-#define GPIO_FDCAN1_TX_9               (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTD | GPIO_PIN1)
-
-/* TODO: missing pinmaps */
+#define GPIO_FDCAN1_RX_1      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTA | GPIO_PIN11)
+#define GPIO_FDCAN1_RX_2      (GPIO_ALT | GPIO_AF3 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN0)
+#define GPIO_FDCAN1_RX_3      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN5)
+#define GPIO_FDCAN1_RX_4      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN12)
+#define GPIO_FDCAN1_RX_5      (GPIO_ALT | GPIO_AF8 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN8)
+#define GPIO_FDCAN1_RX_6      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN2)
+#define GPIO_FDCAN1_RX_7      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN4)
+#define GPIO_FDCAN1_RX_8      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTD | GPIO_PIN0)
+
+#define GPIO_FDCAN1_TX_1      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTA | GPIO_PIN12)
+#define GPIO_FDCAN1_TX_2      (GPIO_ALT | GPIO_AF3 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN1)
+#define GPIO_FDCAN1_TX_3      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN13)
+#define GPIO_FDCAN1_TX_4      (GPIO_ALT | GPIO_AF15 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN6)
+#define GPIO_FDCAN1_TX_5      (GPIO_ALT | GPIO_AF8 | GPIO_PUSHPULL | 
GPIO_PORTB | GPIO_PIN9)
+#define GPIO_FDCAN1_TX_6      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN3)
+#define GPIO_FDCAN1_TX_7      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN5)
+#define GPIO_FDCAN1_TX_8      (GPIO_ALT | GPIO_AF13 | GPIO_PUSHPULL | 
GPIO_PORTC | GPIO_PIN14)
+#define GPIO_FDCAN1_TX_9      (GPIO_ALT | GPIO_AF4 | GPIO_PUSHPULL | 
GPIO_PORTD | GPIO_PIN1)
+
+/* TIM1 */
+
+#define GPIO_TIM1_BKIN_1      (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN6)
+#define GPIO_TIM1_BKIN_2      (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN12)
+#define GPIO_TIM1_BKIN_3      (GPIO_ALT | GPIO_AF2 | GPIO_PORTC | GPIO_PIN13)
+#define GPIO_TIM1_BKIN_4      (GPIO_ALT | GPIO_AF2 | GPIO_PORTD | GPIO_PIN5)
+#define GPIO_TIM1_BKIN2_1     (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN11)
+#define GPIO_TIM1_BKIN2_2     (GPIO_ALT | GPIO_AF1 | GPIO_PORTB | GPIO_PIN12)
+#define GPIO_TIM1_BKIN2_3     (GPIO_ALT | GPIO_AF2 | GPIO_PORTC | GPIO_PIN14)
+#define GPIO_TIM1_BKIN2_4     (GPIO_ALT | GPIO_AF2 | GPIO_PORTD | GPIO_PIN9)
+#define GPIO_TIM1_CH1IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTA | 
GPIO_PIN0)
+#define GPIO_TIM1_CH1IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTA | 
GPIO_PIN5)
+#define GPIO_TIM1_CH1IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTA | 
GPIO_PIN8)
+#define GPIO_TIM1_CH1IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF10 | GPIO_PORTA 
| GPIO_PIN14)
+#define GPIO_TIM1_CH1IN_5     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTA | 
GPIO_PIN15)
+#define GPIO_TIM1_CH1IN_6     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTC | 
GPIO_PIN8)
+#define GPIO_TIM1_CH1OUT_1    (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN0)
+#define GPIO_TIM1_CH1OUT_2    (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN5)
+#define GPIO_TIM1_CH1OUT_3    (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN8)
+#define GPIO_TIM1_CH1OUT_4    (GPIO_ALT | GPIO_AF10 | GPIO_PORTA | GPIO_PIN14)
+#define GPIO_TIM1_CH1OUT_5    (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN15)
+#define GPIO_TIM1_CH1OUT_6    (GPIO_ALT | GPIO_AF2 | GPIO_PORTC | GPIO_PIN8)
+#define GPIO_TIM1_CH1NOUT_1   (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN3)
+#define GPIO_TIM1_CH1NOUT_2   (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN7)
+#define GPIO_TIM1_CH1NOUT_3   (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN13)
+#define GPIO_TIM1_CH1NOUT_4   (GPIO_ALT | GPIO_AF2 | GPIO_PORTD | GPIO_PIN2)
+#define GPIO_TIM1_CH2IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTA | 
GPIO_PIN1)
+#define GPIO_TIM1_CH2IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTA | 
GPIO_PIN9)
+#define GPIO_TIM1_CH2IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTB | 
GPIO_PIN3)
+#define GPIO_TIM1_CH2IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF11 | GPIO_PORTB 
| GPIO_PIN6)
+#define GPIO_TIM1_CH2IN_5     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTC | 
GPIO_PIN9)
+#define GPIO_TIM1_CH2OUT_1    (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN1)
+#define GPIO_TIM1_CH2OUT_2    (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN9)
+#define GPIO_TIM1_CH2OUT_3    (GPIO_ALT | GPIO_AF1 | GPIO_PORTB | GPIO_PIN3)
+#define GPIO_TIM1_CH2OUT_4    (GPIO_ALT | GPIO_AF11 | GPIO_PORTB | GPIO_PIN6)
+#define GPIO_TIM1_CH2OUT_5    (GPIO_ALT | GPIO_AF2 | GPIO_PORTC | GPIO_PIN9)
+#define GPIO_TIM1_CH2NOUT_1   (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN4)
+#define GPIO_TIM1_CH2NOUT_2   (GPIO_ALT | GPIO_AF9 | GPIO_PORTA | GPIO_PIN8)
+#define GPIO_TIM1_CH2NOUT_3   (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN0)
+#define GPIO_TIM1_CH2NOUT_4   (GPIO_ALT | GPIO_AF5 | GPIO_PORTB | GPIO_PIN1)
+#define GPIO_TIM1_CH2NOUT_5   (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN14)
+#define GPIO_TIM1_CH2NOUT_6   (GPIO_ALT | GPIO_AF2 | GPIO_PORTD | GPIO_PIN3)
+#define GPIO_TIM1_CH3IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTA | 
GPIO_PIN2)
+#define GPIO_TIM1_CH3IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTA | 
GPIO_PIN10)
+#define GPIO_TIM1_CH3IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTB | 
GPIO_PIN6)
+#define GPIO_TIM1_CH3IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTC | 
GPIO_PIN10)
+#define GPIO_TIM1_CH3OUT_1    (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN2)
+#define GPIO_TIM1_CH3OUT_2    (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN10)
+#define GPIO_TIM1_CH3OUT_3    (GPIO_ALT | GPIO_AF1 | GPIO_PORTB | GPIO_PIN6)
+#define GPIO_TIM1_CH3OUT_4    (GPIO_ALT | GPIO_AF2 | GPIO_PORTC | GPIO_PIN10)
+#define GPIO_TIM1_CH3NOUT_1   (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN5)
+#define GPIO_TIM1_CH3NOUT_2   (GPIO_ALT | GPIO_AF10 | GPIO_PORTA | GPIO_PIN8)
+#define GPIO_TIM1_CH3NOUT_3   (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN1)
+#define GPIO_TIM1_CH3NOUT_4   (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN15)
+#define GPIO_TIM1_CH3NOUT_5   (GPIO_ALT | GPIO_AF2 | GPIO_PORTD | GPIO_PIN4)
+#define GPIO_TIM1_CH4IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTA | 
GPIO_PIN3)
+#define GPIO_TIM1_CH4IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTA | 
GPIO_PIN11)
+#define GPIO_TIM1_CH4IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTB | 
GPIO_PIN7)
+#define GPIO_TIM1_CH4IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTC | 
GPIO_PIN11)
+#define GPIO_TIM1_CH4IN_5     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTF | 
GPIO_PIN2)
+#define GPIO_TIM1_CH4OUT_1    (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN3)
+#define GPIO_TIM1_CH4OUT_2    (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN11)
+#define GPIO_TIM1_CH4OUT_3    (GPIO_ALT | GPIO_AF1 | GPIO_PORTB | GPIO_PIN7)
+#define GPIO_TIM1_CH4OUT_4    (GPIO_ALT | GPIO_AF2 | GPIO_PORTC | GPIO_PIN11)
+#define GPIO_TIM1_CH4OUT_5    (GPIO_ALT | GPIO_AF1 | GPIO_PORTF | GPIO_PIN2)
+
+/* TIM2 */
+
+#define GPIO_TIM2_CH1IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTA | 
GPIO_PIN0)
+#define GPIO_TIM2_CH1IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTA | 
GPIO_PIN5)
+#define GPIO_TIM2_CH1IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTA | 
GPIO_PIN15)
+#define GPIO_TIM2_CH1IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTC | 
GPIO_PIN4)
+#define GPIO_TIM2_CH1OUT_1    (GPIO_ALT | GPIO_AF3 | GPIO_PORTA | GPIO_PIN0)
+#define GPIO_TIM2_CH1OUT_2    (GPIO_ALT | GPIO_AF3 | GPIO_PORTA | GPIO_PIN5)
+#define GPIO_TIM2_CH1OUT_3    (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN15)
+#define GPIO_TIM2_CH1OUT_4    (GPIO_ALT | GPIO_AF3 | GPIO_PORTC | GPIO_PIN4)
+#define GPIO_TIM2_CH2IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTA | 
GPIO_PIN1)
+#define GPIO_TIM2_CH2IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF6 | GPIO_PORTB | 
GPIO_PIN3)
+#define GPIO_TIM2_CH2IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTC | 
GPIO_PIN5)
+#define GPIO_TIM2_CH2OUT_1    (GPIO_ALT | GPIO_AF3 | GPIO_PORTA | GPIO_PIN1)
+#define GPIO_TIM2_CH2OUT_2    (GPIO_ALT | GPIO_AF6 | GPIO_PORTB | GPIO_PIN3)
+#define GPIO_TIM2_CH2OUT_3    (GPIO_ALT | GPIO_AF3 | GPIO_PORTC | GPIO_PIN5)
+#define GPIO_TIM2_CH3IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF6 | GPIO_PORTA | 
GPIO_PIN2)
+#define GPIO_TIM2_CH3IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTB | 
GPIO_PIN10)
+#define GPIO_TIM2_CH3IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTC | 
GPIO_PIN6)
+#define GPIO_TIM2_CH3OUT_1    (GPIO_ALT | GPIO_AF6 | GPIO_PORTA | GPIO_PIN2)
+#define GPIO_TIM2_CH3OUT_2    (GPIO_ALT | GPIO_AF3 | GPIO_PORTB | GPIO_PIN10)
+#define GPIO_TIM2_CH3OUT_3    (GPIO_ALT | GPIO_AF3 | GPIO_PORTC | GPIO_PIN6)
+#define GPIO_TIM2_CH4IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTA | 
GPIO_PIN3)
+#define GPIO_TIM2_CH4IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTB | 
GPIO_PIN11)
+#define GPIO_TIM2_CH4IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTC | 
GPIO_PIN7)
+#define GPIO_TIM2_CH4OUT_1    (GPIO_ALT | GPIO_AF3 | GPIO_PORTA | GPIO_PIN3)
+#define GPIO_TIM2_CH4OUT_2    (GPIO_ALT | GPIO_AF3 | GPIO_PORTB | GPIO_PIN11)
+#define GPIO_TIM2_CH4OUT_3    (GPIO_ALT | GPIO_AF3 | GPIO_PORTC | GPIO_PIN7)
+
+/* TIM3 */
+
+#define GPIO_TIM3_CH1IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTA | 
GPIO_PIN6)
+#define GPIO_TIM3_CH1IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTB | 
GPIO_PIN4)
+#define GPIO_TIM3_CH1IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF12 | GPIO_PORTB 
| GPIO_PIN6)
+#define GPIO_TIM3_CH1IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF11 | GPIO_PORTB 
| GPIO_PIN7)
+#define GPIO_TIM3_CH1IN_5     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTB | 
GPIO_PIN8)
+#define GPIO_TIM3_CH1IN_6     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTC | 
GPIO_PIN6)
+#define GPIO_TIM3_CH1OUT_1    (GPIO_ALT | GPIO_AF1 | GPIO_PORTA | GPIO_PIN6)
+#define GPIO_TIM3_CH1OUT_2    (GPIO_ALT | GPIO_AF1 | GPIO_PORTB | GPIO_PIN4)
+#define GPIO_TIM3_CH1OUT_3    (GPIO_ALT | GPIO_AF12 | GPIO_PORTB | GPIO_PIN6)
+#define GPIO_TIM3_CH1OUT_4    (GPIO_ALT | GPIO_AF11 | GPIO_PORTB | GPIO_PIN7)
+#define GPIO_TIM3_CH1OUT_5    (GPIO_ALT | GPIO_AF3 | GPIO_PORTB | GPIO_PIN8)
+#define GPIO_TIM3_CH1OUT_6    (GPIO_ALT | GPIO_AF1 | GPIO_PORTC | GPIO_PIN6)
+#define GPIO_TIM3_CH2IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTA | 
GPIO_PIN7)
+#define GPIO_TIM3_CH2IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTB | 
GPIO_PIN3)
+#define GPIO_TIM3_CH2IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTB | 
GPIO_PIN5)
+#define GPIO_TIM3_CH2IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF13 | GPIO_PORTB 
| GPIO_PIN6)
+#define GPIO_TIM3_CH2IN_5     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTB | 
GPIO_PIN9)
+#define GPIO_TIM3_CH2IN_6     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTC | 
GPIO_PIN7)
+#define GPIO_TIM3_CH2IN_7     (GPIO_ALT | GPIO_FLOAT | GPIO_AF11 | GPIO_PORTC 
| GPIO_PIN14)
+#define GPIO_TIM3_CH2OUT_1    (GPIO_ALT | GPIO_AF1 | GPIO_PORTA | GPIO_PIN7)
+#define GPIO_TIM3_CH2OUT_2    (GPIO_ALT | GPIO_AF3 | GPIO_PORTB | GPIO_PIN3)
+#define GPIO_TIM3_CH2OUT_3    (GPIO_ALT | GPIO_AF1 | GPIO_PORTB | GPIO_PIN5)
+#define GPIO_TIM3_CH2OUT_4    (GPIO_ALT | GPIO_AF13 | GPIO_PORTB | GPIO_PIN6)
+#define GPIO_TIM3_CH2OUT_5    (GPIO_ALT | GPIO_AF3 | GPIO_PORTB | GPIO_PIN9)
+#define GPIO_TIM3_CH2OUT_6    (GPIO_ALT | GPIO_AF1 | GPIO_PORTC | GPIO_PIN7)
+#define GPIO_TIM3_CH2OUT_7    (GPIO_ALT | GPIO_AF11 | GPIO_PORTC | GPIO_PIN14)
+#define GPIO_TIM3_CH3IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF11 | GPIO_PORTA 
| GPIO_PIN8)
+#define GPIO_TIM3_CH3IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTB | 
GPIO_PIN0)
+#define GPIO_TIM3_CH3IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTB | 
GPIO_PIN5)
+#define GPIO_TIM3_CH3IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTB | 
GPIO_PIN6)
+#define GPIO_TIM3_CH3IN_5     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTC | 
GPIO_PIN8)
+#define GPIO_TIM3_CH3IN_6     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTC | 
GPIO_PIN15)
+#define GPIO_TIM3_CH3OUT_1    (GPIO_ALT | GPIO_AF11 | GPIO_PORTA | GPIO_PIN8)
+#define GPIO_TIM3_CH3OUT_2    (GPIO_ALT | GPIO_AF1 | GPIO_PORTB | GPIO_PIN0)
+#define GPIO_TIM3_CH3OUT_3    (GPIO_ALT | GPIO_AF3 | GPIO_PORTB | GPIO_PIN5)
+#define GPIO_TIM3_CH3OUT_4    (GPIO_ALT | GPIO_AF3 | GPIO_PORTB | GPIO_PIN6)
+#define GPIO_TIM3_CH3OUT_5    (GPIO_ALT | GPIO_AF1 | GPIO_PORTC | GPIO_PIN8)
+#define GPIO_TIM3_CH3OUT_6    (GPIO_ALT | GPIO_AF3 | GPIO_PORTC | GPIO_PIN15)
+#define GPIO_TIM3_CH4IN_1     (GPIO_ALT | GPIO_FLOAT | GPIO_AF12 | GPIO_PORTA 
| GPIO_PIN8)
+#define GPIO_TIM3_CH4IN_2     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTB | 
GPIO_PIN1)
+#define GPIO_TIM3_CH4IN_3     (GPIO_ALT | GPIO_FLOAT | GPIO_AF3 | GPIO_PORTB | 
GPIO_PIN7)
+#define GPIO_TIM3_CH4IN_4     (GPIO_ALT | GPIO_FLOAT | GPIO_AF1 | GPIO_PORTC | 
GPIO_PIN9)
+#define GPIO_TIM3_CH4OUT_1    (GPIO_ALT | GPIO_AF12 | GPIO_PORTA | GPIO_PIN8)
+#define GPIO_TIM3_CH4OUT_2    (GPIO_ALT | GPIO_AF1 | GPIO_PORTB | GPIO_PIN1)
+#define GPIO_TIM3_CH4OUT_3    (GPIO_ALT | GPIO_AF3 | GPIO_PORTB | GPIO_PIN7)
+#define GPIO_TIM3_CH4OUT_4    (GPIO_ALT | GPIO_AF1 | GPIO_PORTC | GPIO_PIN9)
+
+/* TIM14 */
+
+#define GPIO_TIM14_CH1IN_1    (GPIO_ALT | GPIO_FLOAT | GPIO_AF4 | GPIO_PORTA | 
GPIO_PIN4)
+#define GPIO_TIM14_CH1IN_2    (GPIO_ALT | GPIO_FLOAT | GPIO_AF4 | GPIO_PORTA | 
GPIO_PIN7)
+#define GPIO_TIM14_CH1IN_3    (GPIO_ALT | GPIO_FLOAT | GPIO_AF13 | GPIO_PORTA 
| GPIO_PIN8)
+#define GPIO_TIM14_CH1IN_4    (GPIO_ALT | GPIO_FLOAT | GPIO_AF0 | GPIO_PORTB | 
GPIO_PIN1)
+#define GPIO_TIM14_CH1IN_5    (GPIO_ALT | GPIO_FLOAT | GPIO_AF0 | GPIO_PORTC | 
GPIO_PIN12)
+#define GPIO_TIM14_CH1IN_6    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTF | 
GPIO_PIN0)
+#define GPIO_TIM14_CH1OUT_1   (GPIO_ALT | GPIO_AF4 | GPIO_PORTA | GPIO_PIN4)
+#define GPIO_TIM14_CH1OUT_2   (GPIO_ALT | GPIO_AF4 | GPIO_PORTA | GPIO_PIN7)
+#define GPIO_TIM14_CH1OUT_3   (GPIO_ALT | GPIO_AF13 | GPIO_PORTA | GPIO_PIN8)
+#define GPIO_TIM14_CH1OUT_4   (GPIO_ALT | GPIO_AF0 | GPIO_PORTB | GPIO_PIN1)
+#define GPIO_TIM14_CH1OUT_5   (GPIO_ALT | GPIO_AF0 | GPIO_PORTC | GPIO_PIN12)
+#define GPIO_TIM14_CH1OUT_6   (GPIO_ALT | GPIO_AF2 | GPIO_PORTF | GPIO_PIN0)
+
+/* TIM15 */
+
+#define GPIO_TIM15_BKIN_1     (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN9)
+#define GPIO_TIM15_BKIN_2     (GPIO_ALT | GPIO_AF5 | GPIO_PORTB | GPIO_PIN8)
+#define GPIO_TIM15_BKIN_3     (GPIO_ALT | GPIO_AF5 | GPIO_PORTB | GPIO_PIN12)
+#define GPIO_TIM15_BKIN_4     (GPIO_ALT | GPIO_AF4 | GPIO_PORTC | GPIO_PIN15)
+#define GPIO_TIM15_CH1IN_1    (GPIO_ALT | GPIO_FLOAT | GPIO_AF8 | GPIO_PORTA | 
GPIO_PIN2)
+#define GPIO_TIM15_CH1IN_2    (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTB | 
GPIO_PIN14)
+#define GPIO_TIM15_CH1IN_3    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTC | 
GPIO_PIN1)
+#define GPIO_TIM15_CH1OUT_1   (GPIO_ALT | GPIO_AF8 | GPIO_PORTA | GPIO_PIN2)
+#define GPIO_TIM15_CH1OUT_2   (GPIO_ALT | GPIO_AF5 | GPIO_PORTB | GPIO_PIN14)
+#define GPIO_TIM15_CH1OUT_3   (GPIO_ALT | GPIO_AF2 | GPIO_PORTC | GPIO_PIN1)
+#define GPIO_TIM15_CH1NOUT_1  (GPIO_ALT | GPIO_AF8 | GPIO_PORTA | GPIO_PIN1)
+#define GPIO_TIM15_CH1NOUT_2  (GPIO_ALT | GPIO_AF5 | GPIO_PORTB | GPIO_PIN13)
+#define GPIO_TIM15_CH1NOUT_3  (GPIO_ALT | GPIO_AF4 | GPIO_PORTB | GPIO_PIN15)
+#define GPIO_TIM15_CH1NOUT_4  (GPIO_ALT | GPIO_AF2 | GPIO_PORTF | GPIO_PIN1)
+#define GPIO_TIM15_CH2IN_1    (GPIO_ALT | GPIO_FLOAT | GPIO_AF8 | GPIO_PORTA | 
GPIO_PIN3)
+#define GPIO_TIM15_CH2IN_2    (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTB | 
GPIO_PIN15)
+#define GPIO_TIM15_CH2IN_3    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTC | 
GPIO_PIN2)
+#define GPIO_TIM15_CH2OUT_1   (GPIO_ALT | GPIO_AF8 | GPIO_PORTA | GPIO_PIN3)
+#define GPIO_TIM15_CH2OUT_2   (GPIO_ALT | GPIO_AF5 | GPIO_PORTB | GPIO_PIN15)
+#define GPIO_TIM15_CH2OUT_3   (GPIO_ALT | GPIO_AF2 | GPIO_PORTC | GPIO_PIN2)
+
+/* TIM16 */
+
+#define GPIO_TIM16_BKIN_1     (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN5)
+#define GPIO_TIM16_BKIN_2     GPIO_ALT | GPIO_AF14 | GPIO_PORTB | GPIO_PIN6)
+#define GPIO_TIM16_CH1IN_1    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTA | 
GPIO_PIN0)
+#define GPIO_TIM16_CH1IN_2    (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTA | 
GPIO_PIN6)
+#define GPIO_TIM16_CH1IN_3    (GPIO_ALT | GPIO_FLOAT | GPIO_AF10 | GPIO_PORTB 
| GPIO_PIN7)
+#define GPIO_TIM16_CH1IN_4    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTB | 
GPIO_PIN8)
+#define GPIO_TIM16_CH1IN_5    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTD | 
GPIO_PIN0)
+#define GPIO_TIM16_CH1OUT_1   (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN0)
+#define GPIO_TIM16_CH1OUT_2   (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN6)
+#define GPIO_TIM16_CH1OUT_3   (GPIO_ALT | GPIO_AF10 | GPIO_PORTB | GPIO_PIN7)
+#define GPIO_TIM16_CH1OUT_4   (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN8)
+#define GPIO_TIM16_CH1OUT_5   (GPIO_ALT | GPIO_AF2 | GPIO_PORTD | GPIO_PIN0)
+#define GPIO_TIM16_CH1NOUT_1  (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN2)
+#define GPIO_TIM16_CH1NOUT_2  (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN6)
+
+/* TIM17 */
+
+#define GPIO_TIM17_BKIN_1     (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN10)
+#define GPIO_TIM17_BKIN_2     (GPIO_ALT | GPIO_AF5 | GPIO_PORTB | GPIO_PIN4)
+#define GPIO_TIM17_CH1IN_1    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTA | 
GPIO_PIN1)
+#define GPIO_TIM17_CH1IN_2    (GPIO_ALT | GPIO_FLOAT | GPIO_AF5 | GPIO_PORTA | 
GPIO_PIN7)
+#define GPIO_TIM17_CH1IN_3    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTB | 
GPIO_PIN9)
+#define GPIO_TIM17_CH1IN_4    (GPIO_ALT | GPIO_FLOAT | GPIO_AF10 | GPIO_PORTC 
| GPIO_PIN14)
+#define GPIO_TIM17_CH1IN_5    (GPIO_ALT | GPIO_FLOAT | GPIO_AF2 | GPIO_PORTD | 
GPIO_PIN1)
+#define GPIO_TIM17_CH1OUT_1   (GPIO_ALT | GPIO_AF2 | GPIO_PORTA | GPIO_PIN1)
+#define GPIO_TIM17_CH1OUT_2   (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN7)
+#define GPIO_TIM17_CH1OUT_3   (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN9)
+#define GPIO_TIM17_CH1OUT_4   (GPIO_ALT | GPIO_AF10 | GPIO_PORTC | GPIO_PIN14)
+#define GPIO_TIM17_CH1OUT_5   (GPIO_ALT | GPIO_AF2 | GPIO_PORTD | GPIO_PIN1)
+#define GPIO_TIM17_CH1NOUT_1  (GPIO_ALT | GPIO_AF5 | GPIO_PORTA | GPIO_PIN4)
+#define GPIO_TIM17_CH1NOUT_2  (GPIO_ALT | GPIO_AF2 | GPIO_PORTB | GPIO_PIN7)
 
 #endif /* __ARCH_ARM_SRC_STM32F0L0G0_HARDWARE_STM32C0_PINMAP_H */
diff --git a/arch/arm/src/stm32f0l0g0/stm32_qencoder.c 
b/arch/arm/src/stm32f0l0g0/stm32_qencoder.c
new file mode 100644
index 00000000000..8f09d5596fb
--- /dev/null
+++ b/arch/arm/src/stm32f0l0g0/stm32_qencoder.c
@@ -0,0 +1,1254 @@
+/****************************************************************************
+ * arch/arm/src/stm32f0l0g0/stm32_qencoder.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/sensors/qencoder.h>
+
+#include <arch/board/board.h>
+
+#include "chip.h"
+#include "arm_internal.h"
+#include "stm32.h"
+#include "stm32_gpio.h"
+#include "stm32_tim.h"
+#include "stm32_qencoder.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Timers *******************************************************************/
+
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+#  undef HAVE_32BIT_TIMERS
+#  undef HAVE_16BIT_TIMERS
+
+/* If TIM2 is enabled and is 32-bit, then we have 32-bit timers */
+
+#  if defined(CONFIG_STM32F0L0G0_TIM2_QE) && defined(HAVE_TIM2_32BIT)
+#    define HAVE_32BIT_TIMERS   1
+#  endif
+
+/* If TIM1, TIM2 (16-bit variant), TIM3, or TIM4 are enabled, we have
+ * 16-bit timers
+ */
+
+#  if defined(CONFIG_STM32F0L0G0_TIM1_QE) || 
defined(CONFIG_STM32F0L0G0_TIM3_QE) || \
+      defined(CONFIG_STM32F0L0G0_TIM4_QE) || \
+      (defined(CONFIG_STM32F0L0G0_TIM2_QE) && defined(HAVE_TIM2_16BIT))
+#    define HAVE_16BIT_TIMERS   1
+#  endif
+
+/* The width in bits of each timer */
+
+#  define TIM1_BITWIDTH         16
+#  ifdef HAVE_TIM2_16BIT
+#    define TIM2_BITWIDTH       16
+#  else
+#    define TIM2_BITWIDTH       32
+#  endif
+#  define TIM3_BITWIDTH         16
+#  define TIM4_BITWIDTH         16
+
+/* Do we need to support mixed 16- and 32-bit timers */
+
+#  undef HAVE_MIXEDWIDTH_TIMERS
+#  if defined(HAVE_16BIT_TIMERS) && defined(HAVE_32BIT_TIMERS)
+#    define HAVE_MIXEDWIDTH_TIMERS 1
+#  endif
+#endif
+
+/* Input filter *************************************************************/
+
+#ifdef CONFIG_STM32F0L0G0_QENCODER_FILTER
+#  if defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_FDTS)
+#    if defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_1)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_NOFILT
+#    endif
+#  elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_CKINT)
+#    if defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_2)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FCKINT2
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_4)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FCKINT4
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_8)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FCKINT8
+#    endif
+#  elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_FDTS_2)
+#    if defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_6)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd26
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_8)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd28
+#    endif
+#  elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_FDTS_4)
+#    if defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_6)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd46
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_8)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd48
+#    endif
+#  elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_FDTS_8)
+#    if defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_6)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd86
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_8)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd88
+#    endif
+#  elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_FDTS_16)
+#    if defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_5)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd165
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_6)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd166
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_8)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd168
+#    endif
+#  elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_FDTS_32)
+#    if defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_5)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd325
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_6)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd326
+#    elif defined(CONFIG_STM32F0L0G0_QENCODER_SAMPLE_EVENT_8)
+#      define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_FDTSd328
+#    endif
+#  endif
+
+#  ifndef STM32F0L0G0_QENCODER_ICF
+#    warning "Invalid encoder filter combination, filter disabled"
+#  endif
+#endif
+
+#ifndef STM32F0L0G0_QENCODER_ICF
+#  define STM32F0L0G0_QENCODER_ICF GTIM_CCMR_ICF_NOFILT
+#endif
+
+#define STM32F0L0G0_GPIO_INPUT_FLOAT (GPIO_INPUT | GPIO_FLOAT)
+
+/* Debug ********************************************************************/
+
+/* Non-standard debug that may be enabled just for testing the quadrature
+ * encoder
+ */
+
+#ifndef CONFIG_DEBUG_FEATURES
+#  undef CONFIG_DEBUG_SENSORS
+#endif
+
+#ifdef CONFIG_DEBUG_SENSORS
+#  ifdef CONFIG_DEBUG_INFO
+#    define qe_dumpgpio(p,m)    stm32_dumpgpio(p,m)
+#  else
+#    define qe_dumpgpio(p,m)
+#  endif
+#else
+#  define qe_dumpgpio(p,m)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Constant configuration structure that is retained in FLASH */
+
+struct stm32_qeconfig_s
+{
+  uint8_t  timid;   /* Timer ID {1,2,3,4,5,8} */
+  uint8_t  irq;     /* Timer update IRQ */
+#ifdef HAVE_MIXEDWIDTH_TIMERS
+  uint8_t  width;   /* Timer width (16- or 32-bits) */
+#endif
+  uint32_t ti1cfg;  /* TI1 input pin configuration (20-bit encoding) */
+  uint32_t ti2cfg;  /* TI2 input pin configuration (20-bit encoding) */
+  uint32_t base;    /* Register base address */
+  uint32_t psc;     /* Encoder pulses prescaler */
+};
+
+/* Overall, RAM-based state structure */
+
+struct stm32_lowerhalf_s
+{
+  /* The first field of this state structure must be a pointer to the lower-
+   * half callback structure:
+   */
+
+  const struct qe_ops_s *ops;
+
+  /* STM32 driver-specific fields: */
+
+  const struct stm32_qeconfig_s *config;
+
+  bool             inuse;        /* True: The lower-half driver is in-use */
+
+#ifdef CONFIG_STM32F0L0G0_QENCODER_INDEX_PIN
+  uint32_t         index_pin;    /* Index pin GPIO */
+  bool             index_use;    /* True: Index pin is configured */
+  int32_t          index_offset; /* Index pin offset */
+#endif
+
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+  volatile int32_t position;      /* The current position offset */
+#endif
+  spinlock_t       lock;          /* Spinlock */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Helper functions */
+
+static uint16_t stm32_getreg16(struct stm32_lowerhalf_s *priv, int offset);
+static void stm32_putreg16(struct stm32_lowerhalf_s *priv, int offset,
+                           uint16_t value);
+static uint32_t stm32_getreg32(struct stm32_lowerhalf_s *priv, int offset);
+static void stm32_putreg32(struct stm32_lowerhalf_s *priv, int offset,
+                           uint32_t value);
+
+#if defined(CONFIG_DEBUG_SENSORS) && defined(CONFIG_DEBUG_INFO)
+static void stm32_dumpregs(struct stm32_lowerhalf_s *priv,
+                           const char *msg);
+#else
+#  define stm32_dumpregs(priv, msg)
+#endif
+
+static struct stm32_lowerhalf_s *stm32_tim2lower(int tim);
+
+/* Interrupt handling */
+
+#ifdef CONFIG_STM32F0L0G0_QENCODER_INDEX_PIN
+static int stm32_qe_index_irq(int irq, void *context, void *arg);
+#endif
+
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+static int stm32_interrupt(int irq, void *context, void *arg);
+#endif
+
+/* Lower-half Quadrature Encoder Driver Methods */
+
+static int stm32_setup(struct qe_lowerhalf_s *lower);
+static int stm32_shutdown(struct qe_lowerhalf_s *lower);
+static int stm32_position(struct qe_lowerhalf_s *lower, int32_t *pos);
+static int stm32_setposmax(struct qe_lowerhalf_s *lower, uint32_t pos);
+static int stm32_reset(struct qe_lowerhalf_s *lower);
+static int stm32_setindex(struct qe_lowerhalf_s *lower, uint32_t pos);
+static int stm32_ioctl(struct qe_lowerhalf_s *lower, int cmd,
+                       unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The lower half callback structure */
+
+static const struct qe_ops_s g_qecallbacks =
+{
+  .setup     = stm32_setup,
+  .shutdown  = stm32_shutdown,
+  .position  = stm32_position,
+  .setposmax = stm32_setposmax,
+  .reset     = stm32_reset,
+  .setindex  = stm32_setindex,
+  .ioctl     = stm32_ioctl,
+};
+
+/* Per-timer state structures */
+
+#ifdef CONFIG_STM32F0L0G0_TIM1_QE
+static const struct stm32_qeconfig_s g_tim1config =
+{
+  .timid    = 1,
+  .irq      = STM32_IRQ_TIM1_BRK,
+#ifdef HAVE_MIXEDWIDTH_TIMERS
+  .width    = TIM1_BITWIDTH,
+#endif
+  .base     = STM32_TIM1_BASE,
+  .psc      = CONFIG_STM32F0L0G0_TIM1_QEPSC,
+  .ti1cfg   = GPIO_TIM1_CH1IN,
+  .ti2cfg   = GPIO_TIM1_CH2IN,
+};
+
+static struct stm32_lowerhalf_s g_tim1lower =
+{
+  .ops      = &g_qecallbacks,
+  .config   = &g_tim1config,
+  .inuse    = false,
+  .lock     = SP_UNLOCKED,
+};
+
+#endif
+
+#ifdef CONFIG_STM32F0L0G0_TIM2_QE
+static const struct stm32_qeconfig_s g_tim2config =
+{
+  .timid    = 2,
+  .irq      = STM32_IRQ_TIM2,
+#ifdef HAVE_MIXEDWIDTH_TIMERS
+  .width    = TIM2_BITWIDTH,
+#endif
+  .base     = STM32_TIM2_BASE,
+  .psc      = CONFIG_STM32F0L0G0_TIM2_QEPSC,
+  .ti1cfg   = GPIO_TIM2_CH1IN,
+  .ti2cfg   = GPIO_TIM2_CH2IN,
+};
+
+static struct stm32_lowerhalf_s g_tim2lower =
+{
+  .ops      = &g_qecallbacks,
+  .config   = &g_tim2config,
+  .inuse    = false,
+  .lock     = SP_UNLOCKED,
+};
+
+#endif
+
+#ifdef CONFIG_STM32F0L0G0_TIM3_QE
+static const struct stm32_qeconfig_s g_tim3config =
+{
+  .timid    = 3,
+  .irq      = STM32_IRQ_TIM3,
+#ifdef HAVE_MIXEDWIDTH_TIMERS
+  .width    = TIM3_BITWIDTH,
+#endif
+  .base     = STM32_TIM3_BASE,
+  .psc      = CONFIG_STM32F0L0G0_TIM3_QEPSC,
+  .ti1cfg   = GPIO_TIM3_CH1IN,
+  .ti2cfg   = GPIO_TIM3_CH2IN,
+};
+
+static struct stm32_lowerhalf_s g_tim3lower =
+{
+  .ops      = &g_qecallbacks,
+  .config   = &g_tim3config,
+  .inuse    = false,
+  .lock     = SP_UNLOCKED,
+};
+
+#endif
+
+#ifdef CONFIG_STM32F0L0G0_TIM4_QE
+static const struct stm32_qeconfig_s g_tim4config =
+{
+  .timid    = 4,
+  .irq      = STM32_IRQ_TIM4,
+#ifdef HAVE_MIXEDWIDTH_TIMERS
+  .width    = TIM4_BITWIDTH,
+#endif
+  .base     = STM32_TIM4_BASE,
+  .psc      = CONFIG_STM32F0L0G0_TIM4_QEPSC,
+  .ti1cfg   = GPIO_TIM4_CH1IN,
+  .ti2cfg   = GPIO_TIM4_CH2IN,
+};
+
+static struct stm32_lowerhalf_s g_tim4lower =
+{
+  .ops      = &g_qecallbacks,
+  .config   = &g_tim4config,
+  .inuse    = false,
+  .lock     = SP_UNLOCKED,
+};
+
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_getreg16
+ *
+ * Description:
+ *   Read the value of a 16-bit timer register.
+ *
+ * Input Parameters:
+ *   priv - A reference to the lower half status
+ *   offset - The offset to the register to read
+ *
+ * Returned Value:
+ *   The current contents of the specified register
+ *
+ ****************************************************************************/
+
+static uint16_t stm32_getreg16(struct stm32_lowerhalf_s *priv, int offset)
+{
+  return getreg16(priv->config->base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_putreg16
+ *
+ * Description:
+ *   Write a value to a 16-bit timer register.
+ *
+ * Input Parameters:
+ *   priv - A reference to the lower half status
+ *   offset - The offset to the register to read
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void stm32_putreg16(struct stm32_lowerhalf_s *priv, int offset,
+                           uint16_t value)
+{
+  putreg16(value, priv->config->base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_getreg32
+ *
+ * Description:
+ *   Read the value of a 32-bit timer register.
+ *   This applies only for the STM32 F4 32-bit registers (CNT, ARR, CRR1-4)
+ *   in the 32-bit timers TIM2-5 (but works OK with the 16-bit TIM1,8
+ *   and F1 registers as well).
+ *
+ * Input Parameters:
+ *   priv - A reference to the lower half status
+ *   offset - The offset to the register to read
+ *
+ * Returned Value:
+ *   The current contents of the specified register
+ *
+ ****************************************************************************/
+
+static uint32_t stm32_getreg32(struct stm32_lowerhalf_s *priv, int offset)
+{
+  return getreg32(priv->config->base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_putreg16
+ *
+ * Description:
+ *   Write a value to a 32-bit timer register.
+ *   This applies only for the STM32 F4 32-bit registers (CNT, ARR, CRR1-4)
+ *   in the 32-bit timers TIM2-5 (but works OK with the 16-bit TIM1,8
+ *   and F1 registers).
+ *
+ * Input Parameters:
+ *   priv - A reference to the lower half status
+ *   offset - The offset to the register to read
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void stm32_putreg32(struct stm32_lowerhalf_s *priv, int offset,
+                           uint32_t value)
+{
+  putreg32(value, priv->config->base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_dumpregs
+ *
+ * Description:
+ *   Dump all timer registers.
+ *
+ * Input Parameters:
+ *   priv - A reference to the QENCODER block status
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_DEBUG_SENSORS) && defined(CONFIG_DEBUG_INFO)
+static void stm32_dumpregs(struct stm32_lowerhalf_s *priv,
+                           const char *msg)
+{
+  sninfo("%s:\n", msg);
+  sninfo("  CR1: %04x CR2:  %04x SMCR:  %08" PRIx32 " DIER:  %04x\n",
+         stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET),
+         stm32_getreg16(priv, STM32_GTIM_CR2_OFFSET),
+         stm32_getreg32(priv, STM32_GTIM_SMCR_OFFSET),
+         stm32_getreg16(priv, STM32_GTIM_DIER_OFFSET));
+  sninfo("   SR: %04x EGR:  %04x CCMR1: %08" PRIx32
+         " CCMR2: %08" PRIx32 "\n",
+         stm32_getreg16(priv, STM32_GTIM_SR_OFFSET),
+         stm32_getreg16(priv, STM32_GTIM_EGR_OFFSET),
+         stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET),
+         stm32_getreg32(priv, STM32_GTIM_CCMR2_OFFSET));
+  sninfo(" CCER: %04x CNT:  %08" PRIx32 " PSC:   %04x"
+         " ARR:   %08" PRIx32 "\n",
+         stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET),
+         stm32_getreg32(priv, STM32_GTIM_CNT_OFFSET),
+         stm32_getreg16(priv, STM32_GTIM_PSC_OFFSET),
+         stm32_getreg32(priv, STM32_GTIM_ARR_OFFSET));
+  sninfo(" CCR1: %08" PRIx32 " CCR2: %08" PRIx32 "\n",
+         stm32_getreg32(priv, STM32_GTIM_CCR1_OFFSET),
+         stm32_getreg32(priv, STM32_GTIM_CCR2_OFFSET));
+  sninfo(" CCR3: %08" PRIx32 " CCR4: %08" PRIx32 "\n",
+         stm32_getreg32(priv, STM32_GTIM_CCR3_OFFSET),
+         stm32_getreg32(priv, STM32_GTIM_CCR4_OFFSET));
+#if defined(CONFIG_STM32F0L0G0_TIM1_QE)
+  if (priv->config->timid == 1)
+    {
+      sninfo("  RCR: %04x BDTR: %04x DCR:   %04x DMAR:  %04x\n",
+             stm32_getreg16(priv, STM32_ATIM_RCR_OFFSET),
+             stm32_getreg16(priv, STM32_ATIM_BDTR_OFFSET),
+             stm32_getreg16(priv, STM32_ATIM_DCR_OFFSET),
+             stm32_getreg16(priv, STM32_ATIM_DMAR_OFFSET));
+    }
+  else
+#endif
+    {
+      sninfo("  DCR: %04x DMAR: %04x\n",
+             stm32_getreg16(priv, STM32_GTIM_DCR_OFFSET),
+             stm32_getreg16(priv, STM32_GTIM_DMAR_OFFSET));
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: stm32_tim2lower
+ *
+ * Description:
+ *   Map a timer number to a device structure
+ *
+ ****************************************************************************/
+
+static struct stm32_lowerhalf_s *stm32_tim2lower(int tim)
+{
+  switch (tim)
+    {
+#ifdef CONFIG_STM32F0L0G0_TIM1_QE
+    case 1:
+      return &g_tim1lower;
+#endif
+#ifdef CONFIG_STM32F0L0G0_TIM2_QE
+    case 2:
+      return &g_tim2lower;
+#endif
+#ifdef CONFIG_STM32F0L0G0_TIM3_QE
+    case 3:
+      return &g_tim3lower;
+#endif
+#ifdef CONFIG_STM32F0L0G0_TIM4_QE
+    case 4:
+      return &g_tim4lower;
+#endif
+    default:
+      return NULL;
+    }
+}
+
+/****************************************************************************
+ * Name: stm32_qe_index_irq
+ *
+ * Description:
+ *   Common encoder index pin interrupt.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32F0L0G0_QENCODER_INDEX_PIN
+static int stm32_qe_index_irq(int irq, void *context, void *arg)
+{
+  struct stm32_lowerhalf_s *priv;
+  bool valid = false;
+
+  DEBUGASSERT(arg);
+
+  priv = (struct stm32_lowerhalf_s *)arg;
+
+  valid = stm32_gpioread(priv->index_pin);
+
+  if (valid == true)
+    {
+      stm32_putreg32(priv, STM32_GTIM_CNT_OFFSET, priv->index_offset);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: stm32_interrupt
+ *
+ * Description:
+ *   Common timer interrupt handling.  NOTE: Only 16-bit timers require timer
+ *   interrupts.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+static int stm32_interrupt(int irq, void *context, void *arg)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)arg;
+  uint16_t regval;
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Verify that this is an update interrupt.
+   * Nothing else is expected.
+   */
+
+  regval = stm32_getreg16(priv, STM32_GTIM_SR_OFFSET);
+  DEBUGASSERT((regval & ATIM_SR_UIF) != 0);
+
+  /* Clear the UIF interrupt bit */
+
+  stm32_putreg16(priv, STM32_GTIM_SR_OFFSET, regval & ~GTIM_SR_UIF);
+
+  /* Check the direction bit in the CR1 register and add or subtract the
+   * maximum value, as appropriate.
+   */
+
+  regval = stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET);
+  if ((regval & ATIM_CR1_DIR) != 0)
+    {
+      priv->position -= (int32_t)0x0000ffff;
+    }
+  else
+    {
+      priv->position += (int32_t)0x0000ffff;
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: stm32_setup
+ *
+ * Description:
+ *   This method is called when the driver is opened.  The lower half driver
+ *   should configure and initialize the device so that it is ready for use.
+ *   The initial position value should be zero. *
+ *
+ ****************************************************************************/
+
+static int stm32_setup(struct qe_lowerhalf_s *lower)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  uint16_t dier;
+  uint32_t smcr;
+  uint32_t ccmr1;
+  uint16_t ccer;
+  uint16_t cr1;
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+  uint16_t regval;
+  int ret;
+#endif
+
+  /* NOTE:
+   * Clocking should have been enabled in the low-level RCC logic at boot-up
+   */
+
+  /* Timer base configuration */
+
+  cr1 = stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET);
+
+  /* Clear the direction bit (0=count up) and select the Counter Mode
+   * (0=Edge aligned)
+   * (Timers 2-5 and 1-8 only)
+   */
+
+  cr1 &= ~(GTIM_CR1_DIR | GTIM_CR1_CMS_MASK);
+  stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1);
+
+  /* Set the Autoreload value */
+
+#if defined(HAVE_MIXEDWIDTH_TIMERS)
+  if (priv->config->width == 32)
+    {
+      stm32_putreg32(priv, STM32_GTIM_ARR_OFFSET, 0xffffffff);
+    }
+  else
+    {
+      stm32_putreg16(priv, STM32_GTIM_ARR_OFFSET, 0xffff);
+    }
+#elif defined(HAVE_32BIT_TIMERS)
+  stm32_putreg32(priv, STM32_GTIM_ARR_OFFSET, 0xffffffff);
+#else
+  stm32_putreg16(priv, STM32_GTIM_ARR_OFFSET, 0xffff);
+#endif
+
+  /* Set the timer prescaler value. */
+
+  stm32_putreg16(priv,
+                   STM32_GTIM_PSC_OFFSET, (uint16_t)priv->config->psc);
+
+#if defined(CONFIG_STM32F0L0G0_TIM1_QE)
+  if (priv->config->timid == 1)
+    {
+      /* Clear the Repetition Counter value */
+
+      stm32_putreg16(priv, STM32_ATIM_RCR_OFFSET, 0);
+    }
+#endif
+
+  /* Generate an update event to reload the Prescaler
+   * and the repetition counter (only for TIM1) value immediately
+   */
+
+  stm32_putreg16(priv, STM32_GTIM_EGR_OFFSET, GTIM_EGR_UG);
+
+  /* GPIO pin configuration */
+
+  stm32_configgpio(priv->config->ti1cfg);
+  stm32_configgpio(priv->config->ti2cfg);
+
+  /* Set the encoder Mode 3 */
+
+  smcr = stm32_getreg32(priv, STM32_GTIM_SMCR_OFFSET);
+  smcr &= ~GTIM_SMCR_SMS_MASK;
+  smcr |= GTIM_SMCR_ENCMD3;
+  stm32_putreg32(priv, STM32_GTIM_SMCR_OFFSET, smcr);
+
+  /* TI1 Channel Configuration */
+
+  /* Disable the Channel 1: Reset the CC1E Bit */
+
+  ccer  = stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET);
+  ccer &= ~GTIM_CCER_CC1E;
+  stm32_putreg16(priv, STM32_GTIM_CCER_OFFSET, ccer);
+
+  ccmr1 = stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET);
+  ccer = stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET);
+
+  /* Select the Input IC1=TI1 and set the filter fSAMPLING=fDTS/4, N=6 */
+
+  ccmr1 &= ~(GTIM_CCMR1_CC1S_MASK | GTIM_CCMR1_IC1F_MASK);
+  ccmr1 |= GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR1_CC1S_SHIFT;
+  ccmr1 |= STM32F0L0G0_QENCODER_ICF << GTIM_CCMR1_IC1F_SHIFT;
+
+  /* Select the Polarity=rising and set the CC1E Bit */
+
+  ccer &= ~(GTIM_CCER_CC1P | GTIM_CCER_CC1NP);
+  ccer |= GTIM_CCER_CC1E;
+
+  /* Write to TIM CCMR1 and CCER registers */
+
+  stm32_putreg32(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1);
+  stm32_putreg16(priv, STM32_GTIM_CCER_OFFSET, ccer);
+
+  /* Set the Input Capture Prescaler value: Capture performed each time an
+   * edge is detected on the capture input.
+   */
+
+  ccmr1  = stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET);
+  ccmr1 &= ~GTIM_CCMR1_IC1PSC_MASK;
+  ccmr1 |= (GTIM_CCMR_ICPSC_NOPSC << GTIM_CCMR1_IC1PSC_SHIFT);
+  stm32_putreg32(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1);
+
+  /* TI2 Channel Configuration */
+
+  /* Disable the Channel 2: Reset the CC2E Bit */
+
+  ccer  = stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET);
+  ccer &= ~GTIM_CCER_CC2E;
+  stm32_putreg16(priv, STM32_GTIM_CCER_OFFSET, ccer);
+
+  ccmr1 = stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET);
+  ccer  = stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET);
+
+  /* Select the Input IC2=TI2 and set the filter fSAMPLING=fDTS/4, N=6 */
+
+  ccmr1 &= ~(GTIM_CCMR1_CC2S_MASK | GTIM_CCMR1_IC2F_MASK);
+  ccmr1 |= GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR1_CC2S_SHIFT;
+  ccmr1 |= STM32F0L0G0_QENCODER_ICF << GTIM_CCMR1_IC2F_SHIFT;
+
+  /* Select the Polarity=rising and set the CC2E Bit */
+
+  ccer &= ~(GTIM_CCER_CC2P | GTIM_CCER_CC2NP);
+  ccer |= GTIM_CCER_CC2E;
+
+  /* Write to TIM CCMR1 and CCER registers */
+
+  stm32_putreg32(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1);
+  stm32_putreg16(priv, STM32_GTIM_CCER_OFFSET, ccer);
+
+  /* Set the Input Capture Prescaler value: Capture performed each time an
+   * edge is detected on the capture input.
+   */
+
+  ccmr1  = stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET);
+  ccmr1 &= ~GTIM_CCMR1_IC2PSC_MASK;
+  ccmr1 |= (GTIM_CCMR_ICPSC_NOPSC << GTIM_CCMR1_IC2PSC_SHIFT);
+  stm32_putreg32(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1);
+
+  /* Disable the update interrupt */
+
+  dier = stm32_getreg16(priv, STM32_GTIM_DIER_OFFSET);
+  dier &= ~GTIM_DIER_UIE;
+  stm32_putreg16(priv, STM32_GTIM_DIER_OFFSET, dier);
+
+  /* There is no need for interrupts with 32-bit timers */
+
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+#ifdef HAVE_MIXEDWIDTH_TIMERS
+  if (priv->config->width != 32)
+#endif
+    {
+      /* Attach the interrupt handler */
+
+      ret = irq_attach(priv->config->irq, stm32_interrupt, priv);
+      if (ret < 0)
+        {
+          stm32_shutdown(lower);
+          return ret;
+        }
+
+      /* Enable the update/global interrupt at the NVIC */
+
+      up_enable_irq(priv->config->irq);
+    }
+#endif
+
+  /* Reset the Update Disable Bit */
+
+  cr1 = stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET);
+  cr1 &= ~GTIM_CR1_UDIS;
+  stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1);
+
+  /* Reset the URS Bit */
+
+  cr1 &= ~GTIM_CR1_URS;
+  stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1);
+
+  /* There is no need for interrupts with 32-bit timers */
+
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+#ifdef HAVE_MIXEDWIDTH_TIMERS
+  if (priv->config->width != 32)
+#endif
+    {
+      /* Clear any pending update interrupts */
+
+      regval = stm32_getreg16(priv, STM32_GTIM_SR_OFFSET);
+      stm32_putreg16(priv, STM32_GTIM_SR_OFFSET, regval & ~GTIM_SR_UIF);
+
+      /* Then enable the update interrupt */
+
+      dier = stm32_getreg16(priv, STM32_GTIM_DIER_OFFSET);
+      dier |= GTIM_DIER_UIE;
+      stm32_putreg16(priv, STM32_GTIM_DIER_OFFSET, dier);
+    }
+#endif
+
+#ifdef CONFIG_STM32F0L0G0_QENCODER_INDEX_PIN
+  priv->index_offset = 0;
+#endif
+
+  /* Enable the TIM Counter */
+
+  cr1 = stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET);
+  cr1 |= GTIM_CR1_CEN;
+  stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1);
+
+  stm32_dumpregs(priv, "After setup");
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_shutdown
+ *
+ * Description:
+ *   This method is called when the driver is closed.  The lower half driver
+ *   should stop data collection, free any resources, disable timer hardware,
+ *   and put the system into the lowest possible power usage state *
+ *
+ ****************************************************************************/
+
+static int stm32_shutdown(struct qe_lowerhalf_s *lower)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  irqstate_t flags;
+  uint32_t regaddr;
+  uint32_t regval;
+  uint32_t resetbit;
+  uint32_t pincfg;
+
+  /* Disable the update/global interrupt at the NVIC */
+
+  flags = enter_critical_section();
+  up_disable_irq(priv->config->irq);
+
+  /* Detach the interrupt handler */
+
+  irq_detach(priv->config->irq);
+
+  /* Disable interrupts momentary to stop any ongoing timer processing and
+   * to prevent any concurrent access to the reset register.
+   */
+
+  /* Disable further interrupts and stop the timer */
+
+  stm32_putreg16(priv, STM32_GTIM_DIER_OFFSET, 0);
+  stm32_putreg16(priv, STM32_GTIM_SR_OFFSET, 0);
+
+  /* Determine which timer to reset */
+
+  switch (priv->config->timid)
+    {
+#ifdef CONFIG_STM32F0L0G0_TIM1_QE
+      case 1:
+        regaddr  = STM32_RCC_APB2RSTR;
+        resetbit = RCC_APB2RSTR_TIM1RST;
+        break;
+#endif
+#ifdef CONFIG_STM32F0L0G0_TIM2_QE
+      case 2:
+        regaddr  = STM32_RCC_APB1RSTR;
+        resetbit = RCC_APB1RSTR_TIM2RST;
+        break;
+#endif
+#ifdef CONFIG_STM32F0L0G0_TIM3_QE
+      case 3:
+        regaddr  = STM32_RCC_APB1RSTR;
+        resetbit = RCC_APB1RSTR_TIM3RST;
+        break;
+#endif
+#ifdef CONFIG_STM32F0L0G0_TIM4_QE
+      case 4:
+        regaddr  = STM32_RCC_APB1RSTR;
+        resetbit = RCC_APB1RSTR_TIM4RST;
+        break;
+#endif
+      default:
+        leave_critical_section(flags);
+        return -EINVAL;
+    }
+
+  /* Reset the timer - stopping the output and putting the timer back
+   * into a state where stm32_start() can be called.
+   */
+
+  regval  = getreg32(regaddr);
+  regval |= resetbit;
+  putreg32(regval, regaddr);
+
+  regval &= ~resetbit;
+  putreg32(regval, regaddr);
+  leave_critical_section(flags);
+
+  sninfo("regaddr: %08" PRIx32 " resetbit: %08" PRIx32 "\n",
+         regaddr, resetbit);
+  stm32_dumpregs(priv, "After stop");
+
+  /* Put the TI1 GPIO pin back to its default state */
+
+  pincfg  = priv->config->ti1cfg & (GPIO_PORT_MASK | GPIO_PIN_MASK);
+  pincfg |= STM32F0L0G0_GPIO_INPUT_FLOAT;
+
+  stm32_configgpio(pincfg);
+
+  /* Put the TI2 GPIO pin back to its default state */
+
+  pincfg  = priv->config->ti2cfg & (GPIO_PORT_MASK | GPIO_PIN_MASK);
+  pincfg |= STM32F0L0G0_GPIO_INPUT_FLOAT;
+
+  stm32_configgpio(pincfg);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_position
+ *
+ * Description:
+ *   Return the current position measurement.
+ *
+ ****************************************************************************/
+
+static int stm32_position(struct qe_lowerhalf_s *lower, int32_t *pos)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+  irqstate_t flags;
+  int32_t position;
+  int32_t verify;
+  uint32_t count;
+
+  DEBUGASSERT(lower && priv->inuse);
+
+  /* Loop until we are certain that no interrupt occurred between samples */
+
+  flags = spin_lock_irqsave(&priv->lock);
+  do
+    {
+      position = priv->position;
+      count    = stm32_getreg32(priv, STM32_GTIM_CNT_OFFSET);
+      verify   = priv->position;
+    }
+  while (position != verify);
+  spin_unlock_irqrestore(&priv->lock, flags);
+
+  /* Return the position measurement */
+
+  *pos = position + (int32_t)count;
+#else
+  /* Return the counter value */
+
+  *pos = (int32_t)stm32_getreg32(priv, STM32_GTIM_CNT_OFFSET);
+#endif
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_reset
+ *
+ * Description:
+ *   Reset the position measurement to zero.
+ *
+ ****************************************************************************/
+
+static int stm32_reset(struct qe_lowerhalf_s *lower)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+#ifndef CONFIG_STM32F0L0G0_QENCODER_DISABLE_EXTEND16BTIMERS
+  irqstate_t flags;
+
+  sninfo("Resetting position to zero\n");
+  DEBUGASSERT(lower && priv->inuse);
+
+  /* Reset the timer and the counter.
+   * Interrupts are disabled to make this atomic (if possible)
+   */
+
+  flags = spin_lock_irqsave(&priv->lock);
+  stm32_putreg32(priv, STM32_GTIM_CNT_OFFSET, 0);
+  priv->position = 0;
+  spin_unlock_irqrestore(&priv->lock, flags);
+#else
+  sninfo("Resetting position to zero\n");
+  DEBUGASSERT(lower && priv->inuse);
+
+  /* Reset the counter to zero */
+
+  stm32_putreg32(priv, STM32_GTIM_CNT_OFFSET, 0);
+#endif
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_setposmax
+ *
+ * Description:
+ *   Set the maximum encoder position.
+ *
+ ****************************************************************************/
+
+static int stm32_setposmax(struct qe_lowerhalf_s *lower, uint32_t pos)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+
+  DEBUGASSERT(lower && priv->inuse);
+
+#if defined(HAVE_MIXEDWIDTH_TIMERS)
+  if (priv->config->width == 32)
+    {
+      stm32_putreg32(priv, STM32_GTIM_ARR_OFFSET, pos);
+    }
+  else
+    {
+      stm32_putreg16(priv, STM32_GTIM_ARR_OFFSET, pos);
+    }
+#elif defined(HAVE_32BIT_TIMERS)
+  stm32_putreg32(priv, STM32_GTIM_ARR_OFFSET, pos);
+#else
+  stm32_putreg16(priv, STM32_GTIM_ARR_OFFSET, pos);
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_setindex
+ *
+ * Description:
+ *   Set the index pin position
+ *
+ ****************************************************************************/
+
+static int stm32_setindex(struct qe_lowerhalf_s *lower, uint32_t pos)
+{
+#ifdef CONFIG_STM32F0L0G0_QENCODER_INDEX_PIN
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  int ret = OK;
+
+  sninfo("Set QE TIM%d the index pin position %" PRIx32 "\n",
+         priv->config->timid, pos);
+  DEBUGASSERT(lower && priv->inuse);
+
+  if (priv->index_use == false)
+    {
+      snerr("ERROR: QE TIM%d index not registered\n",
+            priv->config->timid);
+      ret = -EPERM;
+      goto errout;
+    }
+
+  priv->index_offset = pos;
+
+errout:
+  return ret;
+#else
+  return -ENOTTY;
+#endif
+}
+
+/****************************************************************************
+ * Name: stm32_ioctl
+ *
+ * Description:
+ *   Lower-half logic may support platform-specific ioctl commands
+ *
+ ****************************************************************************/
+
+static int stm32_ioctl(struct qe_lowerhalf_s *lower, int cmd,
+                       unsigned long arg)
+{
+  /* No ioctl commands supported */
+
+  /* TODO add an IOCTL to control the encoder pulse count prescaler */
+
+  return -ENOTTY;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_qeinitialize
+ *
+ * Description:
+ *   Initialize a quadrature encoder interface.
+ *   This function must be called from board-specific logic.
+ *
+ * Input Parameters:
+ *   devpath - The full path to the driver to register. E.g., "/dev/qe0"
+ *   tim     - The timer number to used.  'tim' must be an element of
+ *               {1,2,3,4}
+ *
+ * Returned Value:
+ *   Zero on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+int stm32_qeinitialize(const char *devpath, int tim)
+{
+  struct stm32_lowerhalf_s *priv;
+  int ret;
+
+  /* Find the pre-allocated timer state structure corresponding to this
+   * timer
+   */
+
+  priv = stm32_tim2lower(tim);
+  if (!priv)
+    {
+      snerr("ERROR: TIM%d support not configured\n", tim);
+      return -ENXIO;
+    }
+
+  /* Make sure that it is available */
+
+  if (priv->inuse)
+    {
+      snerr("ERROR: TIM%d is in-use\n", tim);
+      return -EBUSY;
+    }
+
+  /* Register the priv-half driver */
+
+  ret = qe_register(devpath, (struct qe_lowerhalf_s *)priv);
+  if (ret < 0)
+    {
+      snerr("ERROR: qe_register failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Make sure that the timer is in the shutdown state */
+
+  stm32_shutdown((struct qe_lowerhalf_s *)priv);
+
+  /* The driver is now in-use */
+
+  priv->inuse = true;
+  return OK;
+}
+
+#ifdef CONFIG_STM32F0L0G0_QENCODER_INDEX_PIN
+/****************************************************************************
+ * Name: stm32_qe_index_init
+ *
+ * Description:
+ *   Register the encoder index pin to a given Qencoder timer
+ *
+ * Input Parameters:
+ *   tim  - The qenco timer number
+ *   gpio - gpio pin configuration
+ *
+ * Returned Value:
+ *   Zero on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+int stm32_qe_index_init(int tim, uint32_t gpio)
+{
+  struct stm32_lowerhalf_s *priv;
+  int ret = OK;
+
+  priv = stm32_tim2lower(tim);
+  if (!priv)
+    {
+      snerr("ERROR: TIM%d support not configured\n", tim);
+      return -ENXIO;
+    }
+
+  if (priv->inuse == false)
+    {
+      snerr("ERROR: TIM%d is not in-use\n", tim);
+      ret = -EINVAL;
+    }
+
+  priv->index_pin = gpio;
+  stm32_configgpio(priv->index_pin);
+
+  ret = stm32_gpiosetevent(gpio, true, false, true,
+                           stm32_qe_index_irq, priv);
+  if (ret < 0)
+    {
+      snerr("ERROR: QE TIM%d failed register irq\n", tim);
+      goto errout;
+    }
+
+  priv->index_use = true;
+
+errout:
+  return ret;
+}
+#endif
diff --git a/arch/arm/src/stm32f0l0g0/stm32_qencoder.h 
b/arch/arm/src/stm32f0l0g0/stm32_qencoder.h
new file mode 100644
index 00000000000..b6f1c4c9d9c
--- /dev/null
+++ b/arch/arm/src/stm32f0l0g0/stm32_qencoder.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+ * arch/arm/src/stm32f0l0g0/stm32_qencoder.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_STM32F0L0G0_STM32_QENCODER_H
+#define __ARCH_ARM_SRC_STM32F0L0G0_STM32_QENCODER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "chip.h"
+
+#ifdef CONFIG_SENSORS_QENCODER
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Timer devices may be used for different purposes.  One special purpose is
+ * as a quadrature encoder input device.  If CONFIG_STM32F0L0G0_TIMn is
+ * defined then the CONFIG_STM32F0L0G0_TIMn_QE must also be defined to
+ * indicate that timer "n" is intended to be used for as a quadrature
+ * encoder.
+ */
+
+#ifndef CONFIG_STM32F0L0G0_TIM1
+#  undef CONFIG_STM32F0L0G0_TIM1_QE
+#endif
+#ifndef CONFIG_STM32F0L0G0_TIM2
+#  undef CONFIG_STM32F0L0G0_TIM2_QE
+#endif
+#ifndef CONFIG_STM32F0L0G0_TIM3
+#  undef CONFIG_STM32F0L0G0_TIM3_QE
+#endif
+#ifndef CONFIG_STM32F0L0G0_TIM4
+#  undef CONFIG_STM32F0L0G0_TIM4_QE
+#endif
+
+/* Only timers 1-4 can be used as a quadrature encoder (timers with
+ * encoder mode support).
+ * TIM6, TIM7, TIM14-17 are basic/general purpose timers without encoder
+ * capability.
+ */
+
+#undef CONFIG_STM32F0L0G0_TIM6_QE
+#undef CONFIG_STM32F0L0G0_TIM7_QE
+#undef CONFIG_STM32F0L0G0_TIM14_QE
+#undef CONFIG_STM32F0L0G0_TIM15_QE
+#undef CONFIG_STM32F0L0G0_TIM16_QE
+#undef CONFIG_STM32F0L0G0_TIM17_QE
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_qeinitialize
+ *
+ * Description:
+ *   Initialize a quadrature encoder interface.
+ *   This function must be called from board-specific logic.
+ *
+ * Input Parameters:
+ *   devpath - The full path to the driver to register. E.g., "/dev/qe0"
+ *   tim     - The timer number to used.
+ *             'tim' must be an element of {1,2,3,4}
+ *
+ * Returned Value:
+ *   Zero on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+int stm32_qeinitialize(const char *devpath, int tim);
+
+#ifdef CONFIG_STM32F0L0G0_QENCODER_INDEX_PIN
+/****************************************************************************
+ * Name: stm32_qe_index_init
+ *
+ * Description:
+ *   Register the encoder index pin to a given Qencoder timer
+ *
+ * Input Parameters:
+ *   tim  - The qenco timer number
+ *   gpio - gpio pin configuration
+ *
+ * Returned Value:
+ *   Zero on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+int stm32_qe_index_init(int tim, uint32_t gpio);
+#endif
+
+#endif /* CONFIG_SENSORS_QENCODER */
+#endif /* __ARCH_ARM_SRC_STM32F0L0G0_STM32_QENCODER_H */

Reply via email to