summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShicheng Chu <[email protected]>2024-03-08 06:18:53 +0800
committerGitHub <[email protected]>2024-03-07 17:18:53 -0500
commit5d70f98e4dfa7069dd37fab3ebec898ff2e2e7ff (patch)
tree93b0f54d669590f052ddba16f1e8f626a00d58d9
parentc3416c58687759f569b8811de04b68992410cc3d (diff)
[bsp][cvitek] add rtc driver (#8586)
-rwxr-xr-xbsp/cvitek/c906_little/board/Kconfig5
-rwxr-xr-xbsp/cvitek/drivers/SConscript3
-rw-r--r--bsp/cvitek/drivers/drv_rtc.c329
3 files changed, 337 insertions, 0 deletions
diff --git a/bsp/cvitek/c906_little/board/Kconfig b/bsp/cvitek/c906_little/board/Kconfig
index 03f664e89c..3780246c59 100755
--- a/bsp/cvitek/c906_little/board/Kconfig
+++ b/bsp/cvitek/c906_little/board/Kconfig
@@ -86,4 +86,9 @@ menu "General Drivers Configuration"
bool "Enable PWM 3"
default n
endif
+
+ config BSP_USING_RTC
+ bool "Enable RTC"
+ select RT_USING_RTC
+ default n
endmenu
diff --git a/bsp/cvitek/drivers/SConscript b/bsp/cvitek/drivers/SConscript
index a32eb05378..519df88a0e 100755
--- a/bsp/cvitek/drivers/SConscript
+++ b/bsp/cvitek/drivers/SConscript
@@ -26,6 +26,9 @@ if GetDepend('BSP_USING_PWM'):
CPPPATH += [cwd + r'/cv1800b/pwm']
CPPDEFINES += ['-DCONFIG_64BIT']
+if GetDepend('BSP_USING_RTC'):
+ src += ['drv_rtc.c']
+
group = DefineGroup('drivers', src, depend = [''], CPPDEFINES = CPPDEFINES, CPPPATH = CPPPATH)
Return('group')
diff --git a/bsp/cvitek/drivers/drv_rtc.c b/bsp/cvitek/drivers/drv_rtc.c
new file mode 100644
index 0000000000..975b361a1c
--- /dev/null
+++ b/bsp/cvitek/drivers/drv_rtc.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-04 ShichengChu the first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#ifdef BSP_USING_RTC
+
+#define DBG_TAG "DRV.RTC"
+#define DBG_LVL DBG_WARNING
+#include <rtdbg.h>
+
+#include "pinctrl.h"
+#include "mmio.h"
+
+#define CVI_RTC_BASE 0x05026000U
+#define RTC_ALARM_O 17
+#define CVI_RTC_CTRL_BASE 0x05025000U
+#define CLK_EN_0 0x03002000U
+#define CLK_RTC_25M_BIT (1 << 8)
+
+/* CVITEK RTC registers */
+#define CVI_RTC_ANA_CALIB 0x0
+#define CVI_RTC_SEC_PULSE_GEN 0x4
+#define CVI_RTC_ALARM_TIME 0x8
+#define CVI_RTC_ALARM_ENABLE 0xC
+#define CVI_RTC_SET_SEC_CNTR_VALUE 0x10
+#define CVI_RTC_SET_SEC_CNTR_TRIG 0x14
+#define CVI_RTC_SEC_CNTR_VALUE 0x18
+#define CVI_RTC_APB_RDATA_SEL 0x3C
+#define CVI_RTC_POR_DB_MAGIC_KEY 0x68
+#define CVI_RTC_EN_PWR_WAKEUP 0xBC
+#define CVI_RTC_PWR_DET_SEL 0x140
+
+/* CVITEK RTC MACRO registers */
+#define RTC_MACRO_DA_CLEAR_ALL 0x480
+#define RTC_MACRO_DA_SOC_READY 0x48C
+#define RTC_MACRO_RO_T 0x4A8
+#define RTC_MACRO_RG_SET_T 0x498
+
+/* CVITEK RTC CTRL registers */
+#define CVI_RTC_FC_COARSE_EN 0x40
+#define CVI_RTC_FC_COARSE_CAL 0x44
+#define CVI_RTC_FC_FINE_EN 0x48
+#define CVI_RTC_FC_FINE_CAL 0x50
+
+#define RTC_SEC_MAX_VAL 0xFFFFFFFF
+
+#define RTC_OFFSET_SN 0x5201800
+
+struct rtc_device_object
+{
+ rt_rtc_dev_t rtc_dev;
+};
+
+static struct rtc_device_object rtc_device;
+
+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
+
+typedef struct {
+ int tm_sec; ///< Second. [0-59]
+ int tm_min; ///< Minute. [0-59]
+ int tm_hour; ///< Hour. [0-23]
+ int tm_mday; ///< Day. [1-31]
+ int tm_mon; ///< Month. [0-11]
+ int tm_year; ///< Year-1900. [70- ] !NOTE:Set 100 mean 2000
+ int tm_wday; ///< Day of week. [0-6 ] !NOTE:Set 0 mean Sunday
+ int tm_yday; ///< Days in year.[0-365] !NOTE:Set 0 mean January 1st
+} cvi_rtc_time_t;
+
+static const unsigned char cvi_rtc_days_in_month[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static inline int is_leap_year(unsigned int year)
+{
+ return (!(year % 4) && (year % 100)) || !(year % 400);
+}
+
+static int rtc_month_days(unsigned int month, unsigned int year)
+{
+ return cvi_rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
+}
+
+static void hal_cvi_rtc_clk_set(int enable)
+{
+ uint32_t clk_state;
+
+ clk_state = mmio_read_32((long unsigned int)CLK_EN_0);
+
+ if(enable)
+ clk_state |= CLK_RTC_25M_BIT;
+ else
+ clk_state &= ~(CLK_RTC_25M_BIT);
+
+ mmio_write_32((long unsigned int)CLK_EN_0, clk_state);
+}
+
+static void hal_cvi_rtc_enable_sec_counter(uintptr_t rtc_base)
+{
+ uint32_t value = 0;
+
+ value = mmio_read_32(rtc_base + CVI_RTC_SEC_PULSE_GEN) & ~(1 << 31);
+ mmio_write_32(rtc_base + CVI_RTC_SEC_PULSE_GEN, value);
+
+ value = mmio_read_32(rtc_base + CVI_RTC_ANA_CALIB) & ~(1 << 31);
+ mmio_write_32(rtc_base + CVI_RTC_ANA_CALIB, value);
+
+ mmio_read_32(rtc_base + CVI_RTC_SEC_CNTR_VALUE);
+ mmio_write_32(rtc_base + CVI_RTC_ALARM_ENABLE, 0x0);
+}
+
+static void hal_cvi_rtc_set_time(uintptr_t rtc_base, unsigned long sec)
+{
+ mmio_write_32(rtc_base + CVI_RTC_SET_SEC_CNTR_VALUE, sec);
+ mmio_write_32(rtc_base + CVI_RTC_SET_SEC_CNTR_TRIG, 1);
+ mmio_write_32(rtc_base + RTC_MACRO_RG_SET_T, sec);
+ mmio_write_32(rtc_base + RTC_MACRO_DA_CLEAR_ALL, 1);
+ mmio_write_32(rtc_base + RTC_MACRO_DA_SOC_READY, 1);
+ mmio_write_32(rtc_base + RTC_MACRO_DA_CLEAR_ALL, 0);
+ mmio_write_32(rtc_base + RTC_MACRO_RG_SET_T, 0);
+ mmio_write_32(rtc_base + RTC_MACRO_DA_SOC_READY, 0);
+}
+
+static int hal_cvi_rtc_get_time_sec(uintptr_t rtc_base,unsigned long *ret_sec)
+{
+ int ret = 0;
+ unsigned long sec;
+ unsigned long sec_ro_t;
+
+ sec = mmio_read_32(rtc_base + CVI_RTC_SEC_CNTR_VALUE);
+ sec_ro_t = mmio_read_32(rtc_base + RTC_MACRO_RO_T);
+
+ LOG_D("sec=%lx, sec_ro_t=%lx\n", sec, sec_ro_t);
+
+ if (sec_ro_t > 0x30000000) {
+ sec = sec_ro_t;
+ // Writeback to SEC CVI_RTC_SEC_CNTR_VALUE
+ mmio_write_32(rtc_base + CVI_RTC_SET_SEC_CNTR_VALUE, sec);
+ mmio_write_32(rtc_base + CVI_RTC_SET_SEC_CNTR_TRIG, 1);
+ } else if (sec < 0x30000000) {
+ LOG_D("RTC invalid time\n");
+ ret = -EINVAL;
+ }
+
+ *ret_sec = sec;
+
+ return ret;
+}
+
+static inline int64_t div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/*
+ * rtc_time_to_tm64 - Converts time64_t to rtc_time.
+ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
+ */
+static void rtc_time64_to_tm(int64_t time, cvi_rtc_time_t *cvi_tm)
+{
+ unsigned int month, year, secs;
+ int days;
+
+ /* time must be positive */
+ days = div_u64_rem(time, 86400, &secs);
+
+ /* day of the week, 1970-01-01 was a Thursday */
+ cvi_tm->tm_wday = (days + 4) % 7;
+
+ year = 1970 + days / 365;
+ days -= (year - 1970) * 365
+ + LEAPS_THRU_END_OF(year - 1)
+ - LEAPS_THRU_END_OF(1970 - 1);
+ while (days < 0) {
+ year -= 1;
+ days += 365 + is_leap_year(year);
+ }
+ cvi_tm->tm_year = year - 1900;
+ cvi_tm->tm_yday = days + 1;
+
+ for (month = 0; month < 11; month++) {
+ int newdays;
+
+ newdays = days - rtc_month_days(month, year);
+ if (newdays < 0)
+ break;
+ days = newdays;
+ }
+ cvi_tm->tm_mon = month;
+ cvi_tm->tm_mday = days + 1;
+
+ cvi_tm->tm_hour = secs / 3600;
+ secs -= cvi_tm->tm_hour * 3600;
+ cvi_tm->tm_min = secs / 60;
+ cvi_tm->tm_sec = secs - cvi_tm->tm_min * 60;
+}
+
+static int64_t mktime64(const unsigned int year0, const unsigned int mon0,
+ const unsigned int day, const unsigned int hour,
+ const unsigned int min, const unsigned int sec)
+{
+ unsigned int mon = mon0, year = year0;
+
+ /* 1..12 -> 11,12,1..10 */
+ if (0 >= (int) (mon -= 2)) {
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+
+ return ((((int64_t)
+ (year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours - midnight tomorrow handled here */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
+/*
+ * rtc_tm_to_time64 - Converts rtc_time to time64_t.
+ * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
+ */
+static int64_t rtc_tm_to_time64(const cvi_rtc_time_t *cvi_tm)
+{
+ return mktime64(cvi_tm->tm_year + 1900, cvi_tm->tm_mon + 1, cvi_tm->tm_mday,
+ cvi_tm->tm_hour, cvi_tm->tm_min, cvi_tm->tm_sec);
+}
+
+static rt_err_t _rtc_get_timeval(struct timeval *tv)
+{
+ unsigned long sec;
+ cvi_rtc_time_t t = {0};
+ struct tm tm_new = {0};
+
+ hal_cvi_rtc_get_time_sec(CVI_RTC_BASE, &sec);
+ rtc_time64_to_tm(sec, &t);
+
+ tm_new.tm_sec = t.tm_sec;
+ tm_new.tm_min = t.tm_min;
+ tm_new.tm_hour = t.tm_hour;
+ tm_new.tm_wday = t.tm_wday;
+ tm_new.tm_mday = t.tm_mday;
+ tm_new.tm_mon = t.tm_mon;
+ tm_new.tm_year = t.tm_year;
+
+ tv->tv_sec = timegm(&tm_new);
+
+ return RT_EOK;
+}
+
+static rt_err_t _rtc_init(void)
+{
+ hal_cvi_rtc_clk_set(1);
+ hal_cvi_rtc_enable_sec_counter(CVI_RTC_BASE);
+
+ return RT_EOK;
+}
+
+static rt_err_t _rtc_get_secs(time_t *sec)
+{
+ struct timeval tv;
+
+ _rtc_get_timeval(&tv);
+ *(time_t *) sec = tv.tv_sec;
+ LOG_D("RTC: get rtc_time %d", *sec);
+
+ return RT_EOK;
+}
+
+static rt_err_t _rtc_set_secs(time_t *sec)
+{
+ rt_err_t result = RT_EOK;
+ cvi_rtc_time_t t = {0};
+ struct tm tm = {0};
+ unsigned long set_sec;
+
+ gmtime_r(sec, &tm);
+
+ t.tm_sec = tm.tm_sec;
+ t.tm_min = tm.tm_min;
+ t.tm_hour = tm.tm_hour;
+ t.tm_mday = tm.tm_mday;
+ t.tm_mon = tm.tm_mon;
+ t.tm_year = tm.tm_year;
+ t.tm_wday = tm.tm_wday;
+
+ set_sec = rtc_tm_to_time64(&t);
+ hal_cvi_rtc_set_time(CVI_RTC_BASE, set_sec);
+
+ return result;
+}
+
+static const struct rt_rtc_ops _rtc_ops =
+{
+ _rtc_init,
+ _rtc_get_secs,
+ _rtc_set_secs,
+ RT_NULL,
+ RT_NULL,
+ _rtc_get_timeval,
+ RT_NULL,
+};
+
+static int rt_hw_rtc_init(void)
+{
+ rt_err_t result;
+
+ rtc_device.rtc_dev.ops = &_rtc_ops;
+ result = rt_hw_rtc_register(&rtc_device.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 */