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

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

commit 5d66f2c973116b54b3a56f7c6a1892863e2d79c9
Author: raiden00pl <raide...@railab.me>
AuthorDate: Mon Apr 7 10:18:23 2025 +0200

    arch/stm32f0l0g0: add support for IWDG and WWDG
    
    add IWDG and WWDG support for stm32f0l0g0.
    
    ported from arch/stm32.
    
    Signed-off-by: raiden00pl <raide...@railab.me>
---
 Documentation/platforms/arm/stm32c0/index.rst      |   4 +-
 Documentation/platforms/arm/stm32f0/index.rst      |   4 +-
 Documentation/platforms/arm/stm32g0/index.rst      |   4 +-
 Documentation/platforms/arm/stm32l0/index.rst      |   4 +-
 arch/arm/src/stm32f0l0g0/CMakeLists.txt            |   9 +
 arch/arm/src/stm32f0l0g0/Make.defs                 |  10 +-
 arch/arm/src/stm32f0l0g0/hardware/stm32_dbgmcu.h   |  80 +++
 arch/arm/src/stm32f0l0g0/hardware/stm32_wdg.h      | 141 +++++
 arch/arm/src/stm32f0l0g0/hardware/stm32c0_pwr.h    |  10 +-
 arch/arm/src/stm32f0l0g0/hardware/stm32f0_pwr.h    |   1 +
 arch/arm/src/stm32f0l0g0/hardware/stm32g0_pwr.h    |   2 +
 arch/arm/src/stm32f0l0g0/hardware/stm32l0_pwr.h    |   1 +
 arch/arm/src/stm32f0l0g0/stm32_iwdg.c              | 593 ++++++++++++++++++
 arch/arm/src/stm32f0l0g0/stm32_lse.c               |   4 +
 .../src/stm32f0l0g0/{stm32_rcc.h => stm32_lsi.c}   |  70 ++-
 arch/arm/src/stm32f0l0g0/stm32_rcc.h               |  20 +
 .../src/stm32f0l0g0/{stm32_rcc.h => stm32_wdg.h}   |  66 +-
 arch/arm/src/stm32f0l0g0/stm32_wwdg.c              | 684 +++++++++++++++++++++
 18 files changed, 1651 insertions(+), 56 deletions(-)

diff --git a/Documentation/platforms/arm/stm32c0/index.rst 
b/Documentation/platforms/arm/stm32c0/index.rst
index 0bdc06f882..ebaa3c2a93 100644
--- a/Documentation/platforms/arm/stm32c0/index.rst
+++ b/Documentation/platforms/arm/stm32c0/index.rst
@@ -35,8 +35,8 @@ CRC         No
 ADC         Yes
 TIM         Yes
 IRTIM       No
-IWDG        No
-WWDG        No
+IWDG        Yes
+WWDG        Yes
 I2C         Yes
 USART       Yes
 SPI         Yes
diff --git a/Documentation/platforms/arm/stm32f0/index.rst 
b/Documentation/platforms/arm/stm32f0/index.rst
index 9849ed5281..401128aa67 100644
--- a/Documentation/platforms/arm/stm32f0/index.rst
+++ b/Documentation/platforms/arm/stm32f0/index.rst
@@ -40,8 +40,8 @@ COMP        No
 TSC         No
 TIM         Yes
 IRTIM       No
-IWDG        No
-WWDG        No
+IWDG        Yes
+WWDG        Yes
 RTC         No
 I2C         Yes
 USART       Yes
diff --git a/Documentation/platforms/arm/stm32g0/index.rst 
b/Documentation/platforms/arm/stm32g0/index.rst
index b7fbd388f6..49d5123400 100644
--- a/Documentation/platforms/arm/stm32g0/index.rst
+++ b/Documentation/platforms/arm/stm32g0/index.rst
@@ -39,8 +39,8 @@ AES         Yes
 TIM         Yes
 LPTIM       No
 IRTIM       No
-IWDG        No
-WWDG        No
+IWDG        Yes
+WWDG        Yes
 RTC         No
 TAMP        No
 I2C         Yes
diff --git a/Documentation/platforms/arm/stm32l0/index.rst 
b/Documentation/platforms/arm/stm32l0/index.rst
index cb5583b8ae..5b4e565901 100644
--- a/Documentation/platforms/arm/stm32l0/index.rst
+++ b/Documentation/platforms/arm/stm32l0/index.rst
@@ -34,8 +34,8 @@ AES         Yes
 RNG         Yes
 TIM         Yes
 LPTIM       No
-IWDG        No
-WWDG        No
+IWDG        Yes
+WWDG        Yes
 RTC         No
 I2C         Yes
 USART       Yes
diff --git a/arch/arm/src/stm32f0l0g0/CMakeLists.txt 
b/arch/arm/src/stm32f0l0g0/CMakeLists.txt
index 0afcf2dd4c..d82a808b28 100644
--- a/arch/arm/src/stm32f0l0g0/CMakeLists.txt
+++ b/arch/arm/src/stm32f0l0g0/CMakeLists.txt
@@ -31,6 +31,7 @@ list(
   stm32_irq.c
   stm32_lowputc.c
   stm32_serial.c
+  stm32_lsi.c
   stm32_rcc.c)
 
 if(CONFIG_STM32F0L0G0_RTC_LSECLOCK OR CONFIG_LCD_LSECLOCK)
@@ -101,4 +102,12 @@ if(CONFIG_STM32F0L0G0_TIM)
   list(APPEND SRCS stm32_tim.c stm32_tim_lowerhalf.c)
 endif()
 
+if(CONFIG_STM32F0L0G0_IWDG)
+  list(APPEND SRCS stm32_iwdg.c)
+endif()
+
+if(CONFIG_STM32F0L0G0_WWDG)
+  list(APPEND SRCS stm32_wwdg.c)
+endif()
+
 target_sources(arch PRIVATE ${SRCS})
diff --git a/arch/arm/src/stm32f0l0g0/Make.defs 
b/arch/arm/src/stm32f0l0g0/Make.defs
index c2e8d049f3..6415a39736 100644
--- a/arch/arm/src/stm32f0l0g0/Make.defs
+++ b/arch/arm/src/stm32f0l0g0/Make.defs
@@ -23,7 +23,7 @@
 include armv6-m/Make.defs
 
 CHIP_CSRCS  = stm32_start.c stm32_gpio.c stm32_exti_gpio.c stm32_irq.c
-CHIP_CSRCS += stm32_lowputc.c stm32_serial.c stm32_rcc.c
+CHIP_CSRCS += stm32_lowputc.c stm32_serial.c stm32_rcc.c stm32_lsi.c
 
 ifneq ($(CONFIG_STM32F0L0G0_RTC_LSECLOCK)$(CONFIG_STM32F0L0G0_LCD_LSECLOCK),)
 CHIP_CSRCS += stm32_lse.c
@@ -92,3 +92,11 @@ endif
 ifeq ($(CONFIG_STM32F0L0G0_TIM),y)
 CHIP_CSRCS += stm32_tim.c stm32_tim_lowerhalf.c
 endif
