/* * Copyright (c) 2018 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief RTC driver for Actions SoC */ #include #include #include #include #include #include #include #include #include //#include #if (CONFIG_PM_BACKUP_TIME_FUNCTION_EN == 1) #include #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); }