drv_rtc.c 5.5 KB
Newer Older
1 2 3 4 5 6 7
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date         Author         Notes
8
 * 2022-05-16   shelton        first version
9 10 11 12 13
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <sys/time.h>
14
#include "drv_common.h"
15 16 17 18 19 20 21 22 23 24 25

#ifdef BSP_USING_RTC

//#define DRV_DEBUG
#define LOG_TAG                         "drv.rtc"
#include <drv_log.h>

#define BKUP_REG_DATA                   0xA5A5

static time_t get_rtc_timestamp(void)
{
26
#if defined (SOC_SERIES_AT32F435) || defined (SOC_SERIES_AT32F437) || \
S
sheltonyu 已提交
27 28
    defined (SOC_SERIES_AT32F415) || defined (SOC_SERIES_AT32F421) || \
    defined (SOC_SERIES_AT32F425)
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
    struct tm tm_new;
    ertc_time_type ertc_time_struct;

    ertc_calendar_get(&ertc_time_struct);

    tm_new.tm_sec = ertc_time_struct.sec;
    tm_new.tm_min = ertc_time_struct.min;
    tm_new.tm_hour = ertc_time_struct.hour;
    tm_new.tm_mday = ertc_time_struct.day;
    tm_new.tm_mon = ertc_time_struct.month - 1;
    tm_new.tm_year = ertc_time_struct.year + 100;

    LOG_D("get rtc time.");

    return timegm(&tm_new);
44 45 46
#else
    return rtc_counter_get();
#endif
47 48 49 50
}

static rt_err_t set_rtc_time_stamp(time_t time_stamp)
{
51
#if defined (SOC_SERIES_AT32F435) || defined (SOC_SERIES_AT32F437) || \
S
sheltonyu 已提交
52 53
    defined (SOC_SERIES_AT32F415) || defined (SOC_SERIES_AT32F421) || \
    defined (SOC_SERIES_AT32F425)
54
    struct tm now;
55

56 57
    gmtime_r(&time_stamp, &now);
    if (now.tm_year < 100)
58 59 60 61 62
    {
        return -RT_ERROR;
    }

    /* set time */
63
    if(ertc_time_set(now.tm_hour, now.tm_min, now.tm_sec, ERTC_AM) != SUCCESS)
64 65 66 67 68
    {
        return -RT_ERROR;
    }

    /* set date */
69
    if(ertc_date_set(now.tm_year - 100, now.tm_mon + 1, now.tm_mday, now.tm_wday + 1) != SUCCESS)
70 71 72 73 74 75 76 77
    {
        return -RT_ERROR;
    }

    LOG_D("set rtc time.");

    /* indicator for the ertc configuration */
    ertc_bpr_data_write(ERTC_DT1, BKUP_REG_DATA);
78 79 80 81 82 83 84 85 86
#else
    /* set the rtc counter value */
    rtc_counter_set(time_stamp);
    /* wait until last write operation on rtc registers has finished */
    rtc_wait_config_finish();
    LOG_D("set rtc time.");

    bpr_data_write(BPR_DATA1, BKUP_REG_DATA);
#endif
87 88 89 90 91 92

    return RT_EOK;
}

static rt_err_t rt_rtc_config(void)
{
93
    /* allow access to pattery powered domain */
94 95
    pwc_battery_powered_domain_access(TRUE);

96
#if defined (SOC_SERIES_AT32F435) || defined (SOC_SERIES_AT32F437) || \
S
sheltonyu 已提交
97 98
    defined (SOC_SERIES_AT32F415) || defined (SOC_SERIES_AT32F421) || \
    defined (SOC_SERIES_AT32F425)
99

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    /* select rtc clock source */
#ifdef BSP_RTC_USING_LICK
    crm_ertc_clock_select(CRM_ERTC_CLOCK_LICK);
#else
    crm_ertc_clock_select(CRM_ERTC_CLOCK_LEXT);
#endif /* BSP_RTC_USING_LICK */

    /* enable rtc */
    crm_ertc_clock_enable(TRUE);

    /* wait for ertc registers update */
    ertc_wait_update();

    if (ertc_bpr_data_read(ERTC_DT1)!= BKUP_REG_DATA)
    {
        LOG_I("RTC hasn't been configured, please use <date> command to config.");

        /* configure the ertc divider */
        ertc_divider_set(0x7F, 0xFF);
        /* configure the ertc hour mode */
        ertc_hour_mode_set(ERTC_HOUR_MODE_24);
    }
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
#else

#ifdef BSP_RTC_USING_LICK
    crm_rtc_clock_select(CRM_RTC_CLOCK_LICK);
#else
    crm_rtc_clock_select(CRM_RTC_CLOCK_LEXT);
#endif /* BSP_RTC_USING_LICK */
    /* enable rtc */
    crm_rtc_clock_enable(TRUE);

    /* wait for rtc registers update finish */
    rtc_wait_update_finish();
    /* wait until last write operation on rtc registers has finished */
    rtc_wait_config_finish();

    if (bpr_data_read(BPR_DATA1) != BKUP_REG_DATA)
    {
        LOG_I("RTC hasn't been configured, please use <date> command to config.");
        /* set rtc divider: set rtc period to 1sec */
        rtc_divider_set(32767);
        /* wait until last write operation on rtc registers has finished */
        rtc_wait_config_finish();
    }
#endif

147 148 149 150 151 152 153
    return RT_EOK;
}

static rt_err_t _rtc_init(void)
{
    crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);

154 155 156 157 158
#if defined (SOC_SERIES_AT32F403A) || defined (SOC_SERIES_AT32F407) || \
    defined (SOC_SERIES_AT32F413)
    crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
#endif

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
#ifdef BSP_RTC_USING_LICK
    crm_clock_source_enable(CRM_CLOCK_SOURCE_LICK, TRUE);
    while(crm_flag_get(CRM_LICK_STABLE_FLAG) == RESET);
#else
    pwc_battery_powered_domain_access(TRUE);
    crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
    while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET);
#endif /* BSP_RTC_USING_LICK */

    if (rt_rtc_config() != RT_EOK)
    {
        LOG_E("rtc init failed.");
        return -RT_ERROR;
    }

    return RT_EOK;
}

S
sheltonyu 已提交
177
static rt_err_t _rtc_get_secs(time_t *args)
178 179 180 181 182 183 184
{
    *(rt_uint32_t *)args = get_rtc_timestamp();
    LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args);

    return RT_EOK;
}

S
sheltonyu 已提交
185
static rt_err_t _rtc_set_secs(time_t *args)
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
{
    rt_err_t result = RT_EOK;

    if (set_rtc_time_stamp(*(rt_uint32_t *)args))
    {
        result = -RT_ERROR;
    }
    LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args);

    return result;
}

static const struct rt_rtc_ops _rtc_ops =
{
    _rtc_init,
    _rtc_get_secs,
    _rtc_set_secs,
    RT_NULL,
    RT_NULL,
    RT_NULL,
    RT_NULL,
};

static rt_rtc_dev_t at32_rtc_dev;

int rt_hw_rtc_init(void)
{
    rt_err_t result;
    at32_rtc_dev.ops = &_rtc_ops;
    result = rt_hw_rtc_register(&at32_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR,RT_NULL);
    if (result != RT_EOK)
    {
        LOG_E("rtc register err code: %d", result);
        return result;
    }
    LOG_D("rtc init success");
    return RT_EOK;
}

INIT_DEVICE_EXPORT(rt_hw_rtc_init);

#endif /* BSP_USING_RTC */