Files
6CAR/drivers/source/rtc/sdrv_rtc_reg.c
2026-04-18 09:16:58 +08:00

317 lines
6.9 KiB
C

/**
* @file sdrv_rtc_reg.c
* @brief semidrive sec_rtc driver
*
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include <types.h>
#include <part.h>
#include <sdrv_ckgen.h>
#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();
}