123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884 |
- /*
- * Copyright (c) 2018 Actions Semiconductor Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @file
- * @brief RTC driver for Actions SoC
- */
- #include <errno.h>
- #include <device.h>
- #include <init.h>
- #include <kernel.h>
- #include <string.h>
- #include <soc.h>
- #include <board_cfg.h>
- #include <drivers/rtc.h>
- #include <logging/log.h>
- //#include <ksched.h>
- #if (CONFIG_PM_BACKUP_TIME_FUNCTION_EN == 1)
- #include <drivers/nvram_config.h>
- #endif
- LOG_MODULE_REGISTER(rtc0, CONFIG_LOG_DEFAULT_LEVEL);
- #define RTC_DEFAULT_INIT_TIME (1483200000) /* 2016.12.31 16:00:00 */
- /* RTC Control Register */
- #define RTC_CTL_ALIP BIT(0)
- #define RTC_CTL_ALIE BIT(1)
- #define RTC_CTL_4HZ_CLK_SEL_SHIFT (2)
- #define RTC_CTL_4HZ_CLK_SEL_MASK (3 << RTC_CTL_4HZ_CLK_SEL_SHIFT)
- #define RTC_CTL_4HZ_CLK_SEL(x) ((x) << RTC_CTL_4HZ_CLK_SEL_SHIFT)
- #define RTC_CTL_4HZ_CLK_HCL RTC_CTL_4HZ_CLK_SEL(0)
- #define RTC_CTL_4HZ_CLK_32KHZ RTC_CTL_4HZ_CLK_SEL(1)
- #define RTC_CTL_4HZ_CLK_HOSC RTC_CTL_4HZ_CLK_SEL(2)
- #define RTC_CTL_CALEN BIT(4)
- #define RTC_CTL_LEAP BIT(7)
- #define RTC_CTL_32KHZ_SEL BIT(16) /* 0: LOSC 32KHZ; 1 EXT_32KHZ */
- #define RTC_CTL_CAL_CLK_SEL BIT(17) /* 0: 4HZ; 1: 100HZ */
- #define RTC_CTL_TESTEN BIT(18)
- #define RTC_MS_SHIRT (0) /* millisecode x 10 */
- #define RTC_MS_MASK (0x7f << RTC_MS_SHIRT)
- #define RTC_MS(x) (((x) & RTC_MS_MASK) >> RTC_MS_SHIRT)
- #define RTC_MS_MUL10(x) (RTC_MS(x) * 10)
- #define RTC_MS_DIV10(x) (((x) / 10) << RTC_MS_SHIRT)
- #define RTC_YMD_Y_SHIFT (16)
- #define RTC_YMD_Y_MASK (0x7f << RTC_YMD_Y_SHIFT)
- #define RTC_YMD_M_SHIFT (8)
- #define RTC_YMD_M_MASK (0xf << RTC_YMD_M_SHIFT)
- #define RTC_YMD_D_SHIFT (0)
- #define RTC_YMD_D_MASK (0x1f << RTC_YMD_D_SHIFT)
- #define RTC_YMD_Y(ymd) (((ymd) & RTC_YMD_Y_MASK) >> RTC_YMD_Y_SHIFT)
- #define RTC_YMD_M(ymd) (((ymd) & RTC_YMD_M_MASK) >> RTC_YMD_M_SHIFT)
- #define RTC_YMD_D(ymd) (((ymd) & RTC_YMD_D_MASK) >> RTC_YMD_D_SHIFT)
- #define RTC_YMD_VAL(y, m, d) (((y) << RTC_YMD_Y_SHIFT) | ((m) << RTC_YMD_M_SHIFT) | ((d) << RTC_YMD_D_SHIFT))
- #define RTC_HMS_H_SHIFT (16)
- #define RTC_HMS_H_MASK (0x1f << RTC_HMS_H_SHIFT)
- #define RTC_HMS_M_SHIFT (8)
- #define RTC_HMS_M_MASK (0x3f << RTC_HMS_M_SHIFT)
- #define RTC_HMS_S_SHIFT (0)
- #define RTC_HMS_S_MASK (0x3f << RTC_HMS_S_SHIFT)
- #define RTC_HMS_H(ymd) (((ymd) & RTC_HMS_H_MASK) >> RTC_HMS_H_SHIFT)
- #define RTC_HMS_M(ymd) (((ymd) & RTC_HMS_M_MASK) >> RTC_HMS_M_SHIFT)
- #define RTC_HMS_S(ymd) (((ymd) & RTC_HMS_S_MASK) >> RTC_HMS_S_SHIFT)
- #define RTC_HMS_VAL(h, m, s) (((h) << RTC_HMS_H_SHIFT) | ((m) << RTC_HMS_M_SHIFT) | ((s) << RTC_HMS_S_SHIFT))
- #define RTC_REGS_UPDATE_MAGIC (0xA596)
- #define RTC_REGS_UPDATE_OK (0x5A69)
- #define RTC_CONFIG_PERIOD_ALARM_TIMEOUT_MS (1000)
- enum acts_rtc_clock_src {
- RTC_CLKSRC_HOSC_4HZ = 0,
- RTC_CLKSRC_HCL_LOSC_100HZ,
- RTC_CLKSRC_HCL_100HZ,
- };
- struct acts_rtc_controller {
- volatile uint32_t ctrl;
- volatile uint32_t regupdata;
- volatile uint32_t ms_alarm;
- volatile uint32_t hms_alarm;
- volatile uint32_t ymd_alarm;
- volatile uint32_t ms; /* millisecond x 10 */
- volatile uint32_t hms;
- volatile uint32_t ymd;
- };
- struct acts_rtc_data {
- struct acts_rtc_controller *base;
- void (*alarm_cb_fn)(const void *cb_data);
- const void *cb_data;
- struct rtc_alarm_period_config period_config;
- bool alarm_en;
- uint8_t alarm_wakeup : 1; /* System wakeup from RTC alarm indicator */
- uint8_t is_need_sync : 1; /* If 1 to sync ahb clock */
- uint8_t is_set_sync : 1; /* Set the RTC time to ensure that it waits for 3 rtc clk(30ms) before entering sleep mode */
- uint32_t syc_st_cycle;
- uint32_t set_st_ms;
- };
- struct acts_rtc_config {
- struct acts_rtc_controller *base;
- uint8_t rtc_clk_source;
- void (*irq_config)(void);
- };
- static int rtc_acts_set_alarm(const struct device *dev, struct rtc_alarm_config *config, bool enable);
- static int __rtc_acts_set_alarm_period(const struct device *dev);
- static void rtc_acts_dump_regs(struct acts_rtc_controller *base)
- {
- LOG_INF("** RTC Controller register **");
- LOG_INF(" BASE: 0x%x", (uint32_t)base);
- LOG_INF(" CTL: 0x%x", base->ctrl);
- LOG_INF(" REGUPDATE: 0x%x", base->regupdata);
- LOG_INF(" MSALM: 0x%x", base->ms_alarm);
- LOG_INF(" DHMSALM: 0x%x", base->hms_alarm);
- LOG_INF(" YMDALM: 0x%x", base->ymd_alarm);
- LOG_INF(" MS: 0x%x", base->ms);
- LOG_INF(" DHMS: 0x%x", base->hms);
- LOG_INF(" YMD: 0x%x", base->ymd);
- }
- /* RTC associated registers update to take effect */
- void rtc_acts_update_regs(void)
- {
- #if !defined(CONFIG_SOC_SERIES_LARK) && !defined(CONFIG_SOC_SERIES_LEOPARD)
- struct acts_rtc_controller *base = (struct acts_rtc_controller *)RTC_REG_BASE;
- base->regupdata = RTC_REGS_UPDATE_MAGIC;
- while (base->regupdata != RTC_REGS_UPDATE_OK) {
- ; // wait rtc register update
- }
- #endif
- }
- /* Select the LOSC as the clock source which is inside of the HCL controller. */
- static inline void rtc_acts_init_clksource(const struct device *dev, struct acts_rtc_data *rtcd)
- {
- struct acts_rtc_controller *base = rtcd->base;
- const struct acts_rtc_config *cfg = dev->config;
- if (cfg->rtc_clk_source == RTC_CLKSRC_HOSC_4HZ) {
- base->ctrl &= ~RTC_CTL_4HZ_CLK_SEL_MASK;
- base->ctrl |= RTC_CTL_4HZ_CLK_HOSC;
- } else if (cfg->rtc_clk_source == RTC_CLKSRC_HCL_100HZ){
- base->ctrl = RTC_CTL_ALIP | RTC_CTL_4HZ_CLK_HCL; // sel hcl
- sys_write32(0, HCL_CTL);
- k_busy_wait(500);
- //sys_write32(0x8c1, HCL_CTL);// period 4s cal:1s
- sys_write32(0xcc1, HCL_CTL);// period 8s cal:1s
- base->ctrl |= RTC_CTL_CAL_CLK_SEL; /* select 100HZ */
- }else { // RTC_CLKSRC_HCL_LOSC_100HZ
- /* WIO2 => LOSCI; WIO3 => LOSCO */
- sys_write32(1 << 4, WIO2_CTL);
- sys_write32(1 << 4, WIO3_CTL);
- /* enable LOSC */
- sys_write32(0x1a1a71, LOSC_CTL);
- base->ctrl = RTC_CTL_ALIP | RTC_CTL_4HZ_CLK_32KHZ; // sel losc
- sys_write32(0, HCL_CTL);
- k_busy_wait(500);
- sys_write32(0x0c8c, HCL_CTL);
- base->ctrl |= RTC_CTL_CAL_CLK_SEL; /* select 100HZ */
- }
- rtc_acts_update_regs();
- LOG_DBG("rtc_ctl:0x%08x", base->ctrl);
- }
- /**
- * HW ISSUE:
- * software need sleep over 1 RTC period to sync AHB clock.
- */
- static int rtc_pm_sync_ahb(struct acts_rtc_data *rtcd)
- {
- struct acts_rtc_controller *base = rtcd->base;
- uint32_t ymd, hms, ms;
- uint32_t sysn_time_ms;
- if (rtcd->is_need_sync)
- rtcd->is_need_sync = 0;
- else
- return 0;
- ymd = base->ymd;
- hms = base->hms;
- ms = base->ms;
- ms = k_cyc_to_ms_near32(k_cycle_get_32()-rtcd->syc_st_cycle);
- #if (CONFIG_RTC_CLK_SOURCE == 0)
- if(ms >= 300)
- sysn_time_ms = 0;
- else
- sysn_time_ms = 300 - ms; // need over 1 rtc clk
- #else
- if(ms >= 11)
- sysn_time_ms = 0;
- else
- sysn_time_ms = 11 - ms; // need over 1 rtc clk
- #endif
- if(sysn_time_ms){
- if (k_is_in_isr())
- k_busy_wait(sysn_time_ms * 1000);
- else
- k_sleep(K_MSEC(sysn_time_ms));
- }
- ymd = base->ymd;
- hms = base->hms;
- ms = base->ms;
- return 0;
- }
- static int64_t rtc_base_ms, rtc_sys_ms = 0;
- static struct acts_rtc_controller *rtc_reg = NULL;
- static int64_t rtc_acts_get_ms(void)
- {
- int64_t all_ms;
- uint32_t ymd, hms, time;
- uint8_t ms;
- struct rtc_time tm;
- if(rtc_reg == NULL)
- return 0;
- ymd = rtc_reg->ymd;
- hms = rtc_reg->hms;
- ms = rtc_reg->ms;
- tm.tm_ms = RTC_MS_MUL10(ms); /* rtc milisecond 0 ~ 999 */
- tm.tm_sec = RTC_HMS_S(hms); /* rtc second 0-59 */
- tm.tm_min = RTC_HMS_M(hms); /* rtc minute 0-59 */
- tm.tm_hour = RTC_HMS_H(hms); /* rtc hour 0-23 */
- tm.tm_mday = RTC_YMD_D(ymd); /* rtc day 1-31 */
- tm.tm_mon = RTC_YMD_M(ymd) - 1; /* rtc mon 1-12 */
- tm.tm_year = 100 + RTC_YMD_Y(ymd); /* rtc year 0-99 */
- rtc_tm_to_time(&tm, &time);
- all_ms = time;
- all_ms = all_ms*1000+ms;
- return all_ms;
- }
- static void rtc_acts_update_base(struct rtc_time *tm)
- {
- uint32_t time;
- int64_t cur_ms = rtc_acts_get_ms();
- rtc_sys_ms = rtc_sys_ms + (cur_ms - rtc_base_ms) +150;//150 lost
- rtc_tm_to_time(tm, &time);
- rtc_base_ms = time;
- rtc_base_ms = rtc_base_ms*1000+tm->tm_ms;
- }
- static void rtc_acts_base_init(void)
- {
- rtc_base_ms = rtc_acts_get_ms();
- rtc_sys_ms = rtc_base_ms;
- }
- int64_t k_uptime_get_by_rtc(void)
- {
- uint32_t key;
- int64_t cur_ms;
- key = irq_lock();
- cur_ms = rtc_sys_ms + (rtc_acts_get_ms() - rtc_base_ms);
- irq_unlock(key);
- return cur_ms;
- }
- static int rtc_acts_get_datetime(struct acts_rtc_data *rtcd, struct rtc_time *tm)
- {
- struct acts_rtc_controller *base = rtcd->base;
- uint32_t ymd, hms, time;
- uint8_t ms;
- rtc_pm_sync_ahb(rtcd);
- ymd = base->ymd;
- hms = base->hms;
- ms = base->ms;
- tm->tm_ms = RTC_MS_MUL10(ms); /* rtc milisecond 0 ~ 999 */
- tm->tm_sec = RTC_HMS_S(hms); /* rtc second 0-59 */
- tm->tm_min = RTC_HMS_M(hms); /* rtc minute 0-59 */
- tm->tm_hour = RTC_HMS_H(hms); /* rtc hour 0-23 */
- tm->tm_mday = RTC_YMD_D(ymd); /* rtc day 1-31 */
- tm->tm_wday = 0;
- tm->tm_mon = RTC_YMD_M(ymd) - 1; /* rtc mon 1-12 */
- tm->tm_year = 100 + RTC_YMD_Y(ymd); /* rtc year 0-99 */
- LOG_DBG("read date time: %04d-%02d-%02d %02d:%02d:%02d:%03d",
- 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_ms);
- rtc_tm_to_time(tm, &time);
- /* day of the week, 1970-01-01 was a Thursday */
- tm->tm_wday = (time / 86400 + 4) % 7;
- /* the clock can give out invalid datetime, but we cannot return
- * -EINVAL otherwise hwclock will refuse to set the time on bootup.
- */
- if (rtc_valid_tm(tm) < 0) {
- LOG_ERR("rtc: retrieved date/time is not valid.\n");
- rtc_acts_dump_regs(base);
- }
- return 0;
- }
- static int rtc_acts_set_datetime(struct acts_rtc_data *rtcd, struct rtc_time *tm)
- {
- struct acts_rtc_controller *base = rtcd->base;
- uint32_t key;
- LOG_INF("set datetime: %04d-%02d-%02d %02d:%02d:%02d:%03d",
- 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_ms);
- /* disable calendar when update the hms register
- * From the specification discription, the CAL_EN bit must be disable when
- * the RTC_DHMS/RTC_YMD registers being written. And RTC_DHMS/RTC_YMD
- * registers must be written before CAL_EN is enabled.
- */
- key = irq_lock();
- rtc_acts_update_base(tm);
- base->ctrl &= ~RTC_CTL_CALEN;
- rtc_acts_update_regs();
- base->ymd = RTC_YMD_VAL(tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday);
- base->hms = RTC_HMS_VAL(tm->tm_hour, tm->tm_min, tm->tm_sec);
- base->ms = RTC_MS_DIV10(tm->tm_ms);
- rtc_acts_update_regs();
- base->ctrl |= RTC_CTL_CALEN;
- irq_unlock(key);
- rtc_acts_update_regs();
- if(soc_in_sleep_mode()){
- soc_udelay(40*1000);
- }else{
- rtcd->is_set_sync = 1;
- rtcd->set_st_ms = k_uptime_get();
- }
- return 0;
- }
- static void rtc_acts_set_alarm_interrupt(struct acts_rtc_controller *base, bool enable)
- {
- if (enable)
- base->ctrl |= RTC_CTL_ALIE;
- else
- base->ctrl &= ~RTC_CTL_ALIE;
- rtc_acts_update_regs();
- }
- /* get & clear alarm irq pending */
- static uint32_t rtc_acts_get_pending_int(const struct device *dev)
- {
- struct acts_rtc_data *rtcd = dev->data;
- struct acts_rtc_controller *base = rtcd->base;
- int pending;
- pending = base->ctrl & RTC_CTL_ALIP;
- if (pending) {
- /* clear pending */
- base->ctrl |= RTC_CTL_ALIP;
- LOG_INF("Clear old RTC alarm pending");
- rtc_acts_update_regs();
- }
- return pending;
- }
- static void rtc_acts_enable(const struct device *dev)
- {
- struct acts_rtc_data *rtcd = dev->data;
- struct acts_rtc_controller *base = rtcd->base;
- base->ctrl |= RTC_CTL_CALEN;
- rtc_acts_update_regs();
- }
- static void rtc_acts_disable(const struct device *dev)
- {
- struct acts_rtc_data *rtcd = dev->data;
- struct acts_rtc_controller *base = rtcd->base;
- base->ctrl &= ~RTC_CTL_CALEN;
- rtc_acts_update_regs();
- }
- static int rtc_acts_get_time(const struct device *dev, struct rtc_time *tm)
- {
- struct acts_rtc_data *rtcd = dev->data;
- if (!tm)
- return -EINVAL;
- if (rtc_acts_get_datetime(rtcd, tm)) {
- LOG_ERR("failed to get datetime");
- return -EACCES;
- }
- return 0;
- }
- static void rtc_acts_period_alarm_cb_fn(const void *cb_data);
- static int rtc_acts_set_time(const struct device *dev, const struct rtc_time *tm)
- {
- struct acts_rtc_data *rtcd = dev->data;
- int ret;
- if (!tm)
- return -EINVAL;
- if (rtc_valid_tm((struct rtc_time *)tm)) {
- LOG_ERR("Bad time structure");
- print_rtc_time((struct rtc_time *)tm);
- return -ENOEXEC;
- }
- ret = rtc_acts_set_datetime(rtcd, (struct rtc_time *)tm);
- if (ret) {
- LOG_ERR("rtc set time error:%d", ret);
- return ret;
- }
- if (rtcd->period_config.cb_fn) {
- ret = rtc_acts_set_alarm(dev, NULL, false);
- if (!ret)
- //ret = __rtc_acts_set_alarm_period(dev);
- rtc_acts_period_alarm_cb_fn(dev);
- }
- return ret;
- }
- static int rtc_acts_set_alarm_time(const struct acts_rtc_data *rtcd, struct rtc_time *tm)
- {
- struct acts_rtc_controller *base = rtcd->base;
- /* disable alarm interrupt */
- rtc_acts_set_alarm_interrupt(base, false);
- base->ymd_alarm = RTC_YMD_VAL(tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday);
- base->hms_alarm = RTC_HMS_VAL(tm->tm_hour, tm->tm_min, tm->tm_sec);
- base->ms_alarm = RTC_MS_DIV10(tm->tm_ms);
- rtc_acts_update_regs();
- /* enable alarm interrupt */
- rtc_acts_set_alarm_interrupt(base, true);
- LOG_DBG("set alarm: %04d-%02d-%02d %02d:%02d:%02d:%03d",
- 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_ms);
- return 0;
- }
- static int rtc_acts_set_alarm(const struct device *dev, struct rtc_alarm_config *config, bool enable)
- {
- struct acts_rtc_data *rtcd = dev->data;
- int ret = 0;
- /* clear old alarm pending */
- rtc_acts_get_pending_int(dev);
- if (enable) {
- if (!config) {
- LOG_ERR("no alarm configuration");
- return -EINVAL;
- }
- if (rtc_valid_tm(&config->alarm_time)) {
- LOG_ERR("Bad time structure");
- print_rtc_time(&config->alarm_time);
- return -ENOEXEC;
- }
- rtcd->alarm_cb_fn = config->cb_fn;
- rtcd->cb_data = config->cb_data;
- rtcd->alarm_en = true;
- ret = rtc_acts_set_alarm_time(rtcd, &config->alarm_time);
- } else {
- rtc_acts_set_alarm_interrupt(rtcd->base, false);
- rtcd->alarm_en = false;
- rtcd->alarm_cb_fn = NULL;
- rtcd->cb_data = NULL;
- }
- return ret;
- }
- static int rtc_acts_get_alarm(const struct device *dev, struct rtc_alarm_status *sts)
- {
- struct acts_rtc_data *rtcd = dev->data;
- struct acts_rtc_controller *base = rtcd->base;
- struct rtc_time *tm = &sts->alarm_time;
- uint32_t hms;
- uint32_t ymd;
- uint8_t ms;
- if (!sts)
- return -EINVAL;
- memset(sts, 0, sizeof(struct rtc_alarm_status));
- sts->is_on = rtcd->alarm_en;
- hms = base->hms_alarm;
- tm->tm_sec = RTC_HMS_S(hms); /* rtc second 0-59 */
- tm->tm_min = RTC_HMS_M(hms); /* rtc minute 0-59 */
- tm->tm_hour = RTC_HMS_H(hms); /* rtc hour 0-23 */
- ymd = base->ymd_alarm;
- tm->tm_mday = RTC_YMD_D(ymd); /* rtc day 1-31 */
- tm->tm_wday = 0;
- tm->tm_mon = RTC_YMD_M(ymd) - 1; /* rtc mon 1-12 */
- tm->tm_year = 100 + RTC_YMD_Y(ymd); /* rtc year 0-99 */
- ms = base->ms_alarm;
- tm->tm_ms = RTC_MS_MUL10(ms); /* rtc millisecond 0-999 */
- return 0;
- }
- static int __rtc_acts_set_alarm_period(const struct device *dev)
- {
- struct acts_rtc_data *rtcd = dev->data;
- struct rtc_alarm_config alarm_config = {0};
- struct rtc_time tm = {0}, _tm = {0};
- uint32_t time, ms, _time;
- int ret = -1;
- struct rtc_alarm_period_config *config = &rtcd->period_config;
- uint32_t timestamp = k_uptime_get_32();
- while (1) {
- rtc_acts_get_time(dev, &tm);
- rtc_tm_to_time(&tm, &time);
- if ((tm.tm_ms + config->tm_msec) >= 1000) {
- time += 1;
- ms = tm.tm_ms + config->tm_msec - 1000;
- } else {
- ms = tm.tm_ms + config->tm_msec;
- }
- time += config->tm_sec;
- rtc_time_to_tm(time, &tm);
- tm.tm_ms = ms;
- memcpy(&alarm_config.alarm_time, &tm, sizeof(struct rtc_time));
- alarm_config.cb_fn = rtc_acts_period_alarm_cb_fn;
- alarm_config.cb_data = (const void *)dev;
- ret = rtc_acts_set_alarm(dev, &alarm_config, true);
- if (ret)
- return ret;
- rtc_acts_get_time(dev, &_tm);
- rtc_tm_to_time(&_tm, &_time);
- //print_rtc_time(&_tm);
- if ((_tm.tm_ms <= tm.tm_ms) && (_time == time))
- break;
- if ((_tm.tm_ms > tm.tm_ms) && (time == (_time + 1)))
- break;
- if (_time < time)
- break;
- if ((k_uptime_get_32() - timestamp)
- < RTC_CONFIG_PERIOD_ALARM_TIMEOUT_MS) {
- LOG_ERR("set period alarm timeout");
- return -ETIMEDOUT;
- }
- }
- return 0;
- }
- static void rtc_acts_period_alarm_cb_fn(const void *cb_data)
- {
- const struct device *dev = (const struct device *)cb_data;
- struct acts_rtc_data *rtcd = dev->data;
- if (rtcd->period_config.cb_fn)
- rtcd->period_config.cb_fn(rtcd->period_config.cb_data);
- __rtc_acts_set_alarm_period(dev);
- }
- static int rtc_acts_set_period_alarm(const struct device *dev,
- struct rtc_alarm_period_config *config, bool enable)
- {
- struct acts_rtc_data *rtcd = dev->data;
- int ret;
- if (enable) {
- memcpy(&rtcd->period_config, config, sizeof(struct rtc_alarm_period_config));
- ret = __rtc_acts_set_alarm_period(dev);
- } else {
- memset(&rtcd->period_config, 0, sizeof(struct rtc_alarm_period_config));
- ret = rtc_acts_set_alarm(dev, NULL, false);
- }
- return ret;
- }
- void rtc_acts_isr(const struct device *dev)
- {
- struct acts_rtc_data *rtcd = dev->data;
- struct acts_rtc_controller *base = rtcd->base;
- int pending = base->ctrl & RTC_CTL_ALIP;
- LOG_DBG("alarm isr ctl:0x%x", base->ctrl);
- if (pending)
- base->ctrl |= RTC_CTL_ALIP; /* clear pending */
- /* disable alarm irq */
- rtc_acts_set_alarm_interrupt(rtcd->base, false);
- if (pending && rtcd->alarm_en && rtcd->alarm_cb_fn) {
- LOG_DBG("call alarm_cb_fn %p", rtcd->alarm_cb_fn);
- rtcd->alarm_cb_fn(rtcd->cb_data);
- }
- }
- #if (CONFIG_PM_BACKUP_TIME_FUNCTION_EN == 1)
- static int rtc_acts_compensate_datatime(struct acts_rtc_data *rtcd)
- {
- int ret;
- struct sys_pm_backup_time pm_bak_time = {0};
- struct rtc_time tm = {0};
- uint32_t counter8hz_cycles, interval_cycles, cur_time_sec, ms, use_sec;
- #if (CONFIG_RTC_CLK_SOURCE == 2)
- uint32_t rc32k_freq;
- rc32k_freq = acts_clock_rc32k_set_cal_cyc(200);
- printk("cur rc32k_freq=%d\n", rc32k_freq);
- #endif
- ret = nvram_config_get(CONFIG_PM_BACKUP_TIME_NVRAM_ITEM_NAME,
- &pm_bak_time, sizeof(struct sys_pm_backup_time));
- if ((ret == sizeof(struct sys_pm_backup_time))
- && (pm_bak_time.is_backup_time_valid)) {
- ret = soc_pmu_get_counter8hz_cycles(true);
- if (ret > 0) {
- counter8hz_cycles = ret;
- printk("power on current 8hz: %d\n", counter8hz_cycles);
- /* counter8hz overflow */
- if (counter8hz_cycles < pm_bak_time.counter8hz_cycles) {
- interval_cycles = PMU_COUTNER8HZ_MAX - pm_bak_time.counter8hz_cycles + counter8hz_cycles;
- } else {
- interval_cycles = counter8hz_cycles - pm_bak_time.counter8hz_cycles;
- }
- cur_time_sec = pm_bak_time.rtc_time_sec;
- #if (CONFIG_RTC_CLK_SOURCE == 2)
- ms = sys_pmu_8hzcycle_to_ms(interval_cycles, pm_bak_time.rc32k_freq + rc32k_freq);
- use_sec = ms/1000;
- ms += pm_bak_time.rtc_time_msec + 9; // 9 is align 10
- cur_time_sec += ms / 1000;
- ms = ms % 1000 ;
- #else
- use_sec = interval_cycles / 8;
- cur_time_sec += use_sec;
- ms = (interval_cycles / 8)*125 + pm_bak_time.rtc_time_msec + 9;
- if(ms >= 1000){
- cur_time_sec++;
- ms -= 1000;
- }
- #endif
- uint32_t key = irq_lock();
- rtc_time_to_tm(cur_time_sec, &tm);
- tm.tm_ms = ms;
- rtc_acts_set_datetime(rtcd, &tm);
- /* set alarm wakeup flag */
- rtcd->alarm_wakeup = true;
- irq_unlock(key);
- #if (CONFIG_RTC_CLK_SOURCE == 2)
- printk("S4 sleep interval: %ds update, bk_rc32k=%d, rc32k_now=%d\n",
- use_sec, pm_bak_time.rc32k_freq, rc32k_freq);
- #if IS_ENABLED(CONFIG_RTC_ENABLE_CALIBRATION) /*rtc calibration use alarm, recovery user alarm*/
- if(pm_bak_time.is_user_alarm_on){
- if(pm_bak_time.user_alarm_cycles > counter8hz_cycles){
- interval_cycles = pm_bak_time.user_alarm_cycles - counter8hz_cycles;
- }else{
- interval_cycles = PMU_COUTNER8HZ_MAX - counter8hz_cycles + pm_bak_time.user_alarm_cycles;
- }
- ms = (uint64_t)interval_cycles*32768*125 /rc32k_freq; // cal real ms
- printk("recovery alarm: after %d ms, inter=%d, bk=%d\n", ms, interval_cycles, pm_bak_time.user_alarm_cycles);
- soc_pmu_alarm8hz_enable(ms);
- }else if(pm_bak_time.is_use_alarm_cal){ //use alarm cal rc32k rtc in system poweroff
- printk("cali use alarm: power on need disable alarm\n");
- soc_pmu_alarm8hz_disable();
- }
- #endif
- #else
- printk("S4 sleep interval: %ds update\n", use_sec);
- #endif
- print_rtc_time(&tm);
- memset(&pm_bak_time, 0, sizeof(struct sys_pm_backup_time));
- ret = nvram_config_set(CONFIG_PM_BACKUP_TIME_NVRAM_ITEM_NAME,
- &pm_bak_time, sizeof(struct sys_pm_backup_time));
- if (ret) {
- LOG_ERR("failed to save pm backup time to nvram");
- return ret;
- }
- } else {
- LOG_ERR("failed to get counter8hz");
- return -EIO;
- }
- }
- return 0;
- }
- #endif
- static int rtc_acts_check_datetime(struct acts_rtc_data *rtcd)
- {
- struct rtc_time tm;
- int ret;
- #if (CONFIG_PM_BACKUP_TIME_FUNCTION_EN == 1)
- rtc_acts_compensate_datatime(rtcd);
- #endif
- ret = rtc_acts_get_datetime(rtcd, &tm);
- if (ret)
- return ret;
- if (rtc_valid_tm(&tm) < 0) {
- LOG_ERR("Invalid RTC date/time, set to default!");
- rtc_time_to_tm(RTC_DEFAULT_INIT_TIME, &tm);
- rtc_acts_set_datetime(rtcd, &tm);
- }
- return 0;
- }
- static bool rtc_acts_is_alarm_wakeup(const struct device *dev)
- {
- struct acts_rtc_data *rtcd = dev->data;
- if (rtcd->alarm_wakeup)
- return true;
- else
- return false;
- }
- const struct rtc_driver_api rtc_acts_driver_api = {
- .enable = rtc_acts_enable,
- .disable = rtc_acts_disable,
- .get_time = rtc_acts_get_time,
- .set_time = rtc_acts_set_time,
- .set_alarm = rtc_acts_set_alarm,
- .set_period_alarm = rtc_acts_set_period_alarm,
- .get_alarm = rtc_acts_get_alarm,
- .is_alarm_wakeup = rtc_acts_is_alarm_wakeup,
- };
- int rtc_acts_init(const struct device *dev)
- {
- const struct acts_rtc_config *cfg = dev->config;
- struct acts_rtc_data *rtcd = dev->data;
- struct acts_rtc_controller *base = cfg->base;
- rtcd->base = base;
- rtcd->alarm_wakeup = false;
- rtc_reg = base;
- if (soc_pmu_is_alarm_wakeup())
- rtcd->alarm_wakeup = true;
- /* By default to disable RTC alarm IRQ */
- if (base->ctrl & RTC_CTL_ALIE)
- base->ctrl |= RTC_CTL_ALIE;
- rtc_acts_init_clksource(dev, rtcd);
- /* By default to enable the rtc function */
- rtc_acts_enable(dev);
- rtc_acts_check_datetime(rtcd);
- cfg->irq_config();
- rtc_acts_base_init();
- printk("rtc initialized\n");
- return 0;
- }
- #ifdef CONFIG_PM_DEVICE
- int rtc_pm_control(const struct device *dev, enum pm_device_action action)
- {
- struct acts_rtc_data *rtcd = dev->data;
- uint32_t ms;
- switch (action) {
- case PM_DEVICE_ACTION_RESUME:
- rtcd->syc_st_cycle = k_cycle_get_32();
- //rtcd->is_need_sync = 1;
- break;
- case PM_DEVICE_ACTION_SUSPEND:
- rtcd->is_need_sync = 0;
- if(rtcd->is_set_sync){
- rtcd->is_set_sync = 0;
- ms = k_uptime_get() - rtcd->set_st_ms;
- if(ms < 40){
- printk("rtc wait %d ms\n", 40-ms);
- soc_udelay((40-ms)*1000); /*wait time (>3clk(40ms)) to rtc set sync*/
- }
- }
- break;
- case PM_DEVICE_ACTION_EARLY_SUSPEND:
- if (!soc_get_aod_mode())
- rtc_acts_set_alarm_interrupt(rtcd->base, false);
- break;
- case PM_DEVICE_ACTION_LATE_RESUME:
- if (!soc_get_aod_mode())
- __rtc_acts_set_alarm_period(dev);
- break;
- default:
- return 0;
- }
- return 0;
- }
- #else
- #define rtc_pm_control NULL
- #endif
- static void rtc_acts_irq_config(void);
- __act_s2_sleep_data struct acts_rtc_data rtc_acts_ddata;
- static const struct acts_rtc_config rtc_acts_cdata = {
- .base = (struct acts_rtc_controller *)RTC_REG_BASE,
- .rtc_clk_source = CONFIG_RTC_CLK_SOURCE,
- .irq_config = rtc_acts_irq_config,
- };
- DEVICE_DEFINE(rtc0, CONFIG_RTC_0_NAME, rtc_acts_init, rtc_pm_control,
- &rtc_acts_ddata, &rtc_acts_cdata,
- POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
- &rtc_acts_driver_api);
- static void rtc_acts_irq_config(void)
- {
- IRQ_CONNECT(IRQ_ID_RTC, CONFIG_RTC_IRQ_PRI,
- rtc_acts_isr, DEVICE_GET(rtc0), 0);
- irq_enable(IRQ_ID_RTC);
- }
|