drv_rtc.c 4.9 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 * Copyright (c) 2020-2021, Bluetrum Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-01-28     greedyhao         first version
9
 * 2021-03-19     iysheng           modify just set time first power up
10
 * 2021-03-26     iysheng           add alarm and 1s interrupt support
11 12 13 14
 */

#include "board.h"
#include <time.h>
15
#include <sys/time.h>
16 17 18

#ifdef BSP_USING_ONCHIP_RTC

G
greedyhao 已提交
19 20 21 22
#if RTTHREAD_VERSION < 40004
#error "RTTHREAD_VERSION is less than 4.0.4"
#endif

23 24 25 26 27 28 29 30
//#define DRV_DEBUG
#define LOG_TAG             "drv.rtc"
#include <drv_log.h>

static struct rt_device rtc;

/************** HAL Start *******************/
#define IRTC_ENTER_CRITICAL()       uint32_t cpu_ie = PICCON & BIT(0); PICCONCLR = BIT(0);
31
#define IRTC_EXIT_CRITICAL()        PICCON |= cpu_ie
32

33
rt_uint8_t get_weekday(struct tm *const _tm)
34
{
35
    rt_uint8_t weekday;
36
    time_t secs = timegm(_tm);
37 38 39 40 41

    weekday = (secs / 86400 + 4) % 7;
    return weekday;
}

42
void irtc_write(rt_uint32_t cmd)
43 44 45 46 47
{
    RTCDAT = cmd;
    while (RTCCON & RTC_CON_TRANS_DONE);
}

48
rt_uint8_t irtc_read(void)
49 50 51
{
    RTCDAT = 0x00;
    while (RTCCON & RTC_CON_TRANS_DONE);
52
    return (rt_uint8_t)RTCDAT;
53 54
}

55
void irtc_time_write(rt_uint32_t cmd, rt_uint32_t dat)
56 57 58 59
{
    IRTC_ENTER_CRITICAL();
    RTCCON |= RTC_CON_CHIP_SELECT;
    irtc_write(cmd | RTC_WR);
60 61 62 63
    irtc_write((rt_uint8_t)(dat >> 24));
    irtc_write((rt_uint8_t)(dat >> 16));
    irtc_write((rt_uint8_t)(dat >>  8));
    irtc_write((rt_uint8_t)(dat >>  0));
64 65 66 67
    RTCCON &= ~RTC_CON_CHIP_SELECT;
    IRTC_EXIT_CRITICAL();
}

68
rt_uint32_t irtc_time_read(rt_uint32_t cmd)
69
{
70
    rt_uint32_t rd_val;
71 72 73
    IRTC_ENTER_CRITICAL();
    RTCCON |= RTC_CON_CHIP_SELECT;
    irtc_write(cmd | RTC_RD);
74 75 76 77
    *((rt_uint8_t *)&rd_val + 3) = irtc_read();
    *((rt_uint8_t *)&rd_val + 2) = irtc_read();
    *((rt_uint8_t *)&rd_val + 1) = irtc_read();
    *((rt_uint8_t *)&rd_val + 0) = irtc_read();
78 79 80 81 82
    RTCCON &= ~RTC_CON_CHIP_SELECT;
    IRTC_EXIT_CRITICAL();
    return rd_val;
}

83
void irtc_sfr_write(rt_uint32_t cmd, rt_uint8_t dat)
84 85 86 87 88 89 90 91 92
{
    IRTC_ENTER_CRITICAL();
    RTCCON |= RTC_CON_CHIP_SELECT;
    irtc_write(cmd | RTC_WR);
    irtc_write(dat);
    RTCCON &= ~RTC_CON_CHIP_SELECT;
    IRTC_EXIT_CRITICAL();
}

93
rt_uint8_t irtc_sfr_read(rt_uint32_t cmd)
94
{
95
    rt_uint8_t rd_val;
96 97 98 99 100 101 102 103
    IRTC_ENTER_CRITICAL();
    RTCCON |= RTC_CON_CHIP_SELECT;
    irtc_write(cmd | RTC_RD);
    rd_val = irtc_read();
    RTCCON &= ~RTC_CON_CHIP_SELECT;
    IRTC_EXIT_CRITICAL();
}