+
+ifeq ($(CONFIG_STM32F0L0G0_IWDG),y)
+CHIP_CSRCS += stm32_iwdg.c
+endif
+
+ifeq ($(CONFIG_STM32F0L0G0_WWDG),y)
+CHIP_CSRCS += stm32_wwdg.c
+endif
diff --git a/arch/arm/src/stm32f0l0g0/hardware/stm32_dbgmcu.h 
b/arch/arm/src/stm32f0l0g0/hardware/stm32_dbgmcu.h
new file mode 100644
index 0000000000..0e5efadeaf
--- /dev/null
+++ b/arch/arm/src/stm32f0l0g0/hardware/stm32_dbgmcu.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * arch/arm/src/stm32f0l0g0/hardware/stm32_dbgmcu.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_HARDWARE_STM32_DBGMCU_H
+#define __ARCH_ARM_SRC_STM32F0L0G0_HARDWARE_STM32_DBGMCU_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register Offsets *********************************************************/
+
+#define STM32_DBGMCU_IDCODE       0x40015800  /* MCU identifier */
+#define STM32_DBGMCU_CR           0x40015804  /* MCU debug */
+#define STM32_DBGMCU_APB1_FZ      0x40015808  /* Debug MCU APB1 freeze 
register */
+#define STM32_DBGMCU_APB2_FZ      0x4001580c  /* Debug MCU APB2 freeze 
register */
+
+/* Register Bitfield Definitions ********************************************/
+
+/* MCU identifier */
+
+#define DBGMCU_IDCODE_DEVID_SHIFT (0)       /* Bits 11-0: Device Identifier */
+#define DBGMCU_IDCODE_DEVID_MASK  (0x0fff << DBGMCU_IDCODE_DEVID_SHIFT)
+#define DBGMCU_IDCODE_REVID_SHIFT (16)      /* Bits 31-16:  Revision 
Identifier */
+#define DBGMCU_IDCODE_REVID_MASK  (0xffff << DBGMCU_IDCODE_REVID_SHIFT)
+
+/* MCU debug */
+
+#define DBGMCU_CR_SLEEP           (1 << 0)  /* Bit 0: Debug Sleep Mode */
+#define DBGMCU_CR_STOP            (1 << 1)  /* Bit 1: Debug Stop Mode */
+#define DBGMCU_CR_STANDBY         (1 << 2)  /* Bit 2: Debug Standby mode */
+
+/* Debug MCU APB freeze register 1 */
+
+#ifdef CONFIG_ARCH_CHIP_STM32C0
+#  define DBGMCU_APB1_TIM2STOP    (1 << 0)   /* Bit 0: TIM2 stopped when core 
is halted */
+#  define DBGMCU_APB1_TIM3STOP    (1 << 1)   /* Bit 1: TIM3 stopped when core 
is halted */
+#  define DBGMCU_APB1_RTCSTOP     (1 << 10)  /* Bit 10: RTC stopped when core 
is halted */
+#  define DBGMCU_APB1_WWDGSTOP    (1 << 11)  /* Bit 11: WWDG stopped when core 
is halted */
+#  define DBGMCU_APB1_IWDGSTOP    (1 << 12)  /* Bit 12: IWDG stopped when core 
is halted */
+#  define DBGMCU_APB1_I2C1STOP    (1 << 21)  /* Bit 21: SMBUS timeout mode 
stopped when Core is halted  */
+#endif
+
+/* Debug MCU APB freeze register 2 */
+
+#ifdef CONFIG_ARCH_CHIP_STM32C0
+#  define DBGMCU_APB1_TIM1STOP    (1 << 11)   /* Bit 1: TIM1 stopped when core 
is halted */
+#  define DBGMCU_APB1_TIM14STOP   (1 << 15)   /* Bit 15: TIM14 stopped when 
core is halted */
+#  define DBGMCU_APB1_TIM15STOP   (1 << 16)   /* Bit 16: TIM15 stopped when 
core is halted */
+#  define DBGMCU_APB1_TIM16STOP   (1 << 17)   /* Bit 16: TIM16 stopped when 
core is halted */
+#  define DBGMCU_APB1_TIM17STOP   (1 << 18)   /* Bit 16: TIM17 stopped when 
core is halted */
+#endif
+
+#endif /* __ARCH_ARM_SRC_STM32F0L0G0_HARDWARE_STM32_DBGMCU_H */
diff --git a/arch/arm/src/stm32f0l0g0/hardware/stm32_wdg.h 
b/arch/arm/src/stm32f0l0g0/hardware/stm32_wdg.h
new file mode 100644
index 0000000000..824bf9c6a7
--- /dev/null
+++ b/arch/arm/src/stm32f0l0g0/hardware/stm32_wdg.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+ * arch/arm/src/stm32f0l0g0/hardware/stm32_wdg.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_HARDWARE_STM32_WDG_H
+#define __ARCH_ARM_SRC_STM32F0L0G0_HARDWARE_STM32_WDG_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register Offsets *********************************************************/
+
+#define STM32_IWDG_KR_OFFSET     0x0000  /* Key register (32-bit) */
+#define STM32_IWDG_PR_OFFSET     0x0004  /* Prescaler register (32-bit) */
+#define STM32_IWDG_RLR_OFFSET    0x0008  /* Reload register (32-bit) */
+#define STM32_IWDG_SR_OFFSET     0x000c  /* Status register (32-bit) */
+#define STM32_IWDG_WINR_OFFSET   0x000c  /* Window register (32-bit) */
+
+#define STM32_WWDG_CR_OFFSET     0x0000  /* Control Register (32-bit) */
+#define STM32_WWDG_CFR_OFFSET    0x0004  /* Configuration register (32-bit) */
+#define STM32_WWDG_SR_OFFSET     0x0008  /* Status register (32-bit) */
+
+/* Register Addresses *******************************************************/
+
+#define STM32_IWDG_KR            (STM32_IWDG_BASE+STM32_IWDG_KR_OFFSET)
+#define STM32_IWDG_PR            (STM32_IWDG_BASE+STM32_IWDG_PR_OFFSET)
+#define STM32_IWDG_RLR           (STM32_IWDG_BASE+STM32_IWDG_RLR_OFFSET)
+#define STM32_IWDG_SR            (STM32_IWDG_BASE+STM32_IWDG_SR_OFFSET)
+#define STM32_IWDG_WINR          (STM32_IWDG_BASE+STM32_IWDG_WINR_OFFSET)
+
+#define STM32_WWDG_CR            (STM32_WWDG_BASE+STM32_WWDG_CR_OFFSET)
+#define STM32_WWDG_CFR           (STM32_WWDG_BASE+STM32_WWDG_CFR_OFFSET)
+#define STM32_WWDG_SR            (STM32_WWDG_BASE+STM32_WWDG_SR_OFFSET)
+
+/* Register Bitfield Definitions ********************************************/
+
+/* Key register (32-bit) */
+
+#define IWDG_KR_KEY_SHIFT        (0)       /* Bits 15-0: Key value (write 
only, read 0000h) */
+#define IWDG_KR_KEY_MASK         (0xffff << IWDG_KR_KEY_SHIFT)
+
+#define IWDG_KR_KEY_ENABLE       (0x5555)  /* Enable register access */
+#define IWDG_KR_KEY_DISABLE      (0x0000)  /* Disable register access */
+#define IWDG_KR_KEY_RELOAD       (0xaaaa)  /* Reload the counter */
+#define IWDG_KR_KEY_START        (0xcccc)  /* Start the watchdog */
+
+/* Prescaler register (32-bit) */
+
+#define IWDG_PR_SHIFT            (0)       /* Bits 2-0: Prescaler divider */
+#define IWDG_PR_MASK             (7 << IWDG_PR_SHIFT)
+#  define IWDG_PR_DIV4           (0 << IWDG_PR_SHIFT) /* 000: divider /4 */
+#  define IWDG_PR_DIV8           (1 << IWDG_PR_SHIFT) /* 001: divider /8 */
+#  define IWDG_PR_DIV16          (2 << IWDG_PR_SHIFT) /* 010: divider /16 */
+#  define IWDG_PR_DIV32          (3 << IWDG_PR_SHIFT) /* 011: divider /32 */
+#  define IWDG_PR_DIV64          (4 << IWDG_PR_SHIFT) /* 100: divider /64 */
+#  define IWDG_PR_DIV128         (5 << IWDG_PR_SHIFT) /* 101: divider /128 */
+#  define IWDG_PR_DIV256         (6 << IWDG_PR_SHIFT) /* 11x: divider /256 */
+
+/* Reload register (32-bit) */
+
+#define IWDG_RLR_RL_SHIFT        (0)       /* Bits11:0 RL[11:0]: Watchdog 
counter reload value */
+#define IWDG_RLR_RL_MASK         (0x0fff << IWDG_RLR_RL_SHIFT)
+
+#define IWDG_RLR_MAX             (0xfff)
+
+/* Status register (32-bit) */
+
+#define IWDG_SR_PVU              (1 << 0)  /* Bit 0: Watchdog prescaler value 
update */
+#define IWDG_SR_RVU              (1 << 1)  /* Bit 1: Watchdog counter reload 
value update */
+#define IWDG_SR_WVU              (1 << 2)  /* Bit 2:  */
+
+/* Window register (32-bit) */
+
+#define IWDG_WINR_SHIFT          (0)
+#define IWDG_WINR_MASK           (0x0fff << IWDG_WINR_SHIFT)
+
+/* Control Register (32-bit) */
+
+#define WWDG_CR_T_SHIFT          (0)       /* Bits 6:0 T[6:0]: 7-bit counter 
(MSB to LSB) */
+#define WWDG_CR_T_MASK           (0x7f << WWDG_CR_T_SHIFT)
+#  define WWDG_CR_T_MAX          (0x3f << WWDG_CR_T_SHIFT)
+#  define WWDG_CR_T_RESET        (0x40 << WWDG_CR_T_SHIFT)
+#define WWDG_CR_WDGA             (1 << 7)  /* Bit 7: Activation bit */
+
+/* Configuration register (32-bit) */
+
+#define WWDG_CFR_W_SHIFT         (0)       /* Bits 6:0 W[6:0] 7-bit window 
value */
+#define WWDG_CFR_W_MASK          (0x7f << WWDG_CFR_W_SHIFT)
+#define WWDG_CFR_WDGTB_SHIFT     (7)       /* Bits 8:7 [1:0]: Timer Base */
+#define WWDG_CFR_WDGTB_MASK      (3 << WWDG_CFR_WDGTB_SHIFT)
+#  define WWDG_CFR_PCLK1         (0 << WWDG_CFR_WDGTB_SHIFT) /* 00: CK Counter 
Clock (PCLK1 div 4096) div 1 */
+#  define WWDG_CFR_PCLK1d2       (1 << WWDG_CFR_WDGTB_SHIFT) /* 01: CK Counter 
Clock (PCLK1 div 4096) div 2 */
+#  define WWDG_CFR_PCLK1d4       (2 << WWDG_CFR_WDGTB_SHIFT) /* 10: CK Counter 
Clock (PCLK1 div 4096) div 4 */
+#  define WWDG_CFR_PCLK1d8       (3 << WWDG_CFR_WDGTB_SHIFT) /* 11: CK Counter 
Clock (PCLK1 div 4096) div 8 */
+
+#define WWDG_CFR_EWI             (1 << 9)  /* Bit 9: Early Wakeup Interrupt */
+
+/* Status register (32-bit) */
+
+#define WWDG_SR_EWIF             (1 << 0)  /* Bit 0: Early Wakeup Interrupt 
Flag */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+#endif /* __ARCH_ARM_SRC_STM32F0L0G0_HARDWARE_STM32_WDG_H */
diff --git a/arch/arm/src/stm32f0l0g0/hardware/stm32c0_pwr.h 
b/arch/arm/src/stm32f0l0g0/hardware/stm32c0_pwr.h
index 85f4b1658a..db6a6fc3ea 100644
--- a/arch/arm/src/stm32f0l0g0/hardware/stm32c0_pwr.h
+++ b/arch/arm/src/stm32f0l0g0/hardware/stm32c0_pwr.h
@@ -34,6 +34,8 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#undef HAVE_PWR_DBP /* No Disable backup write protection bit */
+
 /* Register Offsets *********************************************************/
 
 #define STM32_PWR_CR1_OFFSET   0x0000  /* Power control register 1 */
