Updated EFM32 RTC driver from Pierre-noel Bouteville
This commit is contained in:
parent
725e3cab72
commit
302dbd967d
@ -56,6 +56,7 @@
|
||||
|
||||
#include "efm32_rmu.h"
|
||||
#include "efm32_rtc.h"
|
||||
#include "efm32_bitband.h"
|
||||
#include "clock/clock.h"
|
||||
|
||||
/************************************************************************************
|
||||
@ -124,18 +125,14 @@
|
||||
# error "BOARD_BURTC_CLKSRC badly setted !"
|
||||
#endif
|
||||
|
||||
#define __SEC_OFF_REG EFM32_BURTC_RET_REG(2)
|
||||
#define __BASETIME_SEC__OFF_REG EFM32_BURTC_RET_REG(3)
|
||||
#define __CNT_TOP (((uint64_t)(_BURTC_CNT_MASK))+1)
|
||||
#define __CNT_CARRY_REG EFM32_BURTC_RET_REG(0)
|
||||
#define __CNT_ZERO_REG EFM32_BURTC_RET_REG(1)
|
||||
|
||||
#ifdef CONFIG_RTC_HIRES
|
||||
# define __CNT_OFF_REG EFM32_BURTC_RET_REG(0)
|
||||
# define __BASETIME_NSEC_OFF_REG EFM32_BURTC_RET_REG(1)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_DEBUG
|
||||
# define burtcdbg lldbg
|
||||
#if defined CONFIG_DEBUG && defined CONFIG_RTC_DEBUG
|
||||
# define burtcdbg lldbg
|
||||
#else
|
||||
# define burtcdbg(x...)
|
||||
# define burtcdbg(x...)
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
@ -199,11 +196,11 @@ static int efm32_rtc_burtc_interrupt(int irq, void *context)
|
||||
#ifdef CONFIG_RTC_HIRES
|
||||
if (source & BURTC_IF_OF)
|
||||
{
|
||||
int regval;
|
||||
uint32_t regval;
|
||||
|
||||
regval = getreg32(__SEC_OFF_REG);
|
||||
regval += (_BURTC_CNT_MASK+1)/CONFIG_RTC_FREQUENCY;
|
||||
putreg32(regval,__SEC_OFF_REG);
|
||||
regval = getreg32(__CNT_CARRY_REG);
|
||||
regval++;
|
||||
putreg32(regval, __CNT_CARRY_REG);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -242,42 +239,41 @@ static int efm32_rtc_burtc_interrupt(int irq, void *context)
|
||||
static void efm32_rtc_burtc_init(void)
|
||||
{
|
||||
uint32_t regval;
|
||||
uint32_t regval2;
|
||||
|
||||
regval = g_efm32_rstcause;
|
||||
regval2 = getreg32(EFM32_BURTC_CTRL);
|
||||
|
||||
if (!(getreg32(EFM32_BURTC_CTRL) & BURTC_CTRL_RSTEN)
|
||||
&& !(regval & RMU_RSTCAUSE_BUBODREG)
|
||||
&& !(regval & RMU_RSTCAUSE_BUBODUNREG)
|
||||
&& !(regval & RMU_RSTCAUSE_BUBODBUVIN)
|
||||
&& !(regval & RMU_RSTCAUSE_EXTRST)
|
||||
&& !(regval & RMU_RSTCAUSE_PORST)
|
||||
)
|
||||
burtcdbg("BURTC RESETCAUSE=0x%08X BURTC_CTRL=0x%08X\n", regval, regval2);
|
||||
|
||||
if (!(regval2 & BURTC_CTRL_RSTEN) &&
|
||||
!(regval & RMU_RSTCAUSE_BUBODREG) &&
|
||||
!(regval & RMU_RSTCAUSE_BUBODUNREG) &&
|
||||
!(regval & RMU_RSTCAUSE_BUBODBUVIN) &&
|
||||
!(regval & RMU_RSTCAUSE_EXTRST) &&
|
||||
!(regval & RMU_RSTCAUSE_PORST))
|
||||
{
|
||||
g_efm32_burtc_reset_status = getreg32(EFM32_BURTC_STATUS);
|
||||
|
||||
/* Reset timestamp BURTC clear status */
|
||||
|
||||
putreg32(BURTC_CMD_CLRSTATUS,EFM32_BURTC_CMD);
|
||||
putreg32(BURTC_CMD_CLRSTATUS, EFM32_BURTC_CMD);
|
||||
|
||||
/* restore saved base time */
|
||||
|
||||
g_basetime.tv_sec = __BASETIME_SEC__OFF_REG;
|
||||
#ifdef CONFIG_RTC_HIRES
|
||||
g_basetime.tv_nsec = __BASETIME_NSEC_OFF_REG;
|
||||
#else
|
||||
g_basetime.tv_nsec = 0;
|
||||
#endif
|
||||
|
||||
burtcdbg("BURTC OK\n");
|
||||
return;
|
||||
}
|
||||
|
||||
burtcdbg("BURTC RESETED\n");
|
||||
|
||||
/* Disable reset of BackupDomain */
|
||||
|
||||
modifyreg32(EFM32_RMU_CTRL,_RMU_CTRL_BURSTEN_MASK,0);
|
||||
bitband_set_peripheral(EFM32_RMU_CTRL, _RMU_CTRL_BURSTEN_SHIFT, 0);
|
||||
|
||||
/* Make sure all registers are updated simultaneously */
|
||||
|
||||
putreg32(BURTC_FREEZE_REGFREEZE_FREEZE,EFM32_BURTC_FREEZE);
|
||||
putreg32(BURTC_FREEZE_REGFREEZE_FREEZE, EFM32_BURTC_FREEZE);
|
||||
|
||||
/* Restore all not setted BURTC registers to default value */
|
||||
|
||||
@ -297,42 +293,75 @@ static void efm32_rtc_burtc_init(void)
|
||||
|
||||
/* Clear interrupts */
|
||||
|
||||
putreg32(0xFFFFFFFF,EFM32_BURTC_IFC);
|
||||
putreg32(0xFFFFFFFF, EFM32_BURTC_IFC);
|
||||
|
||||
/* Set new configuration */
|
||||
|
||||
putreg32(regval|BURTC_CTRL_RSTEN,EFM32_BURTC_CTRL);
|
||||
putreg32(regval | BURTC_CTRL_RSTEN, EFM32_BURTC_CTRL);
|
||||
|
||||
/* Clear freeze */
|
||||
|
||||
putreg32(0,EFM32_BURTC_FREEZE);
|
||||
putreg32(0, EFM32_BURTC_FREEZE);
|
||||
|
||||
/* To enable BURTC counter, we need to disable reset */
|
||||
|
||||
putreg32(regval,EFM32_BURTC_CTRL);
|
||||
putreg32(regval, EFM32_BURTC_CTRL);
|
||||
|
||||
/* Enable BURTC interrupt on compare match and counter overflow */
|
||||
|
||||
putreg32(BURTC_IF_OF|BURTC_IF_LFXOFAIL, EFM32_BURTC_IEN);
|
||||
putreg32(BURTC_IF_OF | BURTC_IF_LFXOFAIL, EFM32_BURTC_IEN);
|
||||
|
||||
/* Lock BURTC to avoid modification */
|
||||
|
||||
putreg32(BURTC_LOCK_LOCKKEY_LOCK,EFM32_BURTC_LOCK);
|
||||
putreg32(BURTC_LOCK_LOCKKEY_LOCK, EFM32_BURTC_LOCK);
|
||||
|
||||
/* reset BURTC retention REG used */
|
||||
|
||||
putreg32(0,__CNT_OFF_REG);
|
||||
putreg32(0,__SEC_OFF_REG);
|
||||
putreg32(0,__BASETIME_SEC__OFF_REG);
|
||||
#ifdef CONFIG_RTC_HIRES
|
||||
putreg32(0,__BASETIME_NSEC_OFF_REG);
|
||||
#endif
|
||||
putreg32(0, __CNT_CARRY_REG);
|
||||
putreg32(0, __CNT_ZERO_REG);
|
||||
|
||||
/* inform rest of software that BURTC was reset at boot */
|
||||
|
||||
g_efm32_burtc_reseted = true;
|
||||
}
|
||||
|
||||
static uint64_t efm32_get_burtc_tick(void)
|
||||
{
|
||||
uint32_t cnt_carry;
|
||||
uint32_t cnt_zero;
|
||||
uint32_t cnt;
|
||||
uint64_t val;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
do
|
||||
{
|
||||
/* pending IRQ so theat it */
|
||||
|
||||
if (getreg32(EFM32_BURTC_IF) & BURTC_IF_COMP0)
|
||||
{
|
||||
efm32_rtc_burtc_interrupt(EFM32_IRQ_BURTC, NULL);
|
||||
}
|
||||
|
||||
cnt = getreg32(EFM32_BURTC_CNT);
|
||||
cnt_zero = getreg32(__CNT_ZERO_REG);
|
||||
cnt_carry = getreg32(__CNT_CARRY_REG);
|
||||
}
|
||||
|
||||
/* Retry if IRQ appear during register reading */
|
||||
|
||||
while (getreg32(EFM32_BURTC_IF) & BURTC_IF_COMP0);
|
||||
|
||||
irqrestore(flags);
|
||||
|
||||
val = (uint64_t)cnt_carry*__CNT_TOP + cnt + cnt_zero;
|
||||
|
||||
burtcdbg("Get Tick carry %u zero %u reg %u\n", cnt_carry, cnt_carry,cnt);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************************/
|
||||
@ -387,28 +416,7 @@ int up_rtcinitialize(void)
|
||||
#ifndef CONFIG_RTC_HIRES
|
||||
time_t up_rtc_time(void)
|
||||
{
|
||||
time_t t;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
do
|
||||
{
|
||||
/* pending IRQ so theat it */
|
||||
|
||||
if (getreg32(EFM32_BURTC_IF) & BURTC_IF_COMP0)
|
||||
efm32_rtc_burtc_interrupt(EFM32_IRQ_BURTC,NULL);
|
||||
|
||||
t = getreg32(__SEC_OFF_REG) + getreg32(EFM32_BURTC_CNT);
|
||||
}
|
||||
|
||||
/* Retry if IRQ appear during register reading */
|
||||
|
||||
while (getreg32(EFM32_BURTC_IF) & BURTC_IF_COMP0);
|
||||
|
||||
irqrestore(flags);
|
||||
|
||||
return t;
|
||||
return (time_t)efm32_get_burtc_tick()/CONFIG_RTC_FREQUENCY;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -431,36 +439,16 @@ time_t up_rtc_time(void)
|
||||
#ifdef CONFIG_RTC_HIRES
|
||||
int up_rtc_gettime(FAR struct timespec *tp)
|
||||
{
|
||||
time_t t;
|
||||
uint32_t hires_val;
|
||||
irqstate_t flags;
|
||||
uint64_t val;
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
do
|
||||
{
|
||||
/* pending IRQ so theat it */
|
||||
|
||||
if (getreg32(EFM32_BURTC_IF) & BURTC_IF_COMP0)
|
||||
efm32_rtc_burtc_interrupt(EFM32_IRQ_BURTC,NULL);
|
||||
|
||||
t = getreg32(__SEC_OFF_REG);
|
||||
hires_val = getreg32(EFM32_BURTC_CNT) + getreg32(__CNT_OFF_REG);
|
||||
}
|
||||
|
||||
/* Retry if IRQ appear during register reading */
|
||||
|
||||
while (getreg32(EFM32_BURTC_IF) & BURTC_IF_COMP0);
|
||||
|
||||
irqrestore(flags);
|
||||
|
||||
t += hires_val / CONFIG_RTC_FREQUENCY;
|
||||
hires_val = hires_val % CONFIG_RTC_FREQUENCY;
|
||||
val = efm32_get_burtc_tick();
|
||||
|
||||
/* Then we can save the time in seconds and fractional seconds. */
|
||||
|
||||
tp->tv_sec = t;
|
||||
tp->tv_nsec = hires_val * (1000000000/CONFIG_RTC_FREQUENCY);
|
||||
tp->tv_sec = val / CONFIG_RTC_FREQUENCY;
|
||||
tp->tv_nsec = (val % CONFIG_RTC_FREQUENCY)*(NSEC_PER_SEC/CONFIG_RTC_FREQUENCY);
|
||||
|
||||
burtcdbg("Get RTC %u.%09u\n", tp->tv_sec, tp->tv_nsec);
|
||||
|
||||
return OK;
|
||||
}
|
||||
@ -483,14 +471,38 @@ int up_rtc_gettime(FAR struct timespec *tp)
|
||||
|
||||
int up_rtc_settime(FAR const struct timespec *tp)
|
||||
{
|
||||
uint32_t cnt_carry;
|
||||
uint32_t cnt;
|
||||
uint32_t cnt_reg;
|
||||
uint64_t val;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
putreg32(g_basetime.tv_sec, __BASETIME_SEC__OFF_REG);
|
||||
#ifdef CONFIG_RTC_HIRES
|
||||
putreg32(g_basetime.tv_nsec,__BASETIME_NSEC_OFF_REG);
|
||||
#endif
|
||||
cnt_reg = getreg32(EFM32_BURTC_CNT);
|
||||
|
||||
/* Compute Burtc offset because we cannot reset counter */
|
||||
|
||||
val = (((uint64_t)tp->tv_sec) * CONFIG_RTC_FREQUENCY) + \
|
||||
(tp->tv_nsec / (NSEC_PER_SEC / CONFIG_RTC_FREQUENCY));
|
||||
|
||||
if (val < cnt_reg)
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
val -= cnt_reg;
|
||||
}
|
||||
|
||||
cnt_carry = val / __CNT_TOP;
|
||||
cnt = val % __CNT_TOP;
|
||||
|
||||
burtcdbg("Set RTC %u.%09u carry %u zero %u reg %u\n",
|
||||
tp->tv_sec, tp->tv_nsec, cnt_carry, cnt, cnt_reg);
|
||||
|
||||
putreg32(cnt_carry, __CNT_CARRY_REG);
|
||||
putreg32(cnt , __CNT_ZERO_REG);
|
||||
|
||||
irqrestore(flags);
|
||||
return OK;
|
||||
|
Loading…
Reference in New Issue
Block a user