drv_wdt.c 3.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2020-06-08     hqfang       the first version.
 *
 */
#include "drv_wdt.h"

#ifdef BSP_USING_WDT


static rt_err_t gd32_wdog_close(rt_watchdog_t *wdt)
{
    rt_uint32_t level;

    level = rt_hw_interrupt_disable();
    rcu_osci_off(RCU_IRC40K);
    rt_hw_interrupt_enable(level);

    return RT_EOK;
}

static rt_err_t gd32_wdog_open(rt_watchdog_t *wdt, rt_uint16_t oflag)
{
    rt_uint32_t level;

    level = rt_hw_interrupt_disable();
    /* enable IRC40K */
    rcu_osci_on(RCU_IRC40K);
    /* wait till IRC40K is ready */
    while (SUCCESS != rcu_osci_stab_wait(RCU_IRC40K));
    fwdgt_counter_reload();
    fwdgt_enable();
    rt_hw_interrupt_enable(level);

    return RT_EOK;
}

static rt_err_t gd32_wdog_init(rt_watchdog_t *wdt)
{
    /* confiure FWDGT counter clock: 40KHz(IRC40K) / 256 = 0.15625 KHz */
    fwdgt_config(FWDGT_RLD_RLD, FWDGT_PSC_DIV256);
    fwdgt_enable();
    return RT_EOK;
}

static rt_err_t gd32_wdog_refresh(rt_watchdog_t *wdt)
{
    rt_uint32_t level;

    level = rt_hw_interrupt_disable();
    fwdgt_counter_reload();
    rt_hw_interrupt_enable(level);

    return RT_EOK;
}

/**
 * @function control wdog
 *
 * @param
 *    wdt  whick wdog used
 *    cmd  control wdog options
 *    args argument of conrtol
 * @retval rt_err_t the status of control result
 *
 *
 */
#define WDT_RELOAD_SECOND       ((FWDGT_RLD & FWDGT_RLD_RLD) / 156)
static rt_err_t gd32_wdog_control(rt_watchdog_t *wdt, int cmd, void *args)
{
    RT_ASSERT(wdt != NULL);

    uint16_t reload_value;
    static uint16_t wdt_started = 0;
    static rt_tick_t last_tick = 0;

    switch (cmd)
    {
    case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
    {
        *(uint16_t *)args = WDT_RELOAD_SECOND;
    }
    break;
    case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
    {
        RT_ASSERT(*(uint16_t *)args != 0);
        reload_value = *(uint16_t *)args;
        // 6.4ms 1 tick, 1s -> 1000 / 6.4 = 625 / 4 ticks
        reload_value = ((uint32_t)reload_value * 625) / 4;
        fwdgt_write_enable();
        while (FWDGT_STAT & FWDGT_STAT_RUD);
        FWDGT_RLD = FWDGT_RLD_RLD & reload_value;
        fwdgt_write_disable();
    }
    break;
    case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
        *(uint16_t *)args = WDT_RELOAD_SECOND - \
                            (rt_tick_get() - last_tick) / RT_TICK_PER_SECOND;

        break;
    case RT_DEVICE_CTRL_WDT_KEEPALIVE:
    {
        last_tick = rt_tick_get();
        gd32_wdog_refresh(wdt);
    }
    break;
    case RT_DEVICE_CTRL_WDT_START:
    {
        gd32_wdog_open(wdt, *(rt_uint32_t *)args);
        last_tick = rt_tick_get();
        wdt_started = 1;
        while (FWDGT_STAT & FWDGT_STAT_RUD);
    }
    break;
    case RT_DEVICE_CTRL_WDT_STOP:
    {
        gd32_wdog_close(wdt);
        wdt_started = 0;
    }
    break;
    default:
        return RT_EINVAL;
    }

    return RT_EOK;
}

static struct rt_watchdog_ops gd32_wdog_ops =
{
    .init = gd32_wdog_init,
    .control = gd32_wdog_control,
};

static struct rt_watchdog_device gd32_wdt_device;

int rt_hw_wdt_init(void)
{
    int result = RT_EOK;

    rcu_osci_off(RCU_IRC40K);
    gd32_wdt_device.ops = &gd32_wdog_ops;
    result = rt_hw_watchdog_register(&gd32_wdt_device, "wdt", \
                                     RT_DEVICE_FLAG_RDWR, (void *)FWDGT);

    return result;
}

INIT_DEVICE_EXPORT(rt_hw_wdt_init);

#endif /* BSP_USING_WDT */