@@ -100,17 +102,9 @@
 #  define PWR_CR1_LPMS_STANDBY   (3 << PWR_CR1_LPMS_SHIFT) /* 011: Standby 
mode */
 #  define PWR_CR1_LPMS_SHUTDOWN  (4 << PWR_CR1_LPMS_SHIFT) /* 1xx: Shutdown 
mode */
 
-#define PWR_CR1_FPDSTOP          (1 << 3) /* Bit 3: Flash memory powered down 
during Stop mode */
                                           /* Bit 4: Reserved */
 #define PWR_CR1_FPDLPSLP         (1 << 5) /* Bit 5: Flash memory powered down 
during Low-power sleep mode */
                                           /* Bits 6-31: Reserved */
-#define PWR_CR1_DBP              (1 << 8) /* Bit 8: Disable Backup domain 
write protection */
-#define PWR_CR1_VOS_SHIFT        (9)      /* Bits 9-10: Voltage scaling range 
selection */
-#define PWR_CR1_VOS_MASK         (3 << PWR_CR1_VOS_SHIFT)
-#  define PWR_CR1_VOS_RANGE1     (1 << PWR_CR1_VOS_SHIFT) /* 01: Range 1 */
-#  define PWR_CR1_VOS_RANGE2     (2 << PWR_CR1_VOS_SHIFT) /* 10: Range 2 */
-
-#define PWR_CR1_LPR              (1 << 14) /* Bit 14: Low-power run */
 
 /* Power control register 2 */
 
diff --git a/arch/arm/src/stm32f0l0g0/hardware/stm32f0_pwr.h 
b/arch/arm/src/stm32f0l0g0/hardware/stm32f0_pwr.h
index a2897babc2..64a693f752 100644
--- a/arch/arm/src/stm32f0l0g0/hardware/stm32f0_pwr.h
+++ b/arch/arm/src/stm32f0l0g0/hardware/stm32f0_pwr.h
@@ -34,6 +34,7 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#define HAVE_PWR_DBP         1
 #undef HAVE_PWR_WKUP2
 #undef HAVE_PWR_WKUP3
 
diff --git a/arch/arm/src/stm32f0l0g0/hardware/stm32g0_pwr.h 
b/arch/arm/src/stm32f0l0g0/hardware/stm32g0_pwr.h
index 2965426705..ae226f9fca 100644
--- a/arch/arm/src/stm32f0l0g0/hardware/stm32g0_pwr.h
+++ b/arch/arm/src/stm32f0l0g0/hardware/stm32g0_pwr.h
@@ -34,6 +34,8 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#define HAVE_PWR_DBP           1
+
 /* Register Offsets *********************************************************/
 
 #define STM32_PWR_CR1_OFFSET   0x0000  /* Power control register 1 */
diff --git a/arch/arm/src/stm32f0l0g0/hardware/stm32l0_pwr.h 
b/arch/arm/src/stm32f0l0g0/hardware/stm32l0_pwr.h
index 8d0097a3cb..b5c00fa05e 100644
--- a/arch/arm/src/stm32f0l0g0/hardware/stm32l0_pwr.h
+++ b/arch/arm/src/stm32f0l0g0/hardware/stm32l0_pwr.h
@@ -36,6 +36,7 @@
 
 #define HAVE_PWR_WKUP2         1
 #define HAVE_PWR_WKUP3         1
+#define HAVE_PWR_DBP           1
 
 /* Register Offsets *********************************************************/
 
