/* * Copyright (c) 2006-2022, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-05-06 sundm75 first version */ #include <rtthread.h> #include <rtdevice.h> #ifdef RT_USING_WDT #include <drivers/watchdog.h> #include "drv_wdt.h" #include "ls1c_wdog.h" #include "ls1c_clock.h" typedef enum { RESTENABLE = 0x0, INTERRUPTENABLE = 0x1, }wdt_enable_mode; static rt_uint32_t heartbeat = 0; static rt_err_t wdt_stop(void) { rt_err_t ret = RT_EOK; Wdog_Reset(); ret = (rt_err_t) Wdog_Disable(); if (ret != RT_EOK) { rt_kprintf("Wdog_Disable error!\n"); return -RT_ERROR; } return ret; } static rt_err_t wdt_start(int mode) { rt_err_t ret = RT_EOK; wdt_enable_mode wdt_mode = RESTENABLE; ret = (rt_err_t) Wdog_Disable(); if (ret != RT_EOK) { rt_kprintf("Wdog_Disable error!\n"); return -RT_ERROR; } if((mode == RESTENABLE) || (mode == INTERRUPTENABLE)) { wdt_mode = mode; } Wdog_Enable(); Wdog_Set(); if (ret != RT_EOK) { rt_kprintf("Wdog_Enable error!\n"); return -RT_ERROR; } return ret; } static rt_err_t wdt_keepalive(void) { rt_err_t ret = RT_EOK; rt_uint32_t index = 0; index = heartbeat * clk_get_apb_rate(); ret = (rt_err_t) Wdog_LoadValue(index); Wdog_Set(); if (ret != 0) { rt_kprintf("LS1C_Wdog_ClrTimeout error!\n"); return -RT_ERROR; } return ret; } static rt_uint32_t wdt_get_timeleft(void) { rt_uint32_t cnt = 0; rt_uint32_t second = 0; cnt = (rt_uint32_t) Wdog_GetValue(); second = cnt/clk_get_apb_rate(); return second; } static rt_err_t wdt_set_timeout(rt_uint32_t second) { rt_err_t ret = RT_EOK; rt_uint32_t index = 0; index = second * clk_get_apb_rate(); ret = (rt_err_t) Wdog_LoadValue(index); if (ret != RT_EOK) { rt_kprintf("Wdog_LoadValue error!\n"); return -RT_ERROR; } return ret; } static rt_err_t watchdog_init(rt_watchdog_t *wdt) { struct wdt_driver *wdt_drv = wdt->parent.user_data; if (wdt_drv->in_use) return -RT_EBUSY; Wdog_Init(); return RT_EOK; } static rt_err_t watchdog_ctrl(rt_watchdog_t *wdt, int cmd, void *arg) { rt_uint32_t val; int mode; switch (cmd) { case RT_DEVICE_CTRL_WDT_START: mode = *((int *)(arg)); wdt_start(mode); break; case RT_DEVICE_CTRL_WDT_STOP: Wdog_Disable(); break; case RT_DEVICE_CTRL_WDT_KEEPALIVE: wdt_keepalive(); break; case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: heartbeat = *((rt_uint32_t *)(arg)); wdt_set_timeout(heartbeat); break; case RT_DEVICE_CTRL_WDT_GET_TIMEOUT: arg = &heartbeat; break; case RT_DEVICE_CTRL_WDT_GET_TIMELEFT: val = (rt_uint32_t) wdt_get_timeleft(); arg = &val; break; default: return -RT_EIO; } return RT_EOK; } struct rt_watchdog_ops watchdog_ops = { .init = &watchdog_init, .control = &watchdog_ctrl, }; int wdt_exit(void *priv_data) { return 0; } int rt_hw_wdt_init(void) { rt_watchdog_t *wdt_dev; struct wdt_driver *wdt_drv; wdt_drv = (struct wdt_driver *)rt_malloc(sizeof(struct wdt_driver)); rt_memset(wdt_drv, 0, sizeof(struct wdt_driver)); wdt_dev = (rt_watchdog_t *)rt_malloc(sizeof(rt_watchdog_t)); if (wdt_dev == RT_NULL) { rt_kprintf("ERROR: %s rt_watchdog_t malloc failed\n", __func__); } wdt_dev->ops = &watchdog_ops; rt_hw_watchdog_register(wdt_dev, "wdt", RT_DEVICE_OFLAG_RDWR, wdt_drv); return 0; } INIT_BOARD_EXPORT(rt_hw_wdt_init); #endif