/* * Copyright (c) 2022 Renesas Electronics Corporation and/or its affiliates * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include LOG_MODULE_REGISTER(wdog_smartbond, CONFIG_WDT_LOG_LEVEL); #define DT_DRV_COMPAT renesas_smartbond_watchdog /* driver data */ struct wdog_smartbond_data { /* Reload value calculated in setup */ uint32_t reload_val; #ifdef CONFIG_WDT_SMARTBOND_NMI const struct device *wdog_device; wdt_callback_t callback; #endif }; static struct wdog_smartbond_data wdog_smartbond_dev_data = {}; static int wdg_smartbond_setup(const struct device *dev, uint8_t options) { ARG_UNUSED(dev); if (options & WDT_OPT_PAUSE_IN_SLEEP) { LOG_ERR("Watchdog pause in sleep is not supported"); return -ENOTSUP; } return 0; } static int wdg_smartbond_disable(const struct device *dev) { ARG_UNUSED(dev); if (SYS_WDOG->WATCHDOG_CTRL_REG & SYS_WDOG_WATCHDOG_CTRL_REG_NMI_RST_Msk) { /* watchdog cannot be stopped once started when NMI_RST is 1 */ return -EPERM; } GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SYS_WDOG_Msk; return 0; } #ifdef CONFIG_WDT_SMARTBOND_NMI static void wdog_smartbond_nmi_isr(void) { if (wdog_smartbond_dev_data.callback) { wdog_smartbond_dev_data.callback(wdog_smartbond_dev_data.wdog_device, 0); } } #endif /* CONFIG_RUNTIME_NMI */ static int wdg_smartbond_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *config) { struct wdog_smartbond_data *data = (struct wdog_smartbond_data *)(dev)->data; uint32_t reload_val; #ifndef CONFIG_WDT_SMARTBOND_NMI if (config->callback != NULL) { return -ENOTSUP; } #endif /* For RC32K timer ticks every ~10ms, for RCX ~21ms */ if (CRG_TOP->CLK_RCX_REG & CRG_TOP_CLK_RCX_REG_RCX_ENABLE_Msk) { reload_val = config->window.max / 21; } else { reload_val = config->window.max / 10; } if (reload_val < 1 || reload_val >= 0x2000 || config->window.min != 0) { /* Out of range supported by watchdog */ LOG_ERR("Watchdog timeout out of range"); return -EINVAL; } #if CONFIG_WDT_SMARTBOND_NMI data->callback = config->callback; data->wdog_device = dev; z_arm_nmi_set_handler(wdog_smartbond_nmi_isr); SYS_WDOG->WATCHDOG_CTRL_REG = 2; #else SYS_WDOG->WATCHDOG_CTRL_REG = 2 | SYS_WDOG_WATCHDOG_CTRL_REG_NMI_RST_Msk; #endif data->reload_val = reload_val; while (SYS_WDOG->WATCHDOG_CTRL_REG & SYS_WDOG_WATCHDOG_CTRL_REG_WRITE_BUSY_Msk) { /* wait */ } SYS_WDOG->WATCHDOG_REG = reload_val; return 0; } static int wdg_smartbond_feed(const struct device *dev, int channel_id) { struct wdog_smartbond_data *data = (struct wdog_smartbond_data *)(dev)->data; ARG_UNUSED(channel_id); while (SYS_WDOG->WATCHDOG_CTRL_REG & SYS_WDOG_WATCHDOG_CTRL_REG_WRITE_BUSY_Msk) { /* wait */ } SYS_WDOG->WATCHDOG_REG = data->reload_val; return 0; } static const struct wdt_driver_api wdg_smartbond_api = { .setup = wdg_smartbond_setup, .disable = wdg_smartbond_disable, .install_timeout = wdg_smartbond_install_timeout, .feed = wdg_smartbond_feed, }; static int wdg_smartbond_init(const struct device *dev) { ARG_UNUSED(dev); #ifdef CONFIG_WDT_DISABLE_AT_BOOT GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SYS_WDOG_Msk; #endif return 0; } DEVICE_DT_INST_DEFINE(0, wdg_smartbond_init, NULL, &wdog_smartbond_dev_data, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdg_smartbond_api);