104 105
static void _init_rtc_clock(void)
{
106 107
    rt_uint8_t rtccon0;
    rt_uint8_t rtccon2;
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

    rtccon0 = irtc_sfr_read(RTCCON0_CMD);
    rtccon2 = irtc_sfr_read(RTCCON2_CMD);
#ifdef RTC_USING_INTERNAL_CLK
    rtccon0 &= ~RTC_CON0_XOSC32K_ENABLE;
    rtccon0 |= RTC_CON0_INTERNAL_32K;
    rtccon2 | RTC_CON2_32K_SELECT;
#else
    rtccon0 |= RTC_CON0_XOSC32K_ENABLE;
    rtccon0 &= ~RTC_CON0_INTERNAL_32K;
    rtccon2 & ~RTC_CON2_32K_SELECT;
#endif
    irtc_sfr_write(RTCCON0_CMD, rtccon0);
    irtc_sfr_write(RTCCON2_CMD, rtccon2);
}

124 125 126 127
void hal_rtc_init(void)
{
    time_t sec = 0;
    struct tm tm_new = {0};
128
    rt_uint8_t temp;
129

130
    _init_rtc_clock();
131
    temp = irtc_sfr_read(RTCCON0_CMD);
132 133
    if (temp & RTC_CON0_PWRUP_FIRST) {
        temp &= ~RTC_CON0_PWRUP_FIRST;
134
        irtc_sfr_write(RTCCON0_CMD, temp); /* First power on */
135 136 137 138
        tm_new.tm_mday = 29;
        tm_new.tm_mon  = 1 - 1;
        tm_new.tm_year = 2021 - 1900;
        sec = timegm(&tm_new);
139

140 141
        irtc_time_write(RTCCNT_CMD, sec);
    }
142 143 144 145 146 147
#ifdef RT_USING_ALARM
    RTCCON |= RTC_CON_ALM_INTERRUPT;
#ifdef RTC_USING_1S_INT
    RTCCON |= RTC_CON_1S_INTERRUPT;
#endif
#endif
148 149 150
}
/************** HAL End *******************/

151
static rt_err_t ab32_rtc_get_secs(void *args)
152
{
153 154
    *(rt_uint32_t *)args = irtc_time_read(RTCCNT_CMD);
    LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args);
155

156
    return RT_EOK;
157 158
}

159
static rt_err_t ab32_rtc_set_secs(void *args)
160
{
161
    irtc_time_write(RTCCNT_CMD, *(rt_uint32_t *)args);
162 163 164 165

    return RT_EOK;
}

166
static rt_err_t ab32_rtc_get_alarm(void *args)
167
{
168
    *(rt_uint32_t *)args = irtc_time_read(RTCALM_CMD);
169 170 171 172

    return RT_EOK;
}

173
static rt_err_t ab32_rtc_set_alarm(void *args)
174
{
175
    irtc_time_write(RTCALM_CMD, *(rt_uint32_t *)args);
176

177
    return RT_EOK;
178 179
}

180
static rt_err_t ab32_rtc_init(void)
181 182 183
{
    hal_rtc_init();

184
    return RT_EOK;
185 186
}

187
static const struct rt_rtc_ops ab32_rtc_ops =
188
{
189 190 191 192 193
    ab32_rtc_init,
    ab32_rtc_get_secs,
    ab32_rtc_set_secs,
    ab32_rtc_get_alarm,
    ab32_rtc_set_alarm,
194 195 196
    RT_NULL,
    RT_NULL,
};
197

198
static rt_rtc_dev_t ab32_rtc_dev;
199

200
static int rt_hw_rtc_init(void)
201 202
{
    rt_err_t result;
203

204 205
    ab32_rtc_dev.ops = &ab32_rtc_ops;
    result = rt_hw_rtc_register(&ab32_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL);
206 207 208 209 210 211
    if (result != RT_EOK)
    {
        LOG_E("rtc register err code: %d", result);
        return result;
    }
    LOG_D("rtc init success");
212

213 214 215 216 217
    return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_rtc_init);

#endif /* BSP_USING_ONCHIP_RTC */