diff --git a/arch/arm/src/efm32/Kconfig b/arch/arm/src/efm32/Kconfig index cd75755215d..c71238134a9 100644 --- a/arch/arm/src/efm32/Kconfig +++ b/arch/arm/src/efm32/Kconfig @@ -132,6 +132,11 @@ config EFM32_RMU bool "Reset Management Unit (RMU) " default n +config EFM32_RMU_DEBUG + bool "Reset Management Unit (RMU) DEBUG " + default n + depends on EFM32_RMU && DEBUG + config EFM32_USART0 bool "USART0" default n @@ -578,4 +583,10 @@ config EFM32_TIMER3_CHANNEL If TIMER3 is enabled for PWM usage, you also need specifies the timer output channel {0,1,2} +config EFM32_RTC_BURTC + bool "Use BURTC as RTC" + default n + ---help--- + Enable RTC with EFM32 BURTC + endif # ARCH_CHIP_EFM32 diff --git a/arch/arm/src/efm32/Make.defs b/arch/arm/src/efm32/Make.defs index 6a3ebac4ae3..a06f7d5cf02 100644 --- a/arch/arm/src/efm32/Make.defs +++ b/arch/arm/src/efm32/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # arch/arm/src/efm32/Make.defs # -# Copyright (C) 2014 Gregory Nutt. All rights reserved. +# Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -131,6 +131,10 @@ ifeq ($(CONFIG_EFM32_DMA),y) CHIP_CSRCS += efm32_dma.c endif +ifeq ($(CONFIG_EFM32_RTC_BURTC),y) +CHIP_CSRCS += efm32_rtc_burtc.c +endif + ifeq ($(CONFIG_EFM32_OTGFS),y) ifeq ($(CONFIG_USBDEV),y) CHIP_CSRCS += efm32_usbdev.c diff --git a/arch/arm/src/efm32/efm32_rmu.c b/arch/arm/src/efm32/efm32_rmu.c index 93a16ce63fb..a03353c0b60 100644 --- a/arch/arm/src/efm32/efm32_rmu.c +++ b/arch/arm/src/efm32/efm32_rmu.c @@ -53,7 +53,7 @@ #include "chip/efm32_emu.h" #include "chip/efm32_rmu.h" -#include "emf32_rmu.h" +#include "efm32_rmu.h" /************************************************************************************ * Pre-processor Definitions @@ -63,10 +63,105 @@ * Private Types ************************************************************************************/ +#ifdef CONFIG_EFM32_RMU_DEBUG +typedef struct +{ + const uint32_t val; + const uint32_t mask; + const char* str; +}efm32_reset_cause_list_t; +#endif + /************************************************************************************ * Private Data ************************************************************************************/ +#ifdef CONFIG_EFM32_RMU_DEBUG +static efm32_reset_cause_list_t efm32_reset_cause_list[] = +{ + { + 0x0001, // 0bXXXX XXXX XXXX XXX1 + 0x0001, // 0bXXXX XXXX XXXX XXX1 + "A Power-on Reset has been performed. X bits are don't care." + }, + { + 0x0002, // 0bXXXX XXXX 0XXX XX10 + 0x0003, // 0bXXXX XXXX 1XXX XX11 + "A Brown-out has been detected on the unregulated power." + }, + { + 0x0004, //0bXXXX XXXX XXX0 0100 + 0x001F, //0bXXXX XXXX XXX1 1111 + "A Brown-out has been detected on the regulated power." + }, + { + 0x0008, //0bXXXX XXXX XXXX 1X00 + 0x000B, //0bXXXX XXXX XXXX 1X11 + "An external reset has been applied." + }, + { + 0x0010, //0bXXXX XXXX XXX1 XX00 + 0x0013, //0bXXXX XXXX XXX1 XX11 + "A watchdog reset has occurred." + }, + { + 0x0020, //0bXXXX X000 0010 0000 + 0x07FF, //0bXXXX X111 1111 1111 + "A lockup reset has occurred." + }, + { + 0x0040, //0bXXXX X000 01X0 0000 + 0x07DF, //0bXXXX X111 11X1 1111 + "A system request reset has occurred." + }, + { + 0x0080, //0bXXXX X000 1XX0 0XX0 + 0x0799, //0bXXXX X111 1XX1 1XX1 + "The system has woken up from EM4." + }, + { + 0x0180, //0bXXXX X001 1XX0 0XX0 + 0x0799, //0bXXXX X111 1XX1 1XX1 + "The system has woken up from EM4 on an EM4 wakeup reset request from pin." + }, + { + 0x0200, //0bXXXX X01X XXX0 0000 + 0x061F, //0bXXXX X11X XXX1 1111 + "A Brown-out has been detected on Analog Power Domain 0 (AVDD0)." + }, + { + 0x0400, //0bXXXX X10X XXX0 0000 + 0x061F, //0bXXXX X11X XXX1 1111 + "A Brown-out has been detected on Analog Power Domain 1 (AVDD1)." + }, + { + 0x0800, //0bXXXX 1XXX XXXX 0XX0 + 0x0809, //0bXXXX 1XXX XXXX 1XX1 + "A Brown-out has been detected by the Backup BOD on VDD_DREG." + }, + { + 0x1000, //0bXXX1 XXXX XXXX 0XX0 + 0x1009, //0bXXX1 XXXX XXXX 1XX1 + "A Brown-out has been detected by the Backup BOD on BU_VIN." + }, + { + 0x2000, //0bXX1X XXXX XXXX 0XX0 + 0x2009, //0bXX1X XXXX XXXX 1XX1 + "A Brown-out has been detected by the Backup BOD on unregulated power" + }, + { + 0x4000, //0bX1XX XXXX XXXX 0XX0 + 0x4009, //0bX1XX XXXX XXXX 1XX1 + "A Brown-out has been detected by the Backup BOD on regulated power." + }, + { + 0x8000, //0b1XXX XXXX XXXX XXX0 + 0x8001, //0b1XXX XXXX XXXX XXX1 + "The system has been in Backup mode." + } +}; +#endif + /************************************************************************************ * Public Data ************************************************************************************/ @@ -83,6 +178,46 @@ uint32_t g_efm32_rstcause; * Public Functions ************************************************************************************/ +/************************************************************************************ + * Name: efm32_reset_cause_list_str + * + * Description: + * Return next reset cause string, NULL if no more reset cause. + * + * Input Parmeters: + * reg: reset cause register to decode (like g_efm32_rstcause) + * idx: Use to keep in maind reset cause decoding position. + * set *idx to zero before first call. + * + ************************************************************************************/ + +#ifdef CONFIG_EFM32_RMU_DEBUG +const char *efm32_reset_cause_list_str(uint32_t reg, unsigned int *idx) +{ + int len = sizeof(efm32_reset_cause_list)/sizeof(efm32_reset_cause_list[0]); + efm32_reset_cause_list_t *ptr = NULL; + + do + { + if (*idx >= len) + { + return NULL; + } + + ptr = &efm32_reset_cause_list[*idx]; + (*idx)++; + } + while ((ptr->mask & reg) != ptr->val); + + if (ptr != NULL) + { + return ptr->str; + } + + return NULL; +} +#endif + /************************************************************************************ * Name: efm32_rmu_initialize * @@ -93,16 +228,19 @@ uint32_t g_efm32_rstcause; void efm32_rmu_initialize(void) { +#ifdef CONFIG_EFM32_RMU_DEBUG + unsigned int idx = 0; +#endif uint32_t locked; - + g_efm32_rstcause = getreg32(EFM32_RMU_RSTCAUSE); /* Now clear reset cause */ putreg32(RMU_CMD_RCCLR,EFM32_RMU_CMD); - /* Clear some reset causes not cleared with RMU CMD register - * (If EMU registers locked, they must be unlocked first) + /* Clear some reset causes not cleared with RMU CMD register + * (If EMU registers locked, they must be unlocked first) */ locked = getreg32(EFM32_EMU_LOCK) & EMU_LOCK_LOCKKEY_LOCKED; @@ -122,4 +260,20 @@ void efm32_rmu_initialize(void) putreg32(EMU_LOCK_LOCKKEY_LOCK,EMU_LOCK_LOCKKEY_LOCK); } + +#ifdef CONFIG_EFM32_RMU_DEBUG + rmudbg("RMU => reg = 0x%08X\n", g_efm32_rstcause); + for (;;) + { + const char* str; + + str = efm32_reset_cause_list_str(g_efm32_rstcause, &idx); + if (str == NULL) + { + break; + } + + rmudbg("RMU => %s\n", str); + } +#endif } diff --git a/arch/arm/src/efm32/efm32_rmu.h b/arch/arm/src/efm32/efm32_rmu.h index 2887afe655f..f793b29fa9a 100644 --- a/arch/arm/src/efm32/efm32_rmu.h +++ b/arch/arm/src/efm32/efm32_rmu.h @@ -45,6 +45,28 @@ #ifdef CONFIG_EFM32_RMU +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_VERBOSE +# undef CONFIG_EFM32_RMU_DEBUG +#endif + +#ifdef CONFIG_EFM32_RMU_DEBUG +# define rmudbg lldbg +# ifdef CONFIG_DEBUG_VERBOSE +# define rmuvdbg lldbg +# else +# define rmuvdbg(x...) +# endif +#else +# define rmudbg(x...) +# define rmuvdbg(x...) +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -64,5 +86,22 @@ extern uint32_t g_efm32_rstcause; void efm32_rmu_initialize(void); +/************************************************************************************ + * Name: efm32_reset_cause_list_str + * + * Description: + * Return next reset cause string, NULL if no more reset cause. + * + * Input Parmeters: + * reg: reset cause register to decode (like g_efm32_rstcause) + * idx: Use to keep in maind reset cause decoding position. + * set *idx to zero before first call. + * + ************************************************************************************/ + +#ifdef CONFIG_EFM32_RMU_DEBUG +const char *efm32_reset_cause_list_str(uint32_t reg, unsigned int *idx); +#endif + #endif /* CONFIG_EFM32_RMU */ #endif /* __ARCH_ARM_SRC_EFM32_EFM32_RMU_H */ diff --git a/arch/arm/src/efm32/efm32_rtc_burtc.c b/arch/arm/src/efm32/efm32_rtc_burtc.c new file mode 100644 index 00000000000..5b177d46afd --- /dev/null +++ b/arch/arm/src/efm32/efm32_rtc_burtc.c @@ -0,0 +1,588 @@ +/************************************************************************************ + * arch/arm/src/efm32/efm32_burtc.c + * + * Copyright (C) 2015 Pierre-Noel Bouteville. All rights reserved. + * Author: Pierre-Noel Bouteville + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "up_arch.h" + +#include "chip.h" +#include "chip/efm32_burtc.h" + +#include "efm32_rmu.h" +#include "clock/clock.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ +/* Configuration ********************************************************************/ + +#ifdef CONFIG_RTC_HIRES +# ifndef CONFIG_RTC_FREQUENCY +# error "CONFIG_RTC_FREQUENCY is required for CONFIG_RTC_HIRES" +# endif +#else +# ifndef CONFIG_RTC_FREQUENCY +# define CONFIG_RTC_FREQUENCY 1 +# endif +# if CONFIG_RTC_FREQUENCY != 1 +# error "Only lo-res CONFIG_RTC_FREQUENCY of 1Hz is supported" +# endif +#endif + +#ifndef BOARD_BURTC_MODE +# define BOARD_BURTC_MODE BURTC_CTRL_MODE_EM4EN +#endif + +#ifndef BOARD_BURTC_PRESC +# define BOARD_BURTC_PRESC BURTC_CTRL_PRESC_DIV1 +#endif + +#ifndef BOARD_BURTC_CLKSRC +# define BOARD_BURTC_CLKSRC BURTC_CTRL_CLKSEL_LFRCO +#endif + +#if (BOARD_BURTC_PRESC == BURTC_CTRL_PRESC_DIV1) +# define BURTC_CLK_DIV 1 +#elif (BOARD_BURTC_PRESC == BURTC_CTRL_PRESC_DIV2) +# define BURTC_CLK_DIV 2 +#elif (BOARD_BURTC_PRESC == BURTC_CTRL_PRESC_DIV4) +# define BURTC_CLK_DIV 4 +#elif (BOARD_BURTC_PRESC == BURTC_CTRL_PRESC_DIV8) +# define BURTC_CLK_DIV 8 +#elif (BOARD_BURTC_PRESC == BURTC_CTRL_PRESC_DIV16) +# define BURTC_CLK_DIV 16 +#elif (BOARD_BURTC_PRESC == BURTC_CTRL_PRESC_DIV32) +# define BURTC_CLK_DIV 32 +#elif (BOARD_BURTC_PRESC == BURTC_CTRL_PRESC_DIV64) +# define BURTC_CLK_DIV 64 +#elif (BOARD_BURTC_PRESC == BURTC_CTRL_PRESC_DIV64) +# define BURTC_CLK_DIV 128 +#else +# error "BOARD_BURTC_PRESC is setted with unknown value" +#endif + +#if (BOARD_BURTC_CLKSRC == BURTC_CTRL_CLKSEL_LFRCO ) +# if (CONFIG_RTC_FREQUENCY*BURTC_CLK_DIV != BOARD_LFRCO_FREQUENCY) +# error "CONFIG_RTC_FREQUENCY is not well be setted" +# endif +#elif (BOARD_BURTC_CLKSRC == BURTC_CTRL_CLKSEL_LFXO ) +# if (CONFIG_RTC_FREQUENCY*BURTC_CLK_DIV != BOARD_LFXO_FREQUENCY) +# error "CONFIG_RTC_FREQUENCY is not well be setted" +# endif +#elif (BOARD_BURTC_CLKSRC == BURTC_CTRL_CLKSEL_ULFRCO ) +# if (CONFIG_RTC_FREQUENCY*BURTC_CLK_DIV != BOARD_ULFRCO_FREQUENCY) +# error "CONFIG_RTC_FREQUENCY is not well be setted" +# endif +#else +# 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) + +#ifdef CONFIG_RTC_HIRES +# define __CNT_OFF_REG EFM32_BURTC_RET_REG(0) +# define __BASETIME_NSEC_OFF_REG EFM32_BURTC_RET_REG(1) +#endif + +/************************************************************************************ + * Private Types + ************************************************************************************/ + +/************************************************************************************ + * Private Data + ************************************************************************************/ + +/* Callback to use when the alarm expires */ + +#ifdef CONFIG_RTC_ALARM +static alarmcb_t g_alarmcb; +#endif + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +/* Variable determines the state of the LSE oscillator. + * Possible errors: + * - on start-up + * - during operation, reported by LSE interrupt + */ + +uint32_t g_efm32_burtc_reset_status; + +bool g_efm32_burtc_reseted = false; + +volatile bool g_rtc_enabled = false; + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: efm32_rtc_interrupt + * + * Description: + * BURTC interrupt service routine + * + * Input Parameters: + * irq - The IRQ number that generated the interrupt + * context - Architecture specific register save information. + * + * Returned Value: + * Zero (OK) on success; A negated errno value on failure. + * + ************************************************************************************/ + +static int efm32_rtc_burtc_interrupt(int irq, void *context) +{ + uint32_t source = getreg32(EFM32_BURTC_IF); + + ASSERT( source & BURTC_IF_LFXOFAIL ); + +#ifdef CONFIG_RTC_HIRES + if ( source & BURTC_IF_OF ) + { + int regval; + + regval = getreg32(__SEC_OFF_REG); + regval += (_BURTC_CNT_MASK+1)/CONFIG_RTC_FREQUENCY; + putreg32(regval,__SEC_OFF_REG); + } +#endif + +#ifdef CONFIG_RTC_ALARM + if ( source & BURTC_IFC_COMP0 ) + { + if ( g_alarmcb != NULL ) + { + /* Alarm callback */ + + g_alarmcb(); + g_alarmcb = NULL; + } + } +#endif + + /* Clear pending flags, leave RSF high */ + + putreg32(BURTC_IFC_OF | BURTC_IFC_COMP0 | BURTC_IFC_LFXOFAIL, EFM32_BURTC_IFC); + + return 0; +} + +/************************************************************************************ + * Name: efm32_burtc_init + * + * Description: + * board initialization of burtc RTC. + * This function is called once in efm32_boardinitialize + * + * Note + * efm32_rmu_initialize should be called one since boot. + * + ************************************************************************************/ + +static void efm32_rtc_burtc_init(void) +{ + uint32_t regval; + + regval = g_efm32_rstcause; + + 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 ) + ) + { + g_efm32_burtc_reset_status = getreg32(EFM32_BURTC_STATUS); + + /* Reset timestamp BURTC clear status */ + + 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 + + return; + } + + /* Disable reset of BackupDomain */ + + modifyreg32(EFM32_RMU_CTRL,_RMU_CTRL_BURSTEN_MASK,0); + + /* Make sure all registers are updated simultaneously */ + + putreg32(BURTC_FREEZE_REGFREEZE_FREEZE,EFM32_BURTC_FREEZE); + + /* Restore all not setted BURTC registers to default value */ + +// putreg32(_BURTC_LPMODE_RESETVALUE, EFM32_BURTC_LPMODE ); +// putreg32(_BURTC_LFXOFDET_RESETVALUE, EFM32_BURTC_LFXOFDET); +// putreg32(_BURTC_COMP0_RESETVALUE, EFM32_BURTC_COMP0 ); + + /* New configuration */ + + regval = ((BOARD_BURTC_MODE ) | + (BURTC_CTRL_DEBUGRUN_DEFAULT ) | + (BURTC_CTRL_COMP0TOP_DEFAULT ) | + (BURTC_CTRL_LPCOMP_DEFAULT ) | + (BOARD_BURTC_PRESC ) | + (BOARD_BURTC_CLKSRC ) | + (BURTC_CTRL_BUMODETSEN_DEFAULT)); + + /* Clear interrupts */ + + putreg32(0xFFFFFFFF,EFM32_BURTC_IFC); + + /* Set new configuration */ + + putreg32(regval|BURTC_CTRL_RSTEN,EFM32_BURTC_CTRL); + + /* Clear freeze */ + + putreg32(0,EFM32_BURTC_FREEZE); + + /* To enable BURTC counter, we need to disable reset */ + + putreg32(regval,EFM32_BURTC_CTRL); + + /* Enable BURTC interrupt on compare match and counter overflow */ + + putreg32(BURTC_IF_OF|BURTC_IF_LFXOFAIL, EFM32_BURTC_IEN ); + + /* Lock BURTC to avoid modification */ + + 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 + + /* inform rest of software that BURTC was reset at boot */ + + g_efm32_burtc_reseted = true; +} + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: up_rtcinitialize + * + * Description: + * Initialize the hardware RTC per the selected configuration. This function is + * called once during the OS initialization sequence + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int up_rtcinitialize(void) +{ + efm32_rtc_burtc_init(); + + /* Configure RTC interrupt to catch overflow and alarm interrupts. */ + + irq_attach(EFM32_IRQ_BURTC, efm32_rtc_burtc_interrupt); + up_enable_irq(EFM32_IRQ_BURTC); + + g_rtc_enabled = true; + + return OK; +} + +/************************************************************************************ + * Name: up_rtc_time + * + * Description: + * Get the current time in seconds. This is similar to the standard time() + * function. This interface is only required if the low-resolution RTC/counter + * hardware implementation selected. It is only used by the RTOS during + * initialization to set up the system time when CONFIG_RTC is set but neither + * CONFIG_RTC_HIRES nor CONFIG_RTC_DATETIME are set. + * + * Input Parameters: + * None + * + * Returned Value: + * The current time in seconds + * + ************************************************************************************/ + +#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; +} +#endif + +/************************************************************************************ + * Name: up_rtc_gettime + * + * Description: + * Get the current time from the high resolution RTC clock/counter. This interface + * is only supported by the high-resolution RTC/counter hardware implementation. + * It is used to replace the system timer. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_HIRES +int up_rtc_gettime(FAR struct timespec *tp) +{ + time_t t; + uint32_t hires_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); + + 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. */ + + tp->tv_sec = t; + tp->tv_nsec = hires_val * (1000000000/CONFIG_RTC_FREQUENCY); + + return OK; +} +#endif + +/************************************************************************************ + * Name: up_rtc_settime + * + * Description: + * Set the RTC to the provided time. All RTC implementations must be able to + * set their time based on a standard timespec. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int up_rtc_settime(FAR const struct timespec *tp) +{ + 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 + + irqrestore(flags); + return OK; +} + +/************************************************************************************ + * Name: up_rtc_setalarm + * + * Description: + * Set up an alarm. + * + * Input Parameters: + * tp - the time to set the alarm + * callback - the function to call when the alarm expires. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +#error "Sorry ! not yet implemented, just copied from STM32" +int up_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) +{ + struct rtc_regvals_s regvals; + irqstate_t flags; + uint16_t cr; + int ret = -EBUSY; + + /* Is there already something waiting on the ALARM? */ + + if (g_alarmcb == NULL) + { + /* No.. Save the callback function pointer */ + + g_alarmcb = callback; + + /* Break out the time values */ + + up_rtc_breakout(tp, ®vals); + + /* Enable RTC alarm */ + + cr = getreg16(STM32_RTC_CRH); + cr |= RTC_CRH_ALRIE; + putreg16(cr, STM32_RTC_CRH); + + /* The set the alarm */ + + flags = irqsave(); + stm32_rtc_beginwr(); + putreg16(regvals.cnth, STM32_RTC_ALRH); + putreg16(regvals.cntl, STM32_RTC_ALRL); + stm32_rtc_endwr(); + irqrestore(flags); + + ret = OK; + } + + return ret; +} +#endif + +/************************************************************************************ + * Name: up_rtc_cancelalarm + * + * Description: + * Cancel a pending alarm alarm + * + * Input Parameters: + * none + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +#error "Sorry ! not yet implemented, just copied from STM32" +int up_rtc_cancelalarm(void) +{ + irqstate_t flags; + int ret = -ENODATA; + + if (g_alarmcb != NULL) + { + /* Cancel the global callback function */ + + g_alarmcb = NULL; + + /* Unset the alarm */ + + flags = irqsave(); + stm32_rtc_beginwr(); + putreg16(0xffff, STM32_RTC_ALRH); + putreg16(0xffff, STM32_RTC_ALRL); + stm32_rtc_endwr(); + irqrestore(flags); + + ret = OK; + } + + return ret; +} +#endif