diff --git a/arch/arm/src/stm32f0l0g0/stm32_iwdg.c 
b/arch/arm/src/stm32f0l0g0/stm32_iwdg.c
new file mode 100644
index 0000000000..ecee26cfb4
--- /dev/null
+++ b/arch/arm/src/stm32f0l0g0/stm32_iwdg.c
@@ -0,0 +1,593 @@
+/****************************************************************************
+ * arch/arm/src/stm32f0l0g0/stm32_iwdg.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 <nuttx/arch.h>
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/timers/watchdog.h>
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "stm32_rcc.h"
+#include "hardware/stm32_dbgmcu.h"
+#include "stm32_wdg.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Clocking *****************************************************************/
+
+/* The minimum frequency of the IWDG clock is:
+ *
+ *  Fmin = Flsi / 256
+ *
+ * So the maximum delay (in milliseconds) is then:
+ *
+ *   1000 * IWDG_RLR_MAX / Fmin
+ *
+ * For example, if Flsi = 30Khz (the nominal, uncalibrated value), then the
+ * maximum delay is:
+ *
+ *   Fmin = 117.1875
+ *   1000 * 4095 / Fmin = 34,944 MSec
+ */
+
+#define IWDG_FMIN       (STM32_LSI_FREQUENCY / 256)
+#define IWDG_MAXTIMEOUT (1000 * IWDG_RLR_MAX / IWDG_FMIN)
+
+/* Configuration ************************************************************/
+
+/* REVISIT:  It appears that you can only setup the prescaler and reload
+ * registers once.  After that, the SR register's PVU and RVU bits never go
+ * to zero.  So we defer setting up these registers until the watchdog
+ * is started, then refuse any further attempts to change timeout.
+ */
+
+#define CONFIG_STM32_IWDG_ONETIMESETUP 1
+
+/* REVISIT:  Another possibility is that we CAN change the prescaler and
+ * reload values after starting the timer.  This option is untested but the
+ * implementation place conditioned on the following:
+ */
+
+#undef CONFIG_STM32_IWDG_DEFERREDSETUP
+
+/* But you can only try one at a time */
+
+#if defined(CONFIG_STM32_IWDG_ONETIMESETUP) && 
defined(CONFIG_STM32_IWDG_DEFERREDSETUP)
+#  error "Both CONFIG_STM32_IWDG_ONETIMESETUP and 
CONFIG_STM32_IWDG_DEFERREDSETUP are defined"
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure provides the private representation of the "lower-half"
+ * driver state structure.  This structure must be cast-compatible with the
+ * well-known watchdog_lowerhalf_s structure.
+ */
+
+struct stm32_lowerhalf_s
+{
+  const struct watchdog_ops_s  *ops; /* Lower half operations */
+  uint32_t lsifreq;                  /* The calibrated frequency of the LSI 
oscillator */
+  uint32_t timeout;                  /* The (actual) selected timeout */
+  uint32_t lastreset;                /* The last reset time */
+  bool     started;                  /* true: The watchdog timer has been 
started */
+  uint8_t  prescaler;                /* Clock prescaler value */
+  uint16_t reload;                   /* Timer reload value */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Register operations ******************************************************/
+
+static inline void stm32_setprescaler(struct stm32_lowerhalf_s *priv);
+
+/* "Lower half" driver methods **********************************************/
+
+static int stm32_start(struct watchdog_lowerhalf_s *lower);
+static int stm32_stop(struct watchdog_lowerhalf_s *lower);
+static int stm32_keepalive(struct watchdog_lowerhalf_s *lower);
+static int stm32_getstatus(struct watchdog_lowerhalf_s *lower,
+                           struct watchdog_status_s *status);
+static int stm32_settimeout(struct watchdog_lowerhalf_s *lower,
+                            uint32_t timeout);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* "Lower half" driver methods */
+
+static const struct watchdog_ops_s g_wdgops =
+{
+  .start      = stm32_start,
+  .stop       = stm32_stop,
+  .keepalive  = stm32_keepalive,
+  .getstatus  = stm32_getstatus,
+  .settimeout = stm32_settimeout,
+  .capture    = NULL,
+  .ioctl      = NULL,
+};
+
+/* "Lower half" driver state */
+
+static struct stm32_lowerhalf_s g_wdgdev;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_setprescaler
+ *
+ * Description:
+ *   Set up the prescaler and reload values.  This seems to be something
+ *   that can only be done one time.
+ *
+ * Input Parameters:
+ *   priv   - A pointer the internal representation of the "lower-half"
+ *             driver state structure.
+ *
+ ****************************************************************************/
+
+static inline void stm32_setprescaler(struct stm32_lowerhalf_s *priv)
+{
+  /* Enable write access to IWDG_PR and IWDG_RLR registers */
+
+  putreg32(IWDG_KR_KEY_ENABLE, STM32_IWDG_KR);
+
+  /* Wait for the PVU and RVU bits to be reset be hardware.  These bits
+   * were set the last time that the PR register was written and may not
+   * yet be cleared.
+   *
+   * If the setup is only permitted one time, then this wait should not
+   * be necessary.
+   */
+
+#ifndef CONFIG_STM32_IWDG_ONETIMESETUP
+  while ((getreg32(STM32_IWDG_SR) & (IWDG_SR_PVU | IWDG_SR_RVU)) != 0);
+#endif
+
+  /* Set the prescaler */
+
+  putreg32((uint16_t)priv->prescaler << IWDG_PR_SHIFT, STM32_IWDG_PR);
+
+  /* Set the reload value */
+
+  putreg32((uint16_t)priv->reload, STM32_IWDG_RLR);
+
+  /* Reload the counter (and disable write access) */
+
+  putreg32(IWDG_KR_KEY_RELOAD, STM32_IWDG_KR);
+}
+
+/****************************************************************************
+ * Name: stm32_start
+ *
+ * Description:
+ *   Start the watchdog timer, resetting the time to the current timeout,
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the
+ *           "lower-half" driver state structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_start(struct watchdog_lowerhalf_s *lower)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  irqstate_t flags;
+
+  wdinfo("Entry: started\n");
+  DEBUGASSERT(priv);
+
+  /* Have we already been started? */
+
+  if (!priv->started)
+    {
+      /* REVISIT: It appears that you can only setup the prescaler and reload
+       * registers once. After that, the SR register's PVU and RVU bits never
+       * go to 0. So we defer setting up these registers until the watchdog
+       * is started, then refuse any further attempts to change timeout.
+       */
+
+      /* Set up prescaler and reload value for the selected timeout before
+       * starting the watchdog timer.
+       */
+
+#if defined(CONFIG_STM32_IWDG_ONETIMESETUP) || 
defined(CONFIG_STM32_IWDG_DEFERREDSETUP)
+      stm32_setprescaler(priv);
+#endif
+
+      /* Enable IWDG (the LSI oscillator will be enabled by hardware).  NOTE:
+       * If the "Hardware watchdog" feature is enabled through the device
+       * option bits, the watchdog is automatically enabled at power-on.
+       */
+
+      flags           = enter_critical_section();
+      putreg32(IWDG_KR_KEY_START, STM32_IWDG_KR);
+      priv->lastreset = clock_systime_ticks();
+      priv->started   = true;
+      leave_critical_section(flags);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_stop
+ *
+ * Description:
+ *   Stop the watchdog timer
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the
+ *           "lower-half" driver state structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_stop(struct watchdog_lowerhalf_s *lower)
+{
+  /* There is no way to disable the IDWG timer once it has been started */
+
+  wdinfo("Entry\n");
+  return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: stm32_keepalive
+ *
+ * Description:
+ *   Reset the watchdog timer to the current timeout value, prevent any
+ *   imminent watchdog timeouts.  This is sometimes referred as "pinging"
+ *   the watchdog timer or "petting the dog".
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the
+ *           "lower-half" driver state structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_keepalive(struct watchdog_lowerhalf_s *lower)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  irqstate_t flags;
+
+  wdinfo("Entry\n");
+
+  /* Reload the IWDG timer */
+
+  flags = enter_critical_section();
+  putreg32(IWDG_KR_KEY_RELOAD, STM32_IWDG_KR);
+  priv->lastreset = clock_systime_ticks();
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_getstatus
+ *
+ * Description:
+ *   Get the current watchdog timer status
+ *
+ * Input Parameters:
+ *   lower  - A pointer the publicly visible representation of the
+ *            "lower-half" driver state structure.
+ *   status - The location to return the watchdog status information.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_getstatus(struct watchdog_lowerhalf_s *lower,
+                           struct watchdog_status_s *status)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  uint32_t ticks;
+  uint32_t elapsed;
+
+  wdinfo("Entry\n");
+  DEBUGASSERT(priv);
+
+  /* Return the status bit */
+
+  status->flags = WDFLAGS_RESET;
+  if (priv->started)
+    {
+      status->flags |= WDFLAGS_ACTIVE;
+    }
+
+  /* Return the actual timeout in milliseconds */
+
+  status->timeout = priv->timeout;
+
+  /* Get the elapsed time since the last ping */
+
+  ticks   = clock_systime_ticks() - priv->lastreset;
+  elapsed = (int32_t)TICK2MSEC(ticks);
+
+  if (elapsed > priv->timeout)
+    {
+      elapsed = priv->timeout;
+    }
+
+  /* Return the approximate time until the watchdog timer expiration */
+
+  status->timeleft = priv->timeout - elapsed;
+
+  wdinfo("Status     :\n");
+  wdinfo("  flags    : %08" PRIx32 "\n", status->flags);
+  wdinfo("  timeout  : %" PRId32 "\n", status->timeout);
+  wdinfo("  timeleft : %" PRId32 "\n", status->timeleft);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_settimeout
+ *
+ * Description:
+ *   Set a new timeout value (and reset the watchdog timer)
+ *
+ * Input Parameters:
+ *   lower   - A pointer the publicly visible representation of the
+ *             "lower-half" driver state structure.
+ *   timeout - The new timeout value in milliseconds.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_settimeout(struct watchdog_lowerhalf_s *lower,
+                            uint32_t timeout)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  uint32_t fiwdg;
+  uint64_t reload;
+  int prescaler;
+  int shift;
+
+  wdinfo("Entry: timeout=%" PRId32 "\n", timeout);
+  DEBUGASSERT(priv);
+
+  /* Can this timeout be represented? */
+
+  if (timeout < 1 || timeout > IWDG_MAXTIMEOUT)
+    {
+      wderr("ERROR: Cannot represent timeout=%" PRId32 " > %d\n",
+            timeout, IWDG_MAXTIMEOUT);
+      return -ERANGE;
+    }
+
+  /* REVISIT:  It appears that you can only setup the prescaler and reload
+   * registers once.  After that, the SR register's PVU and RVU bits never go
+   * to zero.
+   */
+
+#ifdef CONFIG_STM32_IWDG_ONETIMESETUP
+  if (priv->started)
+    {
+      wdwarn("WARNING: Timer is already started\n");
+      return -EBUSY;
+    }
+#endif
+
+  /* Select the smallest prescaler that will result in a reload value that is
+   * less than the maximum.
+   */
+
+  for (prescaler = 0; ; prescaler++)
+    {
+      /* PR = 0 -> Divider = 4   = 1 << 2
+       * PR = 1 -> Divider = 8   = 1 << 3
+       * PR = 2 -> Divider = 16  = 1 << 4
+       * PR = 3 -> Divider = 32  = 1 << 5
+       * PR = 4 -> Divider = 64  = 1 << 6
+       * PR = 5 -> Divider = 128 = 1 << 7
+       * PR = 6 -> Divider = 256 = 1 << 8
+       * PR = n -> Divider       = 1 << (n+2)
+       */
+
+      shift = prescaler + 2;
+
+      /* Get the IWDG counter frequency in Hz. For a nominal 32Khz LSI clock,
+       * this is value in the range of 7500 and 125.
+       */
+
+      fiwdg = priv->lsifreq >> shift;
+
+      /* We want:
+       *  1000 * reload / Fiwdg = timeout
+       * Or:
+       *  reload = Fiwdg * timeout / 1000
+       */
+
+      reload = (uint64_t)fiwdg * (uint64_t)timeout / 1000;
+
+      /* If this reload valid is less than the maximum or we are not ready
+       * at the prescaler value, then break out of the loop to use these
+       * settings.
+       */
+
+      if (reload <= IWDG_RLR_MAX || prescaler == 6)
+        {
+          /* Note that we explicitly break out of the loop rather than using
+           * the 'for' loop termination logic because we do not want the
+           * value of prescaler to be incremented.
+           */
+
+          break;
+        }
+    }
+
+  /* Make sure that the final reload value is within range */
+
+  if (reload > IWDG_RLR_MAX)
+    {
+      reload = IWDG_RLR_MAX;
+    }
+
+  /* Get the actual timeout value in milliseconds.
+   *
+   * We have:
+   *  reload = Fiwdg * timeout / 1000
+   * So we want:
+   *  timeout = 1000 * reload / Fiwdg
+   */
+
+  priv->timeout = (1000 * (uint32_t)reload) / fiwdg;
+
+  /* Save setup values for later use */
+
+  priv->prescaler = prescaler;
+  priv->reload    = reload;
+
+  /* Write the prescaler and reload values to the IWDG registers.
+   *
+   * REVISIT:  It appears that you can only setup the prescaler and reload
+   * registers once.  After that, the SR register's PVU and RVU bits never go
+   * to zero.
+   */
+
+#ifndef CONFIG_STM32_IWDG_ONETIMESETUP
+  /* If CONFIG_STM32_IWDG_DEFERREDSETUP is selected, then perform the
+   * register configuration only if the timer has been started.
+   */
+
+#ifdef CONFIG_STM32_IWDG_DEFERREDSETUP
+  if (priv->started)
+#endif
+    {
+      stm32_setprescaler(priv);
+    }
+#endif
+
+  wdinfo("prescaler=%d fiwdg=%" PRId32 " reload=%" PRId64 "\n",
+         prescaler, fiwdg, reload);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_iwdginitialize
+ *
+ * Description:
+ *   Initialize the IWDG watchdog timer.  The watchdog timer is initialized
+ *   and registers as 'devpath'.  The initial state of the watchdog timer is
+ *   disabled.
+ *
+ * Input Parameters:
+ *   devpath - The full path to the watchdog.  This should be of the form
+ *     /dev/watchdog0
+ *   lsifreq - The calibrated LSI clock frequency
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void stm32_iwdginitialize(const char *devpath, uint32_t lsifreq)
+{
+  struct stm32_lowerhalf_s *priv = &g_wdgdev;
+
+  wdinfo("Entry: devpath=%s lsifreq=%" PRId32 "\n", devpath, lsifreq);
+
+  /* NOTE we assume that clocking to the IWDG has already been provided by
+   * the RCC initialization logic.
+   */
+
+  /* Initialize the driver state structure. */
+
+  priv->ops     = &g_wdgops;
+  priv->lsifreq = lsifreq;
+  priv->started = false;
+
+  /* Make sure that the LSI oscillator is enabled.  NOTE:  The LSI oscillator
+   * is enabled here but is not disabled by this file, because this file does
+   * not know the global usage of the oscillator.  Any clock management
+   * logic (say, as part of a power management scheme) needs handle other
+   * LSI controls outside of this file.
+   */
+
+  stm32_rcc_enablelsi();
+#ifdef STM32_RCC_CSR
+  wdinfo("RCC CSR: %08" PRIx32 "\n", getreg32(STM32_RCC_CSR));
+#else
+  wdinfo("RCC CSR: %08" PRIx32 "\n", getreg32(STM32_RCC_CSR1));
+#endif
+
+  /* Select an arbitrary initial timeout value.  But don't start the watchdog
+   * yet. NOTE: If the "Hardware watchdog" feature is enabled through the
+   * device option bits, the watchdog is automatically enabled at power-on.
+   */
+
+  stm32_settimeout((struct watchdog_lowerhalf_s *)priv, IWDG_MAXTIMEOUT);
+
+  /* Register the watchdog driver as /dev/watchdog0 */
+
+  watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv);
+
+  /* When the microcontroller enters debug mode (core halted),
+   * the IWDG counter either continues to work normally or stops, depending
+   * on DBG_IWDG_STOP configuration bit in DBG module.
+   */
+
+#ifdef CONFIG_DEBUG_FEATURES
+    {
+      uint32_t cr = getreg32(STM32_DBGMCU_APB1_FZ);
+      cr |= DBGMCU_APB1_IWDGSTOP;
+      putreg32(cr, STM32_DBGMCU_APB1_FZ);
+    }
+#endif
+}
diff --git a/arch/arm/src/stm32f0l0g0/stm32_lse.c 
b/arch/arm/src/stm32f0l0g0/stm32_lse.c
index 472bf74045..9fb81ae318 100644
--- a/arch/arm/src/stm32f0l0g0/stm32_lse.c
+++ b/arch/arm/src/stm32f0l0g0/stm32_lse.c
@@ -47,12 +47,14 @@
 
 void stm32_rcc_enablelse(void)
 {
+#ifdef HAVE_PWR_DBP
   /* The LSE is in the RTC domain and write access is denied to this domain
    * after reset, you have to enable write access using DBP bit in the PWR CR
    * register before to configuring the LSE.
    */
 
   stm32_pwr_enablebkp(true);
+#endif
 
 #if defined(CONFIG_ARCH_CHIP_STM32L0)
   /* Enable the External Low-Speed (LSE) oscillator by setting the LSEON bit
@@ -94,7 +96,9 @@ void stm32_rcc_enablelse(void)
     }
 #endif
 
+#ifdef HAVE_PWR_DBP
   /* Disable backup domain access if it was disabled on entry */
 
   stm32_pwr_enablebkp(false);
+#endif
 }
diff --git a/arch/arm/src/stm32f0l0g0/stm32_rcc.h 
b/arch/arm/src/stm32f0l0g0/stm32_lsi.c
similarity index 52%
copy from arch/arm/src/stm32f0l0g0/stm32_rcc.h
copy to arch/arm/src/stm32f0l0g0/stm32_lsi.c
index 41c885599d..cfcc05e190 100644
--- a/arch/arm/src/stm32f0l0g0/stm32_rcc.h
+++ b/arch/arm/src/stm32f0l0g0/stm32_lsi.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/arm/src/stm32f0l0g0/stm32_rcc.h
+ * arch/arm/src/stm32f0l0g0/stm32_lsi.c
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -20,9 +20,6 @@
  *
  ****************************************************************************/
 
-#ifndef __ARCH_ARM_SRC_STM32F0L0G0_STM32_RCC_H
-#define __ARCH_ARM_SRC_STM32F0L0G0_STM32_RCC_H
-
 /****************************************************************************
  * Included Files
  ****************************************************************************/
@@ -30,41 +27,68 @@
 #include <nuttx/config.h>
 
 #include "arm_internal.h"
-#include "chip.h"
+#include "stm32_rcc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* STM32C0 use the second CSR register for LSI */
 
-#include "hardware/stm32_rcc.h"
+#ifdef CONFIG_ARCH_CHIP_STM32C0
+#  define STM32_RCC_CSR STM32_RCC_CSR2
+#  define RCC_CSR_LSION RCC_CSR2_LSION
+#  define RCC_CSR_LSIRDY RCC_CSR2_LSIRDY
+#endif
 
 /****************************************************************************
- * Public Function Prototypes
+ * Private Data
  ****************************************************************************/
 
 /****************************************************************************
- * Name: stm32_clockconfig
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_rcc_enablelsi
  *
  * Description:
- *   Called to initialize the STM32F0XX.
- *   This does whatever setup is needed to put the MCU in a usable state.
- *   This includes the initialization of clocking using the settings
- *   in board.h.
+ *   Enable the Internal Low-Speed (LSI) RC Oscillator.
  *
  ****************************************************************************/
 
-void stm32_clockconfig(void);
+void stm32_rcc_enablelsi(void)
+{
+  /* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION
+   * bit in the RCC CSR register.
+   */
+
+  modifyreg32(STM32_RCC_CSR, 0, RCC_CSR_LSION);
+
+  /* Wait for the internal RC 40 kHz oscillator to be stable. */
+
+  while ((getreg32(STM32_RCC_CSR) & RCC_CSR_LSIRDY) == 0);
+}
 
 /****************************************************************************
- * Name: stm32_rcc_enablelse
+ * Name: stm32_rcc_disablelsi
  *
  * Description:
- *   Enable the External Low-Speed (LSE) Oscillator.
- *
- * Input Parameters:
- *   None
- *
- * Returned Value:
- *   None
+ *   Disable the Internal Low-Speed (LSI) RC Oscillator.
  *
  ****************************************************************************/
 
-void stm32_rcc_enablelse(void);
+void stm32_rcc_disablelsi(void)
+{
+  /* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION
+   * bit in the RCC CSR register.
+   */
+
+  modifyreg32(STM32_RCC_CSR, RCC_CSR_LSION, 0);
 
-#endif /* __ARCH_ARM_SRC_STM32F0L0G0_STM32_RCC_H */
+  /* LSIRDY should go low after 3 LSI clock cycles */
+}
diff --git a/arch/arm/src/stm32f0l0g0/stm32_rcc.h 
b/arch/arm/src/stm32f0l0g0/stm32_rcc.h
index 41c885599d..3a45a94a0c 100644
--- a/arch/arm/src/stm32f0l0g0/stm32_rcc.h
+++ b/arch/arm/src/stm32f0l0g0/stm32_rcc.h
@@ -67,4 +67,24 @@ void stm32_clockconfig(void);
 
 void stm32_rcc_enablelse(void);
 
+/****************************************************************************
+ * Name: stm32_rcc_enablelsi
+ *
+ * Description:
+ *   Enable the Internal Low-Speed (LSI) RC Oscillator.
+ *
+ ****************************************************************************/
+
+void stm32_rcc_enablelsi(void);
+
+/****************************************************************************
+ * Name: stm32_rcc_disablelsi
+ *
+ * Description:
+ *   Disable the Internal Low-Speed (LSI) RC Oscillator.
+ *
+ ****************************************************************************/
+
+void stm32_rcc_disablelsi(void);
+
 #endif /* __ARCH_ARM_SRC_STM32F0L0G0_STM32_RCC_H */
diff --git a/arch/arm/src/stm32f0l0g0/stm32_rcc.h 
b/arch/arm/src/stm32f0l0g0/stm32_wdg.h
similarity index 55%
copy from arch/arm/src/stm32f0l0g0/stm32_rcc.h
copy to arch/arm/src/stm32f0l0g0/stm32_wdg.h
index 41c885599d..1d688da6b3 100644
--- a/arch/arm/src/stm32f0l0g0/stm32_rcc.h
+++ b/arch/arm/src/stm32f0l0g0/stm32_wdg.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/arm/src/stm32f0l0g0/stm32_rcc.h
+ * arch/arm/src/stm32f0l0g0/stm32_wdg.h
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -20,8 +20,8 @@
  *
  ****************************************************************************/
 
-#ifndef __ARCH_ARM_SRC_STM32F0L0G0_STM32_RCC_H
-#define __ARCH_ARM_SRC_STM32F0L0G0_STM32_RCC_H
+#ifndef __ARCH_ARM_SRC_STM32F0L0G0_STM32_WDG_H
+#define __ARCH_ARM_SRC_STM32F0L0G0_STM32_WDG_H
 
 /****************************************************************************
  * Included Files
@@ -29,42 +29,76 @@
 
 #include <nuttx/config.h>
 
-#include "arm_internal.h"
 #include "chip.h"
+#include "hardware/stm32_wdg.h"
 
-#include "hardware/stm32_rcc.h"
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
 
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
 
 /****************************************************************************
- * Name: stm32_clockconfig
+ * Name: stm32_iwdginitialize
  *
  * Description:
- *   Called to initialize the STM32F0XX.
- *   This does whatever setup is needed to put the MCU in a usable state.
- *   This includes the initialization of clocking using the settings
- *   in board.h.
+ *   Initialize the IWDG watchdog time.  The watchdog timer is initialized
+ *   and registers as 'devpath.  The initial state of the watchdog time is
+ *   disabled.
+ *
+ * Input Parameters:
+ *   devpath - The full path to the watchdog.  This should be of the form
+ *     /dev/watchdog0
+ *   lsifreq - The calibrated LSI clock frequency
+ *
+ * Returned Value:
+ *   None
  *
  ****************************************************************************/
 
-void stm32_clockconfig(void);
+#ifdef CONFIG_STM32F0L0G0_IWDG
+void stm32_iwdginitialize(const char *devpath, uint32_t lsifreq);
+#endif
 
 /****************************************************************************
- * Name: stm32_rcc_enablelse
+ * Name: stm32_wwdginitialize
  *
  * Description:
- *   Enable the External Low-Speed (LSE) Oscillator.
+ *   Initialize the WWDG watchdog time.  The watchdog timer is initializeed
+ *   and registers as 'devpath.  The initial state of the watchdog time is
+ *   disabled.
  *
  * Input Parameters:
- *   None
+ *   devpath - The full path to the watchdog.  This should be of the form
+ *     /dev/watchdog0
  *
  * Returned Value:
  *   None
  *
  ****************************************************************************/
 
-void stm32_rcc_enablelse(void);
+#ifdef CONFIG_STM32F0L0G0_WWDG
+void stm32_wwdginitialize(const char *devpath);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
 
-#endif /* __ARCH_ARM_SRC_STM32F0L0G0_STM32_RCC_H */
+#endif /* __ARCH_ARM_SRC_STM32F0L0G0_STM32_WDG_H */
diff --git a/arch/arm/src/stm32f0l0g0/stm32_wwdg.c 
b/arch/arm/src/stm32f0l0g0/stm32_wwdg.c
new file mode 100644
index 0000000000..c8a04bd5ca
--- /dev/null
+++ b/arch/arm/src/stm32f0l0g0/stm32_wwdg.c
@@ -0,0 +1,684 @@
+/****************************************************************************
+ * arch/arm/src/stm32f0l0g0/stm32_wwdg.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 <nuttx/arch.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/timers/watchdog.h>
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "hardware/stm32_dbgmcu.h"
+#include "stm32_wdg.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Clocking *****************************************************************/
+
+/* The minimum frequency of the WWDG clock is:
+ *
+ *  Fmin = PCLK1 / 4096 / 8
+ *
+ * So the maximum delay (in milliseconds) is then:
+ *
+ *   1000 * (WWDG_CR_T_MAX+1) / Fmin
+ *
+ * For example, if PCLK1 = 42MHz, then the maximum delay is:
+ *
+ *   Fmin = 1281.74
+ *   1000 * 64 / Fmin = 49.93 msec
+ */
+
+#define WWDG_FMIN       (STM32_PCLK1_FREQUENCY / 4096 / 8)
+#define WWDG_MAXTIMEOUT (1000 * (WWDG_CR_T_MAX+1) / WWDG_FMIN)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure provides the private representation of the "lower-half"
+ * driver state structure.  This structure must be cast-compatible with the
+ * well-known watchdog_lowerhalf_s structure.
+ */
+
+struct stm32_lowerhalf_s
+{
+  const struct watchdog_ops_s *ops; /* Lower half operations */
+  xcpt_t   handler;                 /* Current EWI interrupt handler */
+  uint32_t timeout;                 /* The actual timeout value */
+  uint32_t fwwdg;                   /* WWDG clock frequency */
+  bool     started;                 /* The timer has been started */
+  uint8_t  reload;                  /* The 7-bit reload field reset value */
+  uint8_t  window;                  /* The 7-bit window (W) field value */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Register operations ******************************************************/
+
+static void stm32_setwindow(struct stm32_lowerhalf_s *priv, uint8_t window);
+
+/* Interrupt handling *******************************************************/
+
+static int stm32_interrupt(int irq, void *context, void *arg);
+
+/* "Lower half" driver methods **********************************************/
+
+static int stm32_start(struct watchdog_lowerhalf_s *lower);
+static int stm32_stop(struct watchdog_lowerhalf_s *lower);
+static int stm32_keepalive(struct watchdog_lowerhalf_s *lower);
+static int stm32_getstatus(struct watchdog_lowerhalf_s *lower,
+                           struct watchdog_status_s *status);
+static int stm32_settimeout(struct watchdog_lowerhalf_s *lower,
+                            uint32_t timeout);
+static xcpt_t stm32_capture(struct watchdog_lowerhalf_s *lower,
+                            xcpt_t handler);
+static int  stm32_ioctl(struct watchdog_lowerhalf_s *lower, int cmd,
+                        unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* "Lower half" driver methods */
+
+static const struct watchdog_ops_s g_wdgops =
+{
+  .start      = stm32_start,
+  .stop       = stm32_stop,
+  .keepalive  = stm32_keepalive,
+  .getstatus  = stm32_getstatus,
+  .settimeout = stm32_settimeout,
+  .capture    = stm32_capture,
+  .ioctl      = stm32_ioctl,
+};
+
+/* "Lower half" driver state */
+
+static struct stm32_lowerhalf_s g_wdgdev;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_setwindow
+ *
+ * Description:
+ *   Set the CFR window value. The window value is compared to the down-
+ *   counter when the counter is updated.  The WWDG counter should be updated
+ *   only when the counter is below this window value (and greater than 64)
+ *   otherwise a reset will be generated
+ *
+ ****************************************************************************/
+
+static void stm32_setwindow(struct stm32_lowerhalf_s *priv, uint8_t window)
+{
+  uint16_t regval;
+
+  /* Set W[6:0] bits according to selected window value */
+
+  regval = getreg32(STM32_WWDG_CFR);
+  regval &= ~WWDG_CFR_W_MASK;
+  regval |= window << WWDG_CFR_W_SHIFT;
+  putreg32(regval, STM32_WWDG_CFR);
+
+  /* Remember the window setting */
+
+  priv->window = window;
+}
+
+/****************************************************************************
+ * Name: stm32_interrupt
+ *
+ * Description:
+ *   WWDG early warning interrupt
+ *
+ * Input Parameters:
+ *   Usual interrupt handler arguments.
+ *
+ * Returned Value:
+ *   Always returns OK.
+ *
+ ****************************************************************************/
+
+static int stm32_interrupt(int irq, void *context, void *arg)
+{
+  struct stm32_lowerhalf_s *priv = &g_wdgdev;
+  uint16_t regval;
+
+  /* Check if the EWI interrupt is really pending */
+
+  regval = getreg32(STM32_WWDG_SR);
+  if ((regval & WWDG_SR_EWIF) != 0)
+    {
+      /* Is there a registered handler? */
+
+      if (priv->handler)
+        {
+          /* Yes... NOTE:  This interrupt service routine (ISR) must reload
+           * the WWDG counter to prevent the reset.  Otherwise, we will reset
+           * upon return.
+           */
+
+          priv->handler(irq, context, arg);
+        }
+
+      /* The EWI interrupt is cleared by writing '0' to the EWIF bit in the
+       * WWDG_SR register.
+       */
+
+      regval &= ~WWDG_SR_EWIF;
+      putreg32(regval, STM32_WWDG_SR);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_start
+ *
+ * Description:
+ *   Start the watchdog timer, resetting the time to the current timeout,
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the "lower-
+ *           half" driver state structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_start(struct watchdog_lowerhalf_s *lower)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+
+  wdinfo("Entry\n");
+  DEBUGASSERT(priv);
+
+  /* The watchdog is always disabled after a reset. It is enabled by setting
+   * the WDGA bit in the WWDG_CR register, then it cannot be disabled again
+   * except by a reset.
+   */
+
+  putreg32(WWDG_CR_WDGA | WWDG_CR_T_RESET | priv->reload, STM32_WWDG_CR);
+  priv->started = true;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_stop
+ *
+ * Description:
+ *   Stop the watchdog timer
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the "lower-
+ *           half" driver state structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_stop(struct watchdog_lowerhalf_s *lower)
+{
+  /* The watchdog is always disabled after a reset. It is enabled by setting
+   * the WDGA bit in the WWDG_CR register, then it cannot be disabled again
+   * except by a reset.
+   */
+
+  wdinfo("Entry\n");
+  return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: stm32_keepalive
+ *
+ * Description:
+ *   Reset the watchdog timer to the current timeout value, prevent any
+ *   imminent watchdog timeouts.  This is sometimes referred as "pinging"
+ *   the watchdog timer or "petting the dog".
+ *
+ *   The application program must write in the WWDG_CR register at regular
+ *   intervals during normal operation to prevent an MCU reset. This
+ *   operation must occur only when the counter value is lower than the
+ *   window register value. The value to be stored in the WWDG_CR register
+ *   must be between 0xff and 0xC0:
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the "lower-
+ *           half" driver state structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_keepalive(struct watchdog_lowerhalf_s *lower)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+
+  wdinfo("Entry\n");
+  DEBUGASSERT(priv);
+
+  /* Write to T[6:0] bits to configure the counter value, no need to do
+   * a read-modify-write; writing a 0 to WDGA bit does nothing.
+   */
+
+  putreg32((WWDG_CR_T_RESET | priv->reload), STM32_WWDG_CR);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_getstatus
+ *
+ * Description:
+ *   Get the current watchdog timer status
+ *
+ * Input Parameters:
+ *   lower  - A pointer the publicly visible representation of the "lower-
+ *            half" driver state structure.
+ *   status - The location to return the watchdog status information.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_getstatus(struct watchdog_lowerhalf_s *lower,
+                           struct watchdog_status_s *status)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  uint32_t elapsed;
+  uint16_t reload;
+
+  wdinfo("Entry\n");
+  DEBUGASSERT(priv);
+
+  /* Return the status bit */
+
+  status->flags = WDFLAGS_RESET;
+  if (priv->started)
+    {
+      status->flags |= WDFLAGS_ACTIVE;
+    }
+
+  if (priv->handler)
+    {
+      status->flags |= WDFLAGS_CAPTURE;
+    }
+
+  /* Return the actual timeout is milliseconds */
+
+  status->timeout = priv->timeout;
+
+  /* Get the time remaining until the watchdog expires (in milliseconds) */
+
+  reload = (getreg32(STM32_WWDG_CR) >> WWDG_CR_T_SHIFT) & 0x7f;
+  elapsed = priv->reload - reload;
+  status->timeleft = (priv->timeout * elapsed) / (priv->reload + 1);
+
+  wdinfo("Status     :\n");
+  wdinfo("  flags    : %08x\n", (unsigned)status->flags);
+  wdinfo("  timeout  : %u\n", (unsigned)status->timeout);
+  wdinfo("  timeleft : %u\n", (unsigned)status->flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_settimeout
+ *
+ * Description:
+ *   Set a new timeout value (and reset the watchdog timer)
+ *
+ * Input Parameters:
+ *   lower   - A pointer the publicly visible representation of the
+ *             "lower-half" driver state structure.
+ *   timeout - The new timeout value in milliseconds.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_settimeout(struct watchdog_lowerhalf_s *lower,
+                            uint32_t timeout)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  uint32_t fwwdg;
+  uint32_t reload;
+  uint16_t regval;
+  int wdgtb;
+
+  DEBUGASSERT(priv);
+  wdinfo("Entry: timeout=%u\n", (unsigned)timeout);
+
+  /* Can this timeout be represented? */
+
+  if (timeout < 1 || timeout > WWDG_MAXTIMEOUT)
+    {
+      wderr("ERROR: Cannot represent timeout=%u > %lu\n",
+            (unsigned)timeout, WWDG_MAXTIMEOUT);
+      return -ERANGE;
+    }
+
+  /* Determine prescaler value.
+   *
+   * Fwwdg = PCLK1/4096/prescaler.
+   *
+   * Where
+   *  Fwwwdg is the frequency of the WWDG clock
+   *  wdgtb is one of {1, 2, 4, or 8}
+   */
+
+  /* Select the smallest prescaler that will result in a reload field value
+   * that is less than the maximum.
+   */
+
+  for (wdgtb = 0; ; wdgtb++)
+    {
+      /* WDGTB = 0 -> Divider = 1  = 1 << 0
+       * WDGTB = 1 -> Divider = 2  = 1 << 1
+       * WDGTB = 2 -> Divider = 4  = 1 << 2
+       * WDGTB = 3 -> Divider = 8  = 1 << 3
+       */
+
+      /* Get the WWDG counter frequency in Hz. */
+
+      fwwdg = (STM32_PCLK1_FREQUENCY / 4096) >> wdgtb;
+
+      /* The formula to calculate the timeout value is given by:
+       *
+       * timeout =  1000 * (reload + 1) / Fwwdg, OR
+       * reload = timeout * Fwwdg / 1000 - 1
+       *
+       * Where
+       *  timeout is the desired timeout in milliseconds
+       *  reload is the contents of T{5:0]
+       *  Fwwdg is the frequency of the WWDG clock
+       */
+
+       reload = timeout * fwwdg / 1000 - 1;
+
+      /* If this reload valid is less than the maximum or we are not ready
+       * at the prescaler value, then break out of the loop to use these
+       * settings.
+       */
+
+#if 0
+      wdinfo("wdgtb=%d fwwdg=%d reload=%d timeout=%d\n",
+             wdgtb, fwwdg, reload,  1000 * (reload + 1) / fwwdg);
+#endif
+      if (reload <= WWDG_CR_T_MAX || wdgtb == 3)
+        {
+          /* Note that we explicitly break out of the loop rather than using
+           * the 'for' loop termination logic because we do not want the
+           * value of wdgtb to be incremented.
+           */
+
+          break;
+        }
+    }
+
+  /* Make sure that the final reload value is within range */
+
+  if (reload > WWDG_CR_T_MAX)
+    {
+      reload = WWDG_CR_T_MAX;
+    }
+
+  /* Calculate and save the actual timeout value in milliseconds:
+   *
+   * timeout =  1000 * (reload + 1) / Fwwdg
+   */
+
+  priv->timeout = 1000 * (reload + 1) / fwwdg;
+
+  /* Remember the selected values */
+
+  priv->fwwdg  = fwwdg;
+  priv->reload = reload;
+
+  wdinfo("wdgtb=%d fwwdg=%u reload=%u timeout=%u\n",
+         wdgtb, (unsigned)fwwdg, (unsigned)reload, (unsigned)priv->timeout);
+
+  /* Set WDGTB[1:0] bits according to calculated value */
+
+  regval = getreg32(STM32_WWDG_CFR);
+  regval &= ~WWDG_CFR_WDGTB_MASK;
+  regval |= (uint16_t)wdgtb << WWDG_CFR_WDGTB_SHIFT;
+  putreg32(regval, STM32_WWDG_CFR);
+
+  /* Reset the 7-bit window value to the maximum value.. essentially
+   * disabling the lower limit of the watchdog reset time.
+   */
+
+  stm32_setwindow(priv, 0x7f);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_capture
+ *
+ * Description:
+ *   Don't reset on watchdog timer timeout; instead, call this user provider
+ *   timeout handler.  NOTE:  Providing handler==NULL will restore the reset
+ *   behavior.
+ *
+ * Input Parameters:
+ *   lower      - A pointer the publicly visible representation of the
+ *                "lower-half" driver state structure.
+ *   newhandler - The new watchdog expiration function pointer.  If this
+ *                function pointer is NULL, then the reset-on-expiration
+ *                behavior is restored,
+ *
+ * Returned Value:
+ *   The previous watchdog expiration function pointer or NULL is there was
+ *   no previous function pointer, i.e., if the previous behavior was
+ *   reset-on-expiration (NULL is also returned if an error occurs).
+ *
+ ****************************************************************************/
+
+static xcpt_t stm32_capture(struct watchdog_lowerhalf_s *lower,
+                            xcpt_t handler)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  irqstate_t flags;
+  xcpt_t oldhandler;
+  uint16_t regval;
+
+  DEBUGASSERT(priv);
+  wdinfo("Entry: handler=%p\n", handler);
+
+  /* Get the old handler return value */
+
+  flags = enter_critical_section();
+  oldhandler = priv->handler;
+
+  /* Save the new handler */
+
+  priv->handler = handler;
+
+  /* Are we attaching or detaching the handler? */
+
+  regval = getreg32(STM32_WWDG_CFR);
+  if (handler)
+    {
+      /* Attaching... Enable the EWI interrupt */
+
+      regval |= WWDG_CFR_EWI;
+      putreg32(regval, STM32_WWDG_CFR);
+
+      up_enable_irq(STM32_IRQ_WWDG);
+    }
+  else
+    {
+      /* Detaching... Disable the EWI interrupt */
+
+      regval &= ~WWDG_CFR_EWI;
+      putreg32(regval, STM32_WWDG_CFR);
+
+      up_disable_irq(STM32_IRQ_WWDG);
+    }
+
+  leave_critical_section(flags);
+  return oldhandler;
+}
+
+/****************************************************************************
+ * Name: stm32_ioctl
+ *
+ * Description:
+ *   Any ioctl commands that are not recognized by the "upper-half" driver
+ *   are forwarded to the lower half driver through this method.
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of the "lower-
+ *           half" driver state structure.
+ *   cmd   - The ioctl command value
+ *   arg   - The optional argument that accompanies the 'cmd'.  The
+ *           interpretation of this argument depends on the particular
+ *           command.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_ioctl(struct watchdog_lowerhalf_s *lower, int cmd,
+                       unsigned long arg)
+{
+  struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
+  int ret = -ENOTTY;
+
+  DEBUGASSERT(priv);
+  wdinfo("Entry: cmd=%d arg=%ld\n", cmd, arg);
+
+  /* WDIOC_MINTIME: Set the minimum ping time.  If two keepalive ioctls
+   * are received within this time, a reset event will be generated.
+   * Argument: A 32-bit time value in milliseconds.
+   */
+
+  if (cmd == WDIOC_MINTIME)
+    {
+      uint32_t mintime = (uint32_t)arg;
+
+      /* The minimum time should be strictly less than the total delay
+       * which, in turn, will be less than or equal to WWDG_CR_T_MAX
+       */
+
+      ret = -EINVAL;
+      if (mintime < priv->timeout)
+        {
+          uint32_t window = (priv->timeout - mintime) * priv->fwwdg /
+                            1000 - 1;
+          DEBUGASSERT(window < priv->reload);
+          stm32_setwindow(priv, window | WWDG_CR_T_RESET);
+          ret = OK;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_wwdginitialize
+ *
+ * Description:
+ *   Initialize the WWDG watchdog timer.  The watchdog timer is initialized
+ *   and registers as 'devpath'.  The initial state of the watchdog timer is
+ *   disabled.
+ *
+ * Input Parameters:
+ *   devpath - The full path to the watchdog.  This should be of the form
+ *     /dev/watchdog0
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void stm32_wwdginitialize(const char *devpath)
+{
+  struct stm32_lowerhalf_s *priv = &g_wdgdev;
+
+  wdinfo("Entry: devpath=%s\n", devpath);
+
+  /* NOTE we assume that clocking to the WWDG has already been provided by
+   * the RCC initialization logic.
+   */
+
+  /* Initialize the driver state structure.  Here we assume: (1) the state
+   * structure lies in .bss and was zeroed at reset time.  (2) This function
+   * is only called once so it is never necessary to re-zero the structure.
+   */
+
+  priv->ops = &g_wdgops;
+
+  /* Attach our EWI interrupt handler (But don't enable it yet) */
+
+  irq_attach(STM32_IRQ_WWDG, stm32_interrupt, NULL);
+
+  /* Select an arbitrary initial timeout value.  But don't start the watchdog
+   * yet. NOTE: If the "Hardware watchdog" feature is enabled through the
+   * device option bits, the watchdog is automatically enabled at power-on.
+   */
+
+  stm32_settimeout((struct watchdog_lowerhalf_s *)priv, WWDG_MAXTIMEOUT);
+
+  /* Register the watchdog driver as /dev/watchdog0 */
+
+  watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv);
+
+  /* When the microcontroller enters debug mode (Cortex-M core halted),
+   * the WWDG counter either continues to work normally or stops, depending
+   * on DBG_WWDG_STOP configuration bit in DBG module.
+   */
+
+#ifdef CONFIG_DEBUG_FEATURES
+    {
+      uint32_t cr = getreg32(STM32_DBGMCU_APB1_FZ);
+      cr |= DBGMCU_APB1_WWDGSTOP;
+      putreg32(cr, STM32_DBGMCU_APB1_FZ);
+    }
+#endif
+}

Reply via email to