summaryrefslogtreecommitdiff
path: root/bsp/gd32103c-eval/drivers/drv_rtc.c
blob: 95c6e56e9d32b7b8cd347fefd5b791fdb8df9297 (plain)
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
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-02-20     iysheng           first version
 */

#include <board.h>
#include <sys/time.h>
#include <drivers/drv_comm.h>

#define DBG_TAG             "drv.rtc"
#define DBG_LVL             DBG_INFO

#include <rtdbg.h>

#ifdef RT_USING_RTC

typedef struct {
    struct rt_device rtc_dev;
} gd32_rtc_device;

static gd32_rtc_device g_gd32_rtc_dev;

static time_t get_rtc_timestamp(void)
{
    time_t rtc_counter;

    rtc_counter = (time_t)RTC_GetCounter();

    return rtc_counter;
}

static rt_err_t set_rtc_timestamp(time_t time_stamp)
{
    uint32_t rtc_counter;

    rtc_counter = (uint32_t)time_stamp;

    /* wait until LWOFF bit in RTC_CTL to 1 */
    RTC_WaitLWOFF();
    /* enter configure mode */
    RTC_EnterConfigMode();
    /* write data to rtc register */
    RTC_SetCounter(rtc_counter);
    /* exit configure mode */
    RTC_ExitConfigMode();
    /* wait until LWOFF bit in RTC_CTL to 1 */
    RTC_WaitLWOFF();

    return RT_EOK;
}

static rt_err_t rt_gd32_rtc_control(rt_device_t dev, int cmd, void *args)
{
    rt_err_t result = RT_EOK;

    RT_ASSERT(dev != RT_NULL);
    switch (cmd)
    {
    case RT_DEVICE_CTRL_RTC_GET_TIME:
        *(rt_uint32_t *)args = get_rtc_timestamp();
        break;

    case RT_DEVICE_CTRL_RTC_SET_TIME:
        if (set_rtc_timestamp(*(rt_uint32_t *)args))
        {
            result = -RT_ERROR;
        }
        break;
    }

    return result;
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops g_gd32_rtc_ops =
{
    RT_NULL,
    RT_NULL,
    RT_NULL,
    RT_NULL,
    RT_NULL,
    rt_gd32_rtc_control
};
#endif

static int rt_hw_rtc_init(void)
{
    rt_err_t ret;
    time_t rtc_counter;

    rcu_periph_clock_enable(RCU_PMU);
    PWR_BackupAccess_Enable(ENABLE);
    rcu_periph_clock_enable(RCU_BKPI);

    rtc_counter = get_rtc_timestamp();
    /* once the rtc clock source has been selected, if can't be changed
     * anymore unless the Backup domain is reset */
    rcu_bkp_reset_enable();
    rcu_bkp_reset_disable();
    rcu_periph_clock_enable(RCU_RTC);
    rcu_osci_on(RCU_LXTAL);
    if (SUCCESS == rcu_osci_stab_wait(RCU_LXTAL))
    {
        /* set lxtal as rtc clock source */
        rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
    }
    set_rtc_timestamp(rtc_counter);

#ifdef RT_USING_DEVICE_OPS
    g_gd32_rtc_dev.rtc_dev.ops         = &g_gd32_rtc_ops;
#else
    g_gd32_rtc_dev.rtc_dev.init        = RT_NULL;
    g_gd32_rtc_dev.rtc_dev.open        = RT_NULL;
    g_gd32_rtc_dev.rtc_dev.close       = RT_NULL;
    g_gd32_rtc_dev.rtc_dev.read        = RT_NULL;
    g_gd32_rtc_dev.rtc_dev.write       = RT_NULL;
    g_gd32_rtc_dev.rtc_dev.control     = rt_gd32_rtc_control;
#endif
    g_gd32_rtc_dev.rtc_dev.type        = RT_Device_Class_RTC;
    g_gd32_rtc_dev.rtc_dev.rx_indicate = RT_NULL;
    g_gd32_rtc_dev.rtc_dev.tx_complete = RT_NULL;
    g_gd32_rtc_dev.rtc_dev.user_data   = RT_NULL;

    ret = rt_device_register(&g_gd32_rtc_dev.rtc_dev, "rtc", \
        RT_DEVICE_FLAG_RDWR);
    if (ret != RT_EOK)
    {
        LOG_E("failed register internal rtc device, err=%d", ret);
    }

    return ret;
}
INIT_DEVICE_EXPORT(rt_hw_rtc_init);
#endif