rt-thread/bsp/hpmicro/libraries/drivers/drv_ewdt.c

269 lines
6.3 KiB
C

/*
* Copyright (c) 2023 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <rthw.h>
#include <rtdevice.h>
#include <rtdbg.h>
#include "board.h"
#include "drv_ewdt.h"
#include "hpm_ewdg_drv.h"
#include "hpm_sysctl_drv.h"
#ifdef BSP_USING_EWDG
#define EWDG_CNT_CLK_FREQ 32768UL
typedef struct hpm_wdog
{
EWDG_Type *wdog_base;
char *device_name;
clock_name_t clock_name;
uint32_t irq_num;
rt_watchdog_t *wdog;
}hpm_wdog_t;
static rt_err_t hpm_wdog_init(rt_watchdog_t *wdt);
static rt_err_t hpm_wdog_open(rt_watchdog_t *wdt, rt_uint16_t oflag);
static rt_err_t hpm_wdog_close(rt_watchdog_t *wdt);
static rt_err_t hpm_wdog_refresh(rt_watchdog_t *wdt);
static rt_err_t hpm_wdog_control(rt_watchdog_t *wdt, int cmd, void *args);
static void hpm_wdog_isr(rt_watchdog_t *wdt);
#if defined(BSP_USING_EWDG0)
rt_watchdog_t wdog0;
void wdog0_isr(void)
{
hpm_wdog_isr(&wdog0);
}
SDK_DECLARE_EXT_ISR_M(IRQn_EWDG0, wdog0_isr)
#endif
#if defined(BSP_USING_EWDG1)
rt_watchdog_t wdog1;
void wdog1_isr(void)
{
hpm_wdog_isr(&wdog1);
}
SDK_DECLARE_EXT_ISR_M(IRQn_EWDG1, wdog1_isr)
#endif
#if defined(BSP_USING_EWDG2)
rt_watchdog_t wdog2;
void wdog2_isr(void)
{
hpm_wdog_isr(&wdog2);
}
SDK_DECLARE_EXT_ISR_M(IRQn_EWDG2, wdog2_isr)
#endif
#if defined(BSP_USING_EWDG3)
rt_watchdog_t wdog3;
void wdog3_isr(void)
{
hpm_wdog_isr(&wdog3);
}
SDK_DECLARE_EXT_ISR_M(IRQn_EWDG3, wdog3_isr)
#endif
static hpm_wdog_t wdogs[] = {
#ifdef BSP_USING_EWDG0
{
.wdog_base = HPM_EWDG0,
.device_name = "wdt0",
.clock_name = clock_watchdog0,
.irq_num = IRQn_EWDG0,
.wdog = &wdog0,
},
#endif
#ifdef BSP_USING_EWDG1
{
.wdog_base = HPM_EWDG1,
.device_name = "wdt1",
.clock_name = clock_watchdog1,
.irq_num = IRQn_EWDG1,
.wdog = &wdog1,
},
#endif
#ifdef BSP_USING_EWDG2
{
.wdog_base = HPM_EWDG2,
.device_name = "wdt2",
.clock_name = clock_watchdog2,
.irq_num = IRQn_EWDG2,
.wdog = &wdog2,
},
#endif
#ifdef BSP_USING_EWDG3
{
.wdog_name = HPM_EWDG3,
.device_name = "wdt3",
.clock_name = clock_watchdog3,
.irq_num = IRQn_EWDG3,
.wdog = &wdog3,
},
#endif
};
static struct rt_watchdog_ops hpm_wdog_ops = {
.init = hpm_wdog_init,
.control = hpm_wdog_control,
};
static rt_err_t hpm_wdog_init(rt_watchdog_t *wdt)
{
hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
EWDG_Type *base = hpm_wdog->wdog_base;
ewdg_config_t config;
printf("Init Watchdog\n");
ewdg_get_default_config(base, &config);
/* Enable EWDG */
config.enable_watchdog = true;
config.ctrl_config.use_lowlevel_timeout = false;
/* Enable EWDG Timeout Reset */
config.int_rst_config.enable_timeout_reset = true;
/* Set EWDG Count clock source to OSC32 */
config.ctrl_config.cnt_clk_sel = ewdg_cnt_clk_src_ext_osc_clk;
/* Set the EWDG reset timeout to 101ms */
config.cnt_src_freq = EWDG_CNT_CLK_FREQ;
config.ctrl_config.timeout_reset_us = 101UL * 1000UL;
ewdg_init(base, &config);
return RT_EOK;
}
static rt_err_t hpm_wdog_open(rt_watchdog_t *wdt, rt_uint16_t oflag)
{
hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
EWDG_Type *base = hpm_wdog->wdog_base;
rt_enter_critical();
ewdg_enable(base);
rt_exit_critical();
}
static rt_err_t hpm_wdog_close(rt_watchdog_t *wdt)
{
hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
EWDG_Type *base = hpm_wdog->wdog_base;
rt_enter_critical();
ewdg_disable(base);
rt_exit_critical();
return RT_EOK;
}
static rt_err_t hpm_wdog_refresh(rt_watchdog_t *wdt)
{
hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
EWDG_Type *base = hpm_wdog->wdog_base;
rt_enter_critical();
ewdg_refresh(base);
rt_exit_critical();
return RT_EOK;
}
static rt_err_t hpm_wdog_control(rt_watchdog_t *wdt, int cmd, void *args)
{
rt_err_t ret = RT_EOK;
hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
EWDG_Type *base = hpm_wdog->wdog_base;
ewdg_config_t config;
uint32_t temp;
switch (cmd)
{
case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
RT_ASSERT(*(uint32_t *)args != 0);
temp = *(uint32_t *)args;
temp *= 1000000U; /* Convert to microseconds */
ewdg_get_default_config(base, &config);
config.enable_watchdog = true;
config.int_rst_config.enable_timeout_reset = true;
config.ctrl_config.use_lowlevel_timeout = false;
uint32_t ewdg_src_clk_freq = EWDG_CNT_CLK_FREQ;
config.ctrl_config.cnt_clk_sel = ewdg_cnt_clk_src_ext_osc_clk;
/* Set the EWDG reset timeout to 1 second */
config.cnt_src_freq = ewdg_src_clk_freq;
config.ctrl_config.timeout_reset_us = temp;
/* Initialize the EWDG */
hpm_stat_t status = ewdg_init(base, &config);
if (status != status_success) {
printf(" EWDG initialization failed, error_code=%d\n", status);
}
/* delay 1ms to ensure above configure take effective*/
rt_thread_mdelay(1);
break;
case RT_DEVICE_CTRL_WDT_KEEPALIVE:
hpm_wdog_refresh(wdt);
break;
case RT_DEVICE_CTRL_WDT_START:
hpm_wdog_open(wdt, *(uint16_t*)args);
break;
case RT_DEVICE_CTRL_WDT_STOP:
hpm_wdog_close(wdt);
break;
default:
ret = RT_EINVAL;
break;
}
return RT_EOK;
}
void hpm_wdog_isr(rt_watchdog_t *wdt)
{
hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
EWDG_Type *base = hpm_wdog->wdog_base;
uint32_t ewdg_stat = ewdg_get_status_flags(base);
if ((ewdg_stat & EWDG_INT_TIMEOUT) != 0) {
ewdg_refresh(base);
}
ewdg_clear_status_flags(base, ewdg_stat);
}
int rt_hw_wdt_init(void)
{
rt_err_t err = RT_EOK;
#if defined(BSP_USING_EWDG)
for (uint32_t i = 0; i < sizeof(wdogs) / sizeof(wdogs[0]); i++)
{
wdogs[i].wdog->ops = &hpm_wdog_ops;
clock_add_to_group(wdogs[i].clock_name, 0);
err = rt_hw_watchdog_register(wdogs[i].wdog, wdogs[i].device_name, RT_DEVICE_FLAG_RDWR, (void *)&wdogs[i]);
if (err != RT_EOK)
{
LOG_E("rt device %s failed, status=%d\n", wdogs[i].device_name, err);
}
}
#endif
return err;
}
INIT_BOARD_EXPORT(rt_hw_wdt_init);
#endif /* RT_USING_WDT */