/** * @file sdrv_rtc_reg.c * @brief semidrive sec_rtc driver * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include "sdrv_rtc_reg.h" #include "reg.h" #include "bits.h" #include "udelay/udelay.h" #if CONFIG_RTC_SS_DYNAMIC_PCLK #define RTC_SS_ACCESS_DELAY_CYCLE(n) udelay(35 * n) #else #define RTC_SS_ACCESS_DELAY_CYCLE(n) #endif uint64_t sec_rtc_get_tick(Rtc *rtc) { RTC_SS_ACCESS_START(); RTC_SS_ACCESS_DELAY_CYCLE(1); uint64_t tick = rtc->RTC_L; tick = (uint64_t)(rtc->RTC_H_HOLD_SHADOW) << 32; tick |= rtc->RTC_L_HOLD_SHADOW; RTC_SS_ACCESS_END(); return tick; } void sec_rtc_set_tick(Rtc *rtc, uint64_t v) { RTC_SS_ACCESS_START(); uint32_t tick = v & 0xffffffff; rtc->RTC_L = tick; rtc->RTC_H = (v >> 32) & 0xffff; RTC_SS_ACCESS_END(); } void sec_rtc_lock(Rtc *rtc) { RTC_SS_ACCESS_START(); rtc->SEC_RTC_CTRL |= BM_SEC_RTC_CTRL_LOCK; RTC_SS_ACCESS_END(); } bool sec_rtc_is_locked(Rtc *rtc) { bool locked = false; if (rtc->SEC_RTC_CTRL & BM_SEC_RTC_CTRL_LOCK) locked = true; return locked; } int sec_rtc_local_enable(Rtc *rtc, bool en) { RTC_SS_ACCESS_START(); if (!sec_rtc_is_locked(rtc)) { if (en) rtc->SEC_RTC_CTRL |= BM_SEC_RTC_CTRL_RTC_LOCAL_ENABLE; else rtc->SEC_RTC_CTRL &= ~BM_SEC_RTC_CTRL_RTC_LOCAL_ENABLE; RTC_SS_ACCESS_END(); return 0; } RTC_SS_ACCESS_END(); return -1; } void sec_rtc_set_alarm_tick(Rtc *rtc, uint64_t val) { RTC_SS_ACCESS_START(); rtc->TIMER_L = (uint32_t)(val & 0xffffffff); rtc->TIMER_H = (val >> 32) & 0xffff; RTC_SS_ACCESS_END(); } uint64_t sec_rtc_get_alarm_tick(Rtc *rtc) { RTC_SS_ACCESS_START(); uint64_t tick = (uint64_t)(rtc->TIMER_H) << 32; tick |= rtc->TIMER_L; RTC_SS_ACCESS_END(); return tick; } uint8_t sec_rtc_is_alarm_enable(Rtc *rtc) { RTC_SS_ACCESS_START(); uint32_t val = rtc->WAKEUP_CTRL; RTC_SS_ACCESS_END(); return (val & (BM_WAKEUP_CTRL_ENABLE | BM_WAKEUP_CTRL_IRQ_ENABLE | BM_WAKEUP_CTRL_REQ_ENABLE)); } bool sec_rtc_get_wakeup_status(Rtc *rtc) { RTC_SS_ACCESS_START(); if (rtc->WAKEUP_CTRL & BM_WAKEUP_CTRL_STATUS) { RTC_SS_ACCESS_END(); return true; } RTC_SS_ACCESS_END(); return false; } void sec_rtc_clear_wakeup_status(Rtc *rtc) { RTC_SS_ACCESS_START(); rtc->WAKEUP_CTRL |= BM_WAKEUP_CTRL_CLEAR; RTC_SS_ACCESS_END(); sec_rtc_set_cross_clk_en(rtc); RTC_SS_ACCESS_START(); rtc->WAKEUP_CTRL &= ~BM_WAKEUP_CTRL_CLEAR; RTC_SS_ACCESS_END(); sec_rtc_set_cross_clk_en(rtc); } bool sec_rtc_get_overflow_status(Rtc *rtc) { RTC_SS_ACCESS_START(); if (rtc->WAKEUP_CTRL & BM_WAKEUP_CTRL_STATUS) { RTC_SS_ACCESS_END(); return true; } RTC_SS_ACCESS_END(); return false; } void sec_rtc_clear_violation_status(Rtc *rtc, uint8_t vio) { RTC_SS_ACCESS_START(); rtc->VIOLATION_INT = (rtc->VIOLATION_INT & ~BM_VIOLATION_INT_DISABLE_STATUS) | (vio << BM_VIOLATION_INT_OVERFLOW_STATS_BIT); rtc->WAKEUP_CTRL |= (vio << BM_WAKEUP_CTRL_OVERFLOW_CLEAR_BIT); udelay(150); rtc->WAKEUP_CTRL &= ~(vio << BM_WAKEUP_CTRL_OVERFLOW_CLEAR_BIT); udelay(150); RTC_SS_ACCESS_END(); } uint64_t sec_rtc_get_hld_tick(Rtc *rtc, uint64_t *tick) { if (tick) *tick = sec_rtc_get_tick(rtc); RTC_SS_ACCESS_START(); uint64_t tick_hld = (uint64_t)(rtc->RTC_H_HOLD_SHADOW) << 32; tick_hld |= rtc->RTC_L_HOLD_SHADOW; RTC_SS_ACCESS_END(); return tick_hld; } void sec_rtc_set_rtc_ctrl(Rtc *rtc, uint32_t ctrl) { RTC_SS_ACCESS_START(); rtc->SEC_RTC_CTRL = ctrl; RTC_SS_ACCESS_END(); } void sec_rtc_set_cross_clk_en(Rtc *rtc) { uint32_t cnt = 0; RTC_SS_ACCESS_START(); rtc->RTC_REGISTER_CROSS_CLOCK |= BM_RTC_REGISTER_CROSS_CLOCK_REGISTER_CROSS_CLOCK_EN; udelay(120); while ((rtc->RTC_REGISTER_CROSS_CLOCK & BM_RTC_REGISTER_CROSS_CLOCK_REGISTER_CROSS_CLOCK_EN) && (cnt < 120)) { udelay(1); cnt ++; }; RTC_SS_ACCESS_END(); udelay(120); } void sec_rtc_wakeup_enable(Rtc *rtc, uint8_t vtype, uint8_t en) { RTC_SS_ACCESS_START(); uint32_t v = rtc->WAKEUP_CTRL; if (en) v |= vtype; else v &= ~vtype; rtc->WAKEUP_CTRL = v; RTC_SS_ACCESS_END(); sec_rtc_set_cross_clk_en(rtc); } void sec_rtc_ms_cfg(Rtc *master, Rtc *slave, uint8_t ctmode1, uint8_t ctmode2) { RTC_SS_ACCESS_START(); master->RTC_WORKING_MODE = BM_RTC_WORKING_MODE_RTC_MASTER_SLAVE; if (ctmode1) master->RTC_WORKING_MODE |= BM_RTC_WORKING_MODE_RTC_COUNT_MODE; slave->RTC_WORKING_MODE &= ~BM_RTC_WORKING_MODE_RTC_MASTER_SLAVE; if (ctmode2) slave->RTC_WORKING_MODE |= BM_RTC_WORKING_MODE_RTC_COUNT_MODE; RTC_SS_ACCESS_END(); } void sec_rtc_set_violation_enable(Rtc *rtc, uint8_t mask) { if (rtc) { /* do not clear BM_VIOLATION_INT_DISABLE_STATUS */ RTC_SS_ACCESS_START(); rtc->VIOLATION_INT = (rtc->VIOLATION_INT & ~BM_VIOLATION_INT_DISABLE_STATUS) | FV_VIOLATION_INT_MASK(mask); RTC_SS_ACCESS_END(); } } void sec_rtc_set_violation_disable(Rtc *rtc, uint8_t mask) { if (rtc) { RTC_SS_ACCESS_START(); /* do not clear BM_VIOLATION_INT_DISABLE_STATUS */ rtc->VIOLATION_INT &= (~FV_VIOLATION_INT_MASK(mask) & ~BM_VIOLATION_INT_DISABLE_STATUS); RTC_SS_ACCESS_END(); } } uint8_t sec_rtc_get_violation_status(Rtc *rtc) { RTC_SS_ACCESS_START(); uint32_t val = rtc->VIOLATION_INT; RTC_SS_ACCESS_END(); return ((val & (BM_VIOLATION_INT_OVERFLOW_STATS | BM_VIOLATION_INT_DISABLE_STATUS)) >> BM_VIOLATION_INT_OVERFLOW_STATS_BIT); } uint32_t sec_rtc_read_general_purpose_reg(Rtc *rtc, uint8_t gp_num) { uint32_t ret = 0; RTC_SS_ACCESS_START(); switch (gp_num) { case 0: ret = rtc->GP0; break; case 1: ret = rtc->GP1; break; case 2: ret = rtc->GP2; break; case 3: ret = rtc->GP3; break; default: ret = rtc->GP0; break; } RTC_SS_ACCESS_END(); return ret; } void sec_rtc_write_general_purpose_reg(Rtc *rtc, uint8_t gp_num, uint32_t value) { RTC_SS_ACCESS_START(); switch (gp_num) { case 0: rtc->GP0 = value; break; case 1: rtc->GP1 = value; break; case 2: rtc->GP2 = value; break; case 3: rtc->GP3 = value; break; default: rtc->GP0 = value; break; } RTC_SS_ACCESS_END(); }