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_rmu.h"
|
||||||
#include "efm32_rtc.h"
|
#include "efm32_rtc.h"
|
||||||
|
#include "efm32_bitband.h"
|
||||||
#include "clock/clock.h"
|
#include "clock/clock.h"
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@ -124,18 +125,14 @@
|
|||||||
# error "BOARD_BURTC_CLKSRC badly setted !"
|
# error "BOARD_BURTC_CLKSRC badly setted !"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __SEC_OFF_REG EFM32_BURTC_RET_REG(2)
|
#define __CNT_TOP (((uint64_t)(_BURTC_CNT_MASK))+1)
|
||||||
#define __BASETIME_SEC__OFF_REG EFM32_BURTC_RET_REG(3)
|
#define __CNT_CARRY_REG EFM32_BURTC_RET_REG(0)
|
||||||
|
#define __CNT_ZERO_REG EFM32_BURTC_RET_REG(1)
|
||||||
|
|
||||||
#ifdef CONFIG_RTC_HIRES
|
#if defined CONFIG_DEBUG && defined CONFIG_RTC_DEBUG
|
||||||
# define __CNT_OFF_REG EFM32_BURTC_RET_REG(0)
|
# define burtcdbg lldbg
|
||||||
# define __BASETIME_NSEC_OFF_REG EFM32_BURTC_RET_REG(1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_DEBUG
|
|
||||||
# define burtcdbg lldbg
|
|
||||||
#else
|
#else
|
||||||
# define burtcdbg(x...)
|
# define burtcdbg(x...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@ -199,11 +196,11 @@ static int efm32_rtc_burtc_interrupt(int irq, void *context)
|
|||||||
#ifdef CONFIG_RTC_HIRES
|
#ifdef CONFIG_RTC_HIRES
|
||||||
if (source & BURTC_IF_OF)
|
if (source & BURTC_IF_OF)
|
||||||
{
|
{
|
||||||
int regval;
|
uint32_t regval;
|
||||||
|
|
||||||
regval = getreg32(__SEC_OFF_REG);
|
regval = getreg32(__CNT_CARRY_REG);
|
||||||
regval += (_BURTC_CNT_MASK+1)/CONFIG_RTC_FREQUENCY;
|
regval++;
|
||||||
putreg32(regval,__SEC_OFF_REG);
|
putreg32(regval, __CNT_CARRY_REG);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -242,42 +239,41 @@ static int efm32_rtc_burtc_interrupt(int irq, void *context)
|
|||||||
static void efm32_rtc_burtc_init(void)
|
static void efm32_rtc_burtc_init(void)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
uint32_t regval2;
|
||||||
|
|
||||||
regval = g_efm32_rstcause;
|
regval = g_efm32_rstcause;
|
||||||
|
regval2 = getreg32(EFM32_BURTC_CTRL);
|
||||||
|
|
||||||
if (!(getreg32(EFM32_BURTC_CTRL) & BURTC_CTRL_RSTEN)
|
burtcdbg("BURTC RESETCAUSE=0x%08X BURTC_CTRL=0x%08X\n", regval, regval2);
|
||||||
&& !(regval & RMU_RSTCAUSE_BUBODREG)
|
|
||||||
&& !(regval & RMU_RSTCAUSE_BUBODUNREG)
|
if (!(regval2 & BURTC_CTRL_RSTEN) &&
|
||||||
&& !(regval & RMU_RSTCAUSE_BUBODBUVIN)
|
!(regval & RMU_RSTCAUSE_BUBODREG) &&
|
||||||
&& !(regval & RMU_RSTCAUSE_EXTRST)
|
!(regval & RMU_RSTCAUSE_BUBODUNREG) &&
|
||||||
&& !(regval & RMU_RSTCAUSE_PORST)
|
!(regval & RMU_RSTCAUSE_BUBODBUVIN) &&
|
||||||
)
|
!(regval & RMU_RSTCAUSE_EXTRST) &&
|
||||||
|
!(regval & RMU_RSTCAUSE_PORST))
|
||||||
{
|
{
|
||||||
g_efm32_burtc_reset_status = getreg32(EFM32_BURTC_STATUS);
|
g_efm32_burtc_reset_status = getreg32(EFM32_BURTC_STATUS);
|
||||||
|
|
||||||
/* Reset timestamp BURTC clear status */
|
/* Reset timestamp BURTC clear status */
|
||||||
|
|
||||||
putreg32(BURTC_CMD_CLRSTATUS,EFM32_BURTC_CMD);
|
putreg32(BURTC_CMD_CLRSTATUS, EFM32_BURTC_CMD);
|
||||||
|
|
||||||
/* restore saved base time */
|
/* restore saved base time */
|
||||||
|
|
||||||
g_basetime.tv_sec = __BASETIME_SEC__OFF_REG;
|
burtcdbg("BURTC OK\n");
|
||||||
#ifdef CONFIG_RTC_HIRES
|
|
||||||
g_basetime.tv_nsec = __BASETIME_NSEC_OFF_REG;
|
|
||||||
#else
|
|
||||||
g_basetime.tv_nsec = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
burtcdbg("BURTC RESETED\n");
|
||||||
|
|
||||||
/* Disable reset of BackupDomain */
|
/* 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 */
|
/* 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 */
|
/* Restore all not setted BURTC registers to default value */
|
||||||
|
|
||||||
@ -297,42 +293,75 @@ static void efm32_rtc_burtc_init(void)
|
|||||||
|
|
||||||
/* Clear interrupts */
|
/* Clear interrupts */
|
||||||
|
|
||||||
putreg32(0xFFFFFFFF,EFM32_BURTC_IFC);
|
putreg32(0xFFFFFFFF, EFM32_BURTC_IFC);
|
||||||
|
|
||||||
/* Set new configuration */
|
/* Set new configuration */
|
||||||
|
|
||||||
putreg32(regval|BURTC_CTRL_RSTEN,EFM32_BURTC_CTRL);
|
putreg32(regval | BURTC_CTRL_RSTEN, EFM32_BURTC_CTRL);
|
||||||
|
|
||||||
/* Clear freeze */
|
/* Clear freeze */
|
||||||
|
|
||||||
putreg32(0,EFM32_BURTC_FREEZE);
|
putreg32(0, EFM32_BURTC_FREEZE);
|
||||||
|
|
||||||
/* To enable BURTC counter, we need to disable reset */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* reset BURTC retention REG used */
|
||||||
|
|
||||||
putreg32(0,__CNT_OFF_REG);
|
putreg32(0, __CNT_CARRY_REG);
|
||||||
putreg32(0,__SEC_OFF_REG);
|
putreg32(0, __CNT_ZERO_REG);
|
||||||
putreg32(0,__BASETIME_SEC__OFF_REG);
|
|
||||||
#ifdef CONFIG_RTC_HIRES
|
|
||||||
putreg32(0,__BASETIME_NSEC_OFF_REG);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* inform rest of software that BURTC was reset at boot */
|
/* inform rest of software that BURTC was reset at boot */
|
||||||
|
|
||||||
g_efm32_burtc_reseted = true;
|
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
|
* Public Functions
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
@ -387,28 +416,7 @@ int up_rtcinitialize(void)
|
|||||||
#ifndef CONFIG_RTC_HIRES
|
#ifndef CONFIG_RTC_HIRES
|
||||||
time_t up_rtc_time(void)
|
time_t up_rtc_time(void)
|
||||||
{
|
{
|
||||||
time_t t;
|
return (time_t)efm32_get_burtc_tick()/CONFIG_RTC_FREQUENCY;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -431,36 +439,16 @@ time_t up_rtc_time(void)
|
|||||||
#ifdef CONFIG_RTC_HIRES
|
#ifdef CONFIG_RTC_HIRES
|
||||||
int up_rtc_gettime(FAR struct timespec *tp)
|
int up_rtc_gettime(FAR struct timespec *tp)
|
||||||
{
|
{
|
||||||
time_t t;
|
uint64_t val;
|
||||||
uint32_t hires_val;
|
|
||||||
irqstate_t flags;
|
|
||||||
|
|
||||||
flags = irqsave();
|
val = efm32_get_burtc_tick();
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* Then we can save the time in seconds and fractional seconds. */
|
/* Then we can save the time in seconds and fractional seconds. */
|
||||||
|
|
||||||
tp->tv_sec = t;
|
tp->tv_sec = val / CONFIG_RTC_FREQUENCY;
|
||||||
tp->tv_nsec = hires_val * (1000000000/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;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -483,14 +471,38 @@ int up_rtc_gettime(FAR struct timespec *tp)
|
|||||||
|
|
||||||
int up_rtc_settime(FAR const 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;
|
irqstate_t flags;
|
||||||
|
|
||||||
flags = irqsave();
|
flags = irqsave();
|
||||||
|
|
||||||
putreg32(g_basetime.tv_sec, __BASETIME_SEC__OFF_REG);
|
cnt_reg = getreg32(EFM32_BURTC_CNT);
|
||||||
#ifdef CONFIG_RTC_HIRES
|
|
||||||
putreg32(g_basetime.tv_nsec,__BASETIME_NSEC_OFF_REG);
|
/* Compute Burtc offset because we cannot reset counter */
|
||||||
#endif
|
|
||||||
|
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);
|
irqrestore(flags);
|
||||||
return OK;
|
return OK;
|
||||||
|
Loading…
Reference in New Issue
Block a user