diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig index 7c578538022..906f740df34 100644 --- a/arch/arm/src/imxrt/Kconfig +++ b/arch/arm/src/imxrt/Kconfig @@ -136,6 +136,15 @@ config IMXRT_SEMC bool "Smart External Memory Controller (SEMC)" default n +config IMXRT_SNVS_LPSRTC + bool "LP SRTC" + default n + select IMXRT_SNVS_HPRTC + +config IMXRT_SNVS_HPRTC + bool "HP RTC" + default n + endmenu # i.MX RT Peripheral Selection menuconfig IMXRT_GPIO_IRQ @@ -452,4 +461,23 @@ config IMXRT_EDMA_EDBG system exits debug mode or the EDBG bit is cleared endmenu # eDMA Global Configuration + +menu "RTC Configuration" + depends on IMXRT_SNVS_HPRTC + +config IMXRT_RTC_MAGIC_REG + int "RTC SNVS GPR" + default 0 + range 0 3 + ---help--- + The BKP register used to store/check the Magic value to determine if + RTC is already setup + +config IMXRT_RTC_MAGIC + hex "RTC Magic 1" + default 0xfacefeed + ---help--- + Value used as Magic to determine if the RTC is already setup + +endmenu endif # ARCH_CHIP_IMXRT diff --git a/arch/arm/src/imxrt/Make.defs b/arch/arm/src/imxrt/Make.defs index 645d4841647..be14839638e 100644 --- a/arch/arm/src/imxrt/Make.defs +++ b/arch/arm/src/imxrt/Make.defs @@ -120,6 +120,17 @@ ifeq ($(CONFIG_IMXRT_EDMA),y) CHIP_CSRCS += imxrt_edma.c endif +ifeq ($(CONFIG_IMXRT_SNVS_LPSRTC),y) +CHIP_CSRCS += imxrt_lpsrtc.c +CHIP_CSRCS += imxrt_hprtc.c +else ifeq ($(CONFIG_IMXRT_SNVS_HPRTC),y) +CHIP_CSRCS += imxrt_hprtc.c +endif + +ifeq ($(CONFIG_RTC_DRIVER),y) +CHIP_CSRCS += imxrt_rtc_lowerhalf.c +endif + ifeq ($(CONFIG_IMXRT_ENET),y) CHIP_CSRCS += imxrt_enet.c endif diff --git a/arch/arm/src/imxrt/chip/imxrt_snvs.h b/arch/arm/src/imxrt/chip/imxrt_snvs.h index c924e52beec..b0918afbcc5 100644 --- a/arch/arm/src/imxrt/chip/imxrt_snvs.h +++ b/arch/arm/src/imxrt/chip/imxrt_snvs.h @@ -47,6 +47,8 @@ * Pre-processor Definitions ********************************************************************************************/ +#define IMXRT_SNVS_LP_MAXTAMPER 10 + /* Register offsets *************************************************************************/ #define IMXRT_SNVS_HPLR_OFFSET 0x0000 /* SNVS_HP Lock Register */ @@ -127,7 +129,9 @@ /* Bits 0-3: Reserved */ #define SNVS_HPCOMR_LPSWR (1 << 4) /* Bit 4: LP Software Reset */ #define SNVS_HPCOMR_LPSWRDIS (1 << 5) /* Bit 5: LP Software Reset Disable */ - /* Bits 6-30: Reserved */ + /* Bits 6-7: Reserved */ +#define SNVS_HPCOMR_SWSV (1 << 8) /* Bit 8: */ + /* Bits 9-30: Reserved */ #define SNVS_HPCOMR_NPSWAEN (1 << 31) /* Bit 31: Non-Privileged Software Access Enable */ /* SNVS_HP Control Register */ @@ -143,6 +147,7 @@ /* Bit 9: Reserved */ #define SNVS_HPCR_HPCALBVAL_SHIFT (10) /* Bits 10-14: HP Calibration Value */ #define SNVS_HPCR_HPCALBVAL_MASK (31 << SNVS_HPCR_HPCALBVAL_SHIFT) +# define SNVS_HPCR_HPCALBVAL(n) ((uint32_t)(n) << SNVS_HPCR_HPCALBVAL_SHIFT) # define SNVS_HPCR_HPCALBVAL_ZERO (0 << SNVS_HPCR_HPCALBVAL_SHIFT) /* +0 counts per 32768 ticks */ # define SNVS_HPCR_HPCALBVAL_P1 (1 << SNVS_HPCR_HPCALBVAL_SHIFT) /* +1 counts per 32768 ticks */ # define SNVS_HPCR_HPCALBVAL_P2 (2 << SNVS_HPCR_HPCALBVAL_SHIFT) /* +2 counts per 32768 ticks */ @@ -151,7 +156,9 @@ # define SNVS_HPCR_HPCALBVAL_M15 (17 << SNVS_HPCR_HPCALBVAL_SHIFT) /* -15 counts per 32768 ticks */ # define SNVS_HPCR_HPCALBVAL_M2 (30 << SNVS_HPCR_HPCALBVAL_SHIFT) /* -2 counts per 32768 ticks */ # define SNVS_HPCR_HPCALBVAL_M1 (31 << SNVS_HPCR_HPCALBVAL_SHIFT) /* -1 counts per 32768 ticks */ - /* Bits 15-23: Reserved */ + /* Bits 15: Reserved */ +#define SNVS_HPCR_HPTS (1 << 16) /* Bit 16: LPSRTC time sychronization */ + /* Bits 17-23: Reserved */ #define SNVS_HPCR_BTNCONFIG_SHIFT (24) /* Bits 24-26: Button Configuration */ #define SNVS_HPCR_BTNCONFIG_MASK (7 << SNVS_HPCR_BTNCONFIG_SHIFT) # define SNVS_HPCR_BTNCONFIG_ LOW (0 << SNVS_HPCR_BTNCONFIG_SHIFT) /* Button signal active low */ @@ -183,8 +190,6 @@ #define SNVS_HPTAMR_MASK 0x00007fff /* Bits 0-14: HP Time Alarm, most-significant 15 bits */ -#define SNVS_HPTALR_ - /* SNVS_LP Lock Register */ /* Bits 0-3: Reserved */ @@ -203,6 +208,20 @@ #define SNVS_LPCR_TOP (1 << 6) /* Bit 6: Turn off System Power */ #define SNVS_LPCR_PWRGLITCHEN (1 << 7) /* Bit 7: Power Glitch Enable */ /* Bits 8-15: Reserved */ +#define SNVS_LPCR_LPCALBEN (1 << 8) /* Bit 8: LP Real Time Counter Calibration Enabled */ + /* Bit 9: Reserved */ +#define SNVS_LPCR_LPCALBVAL_SHIFT (10) /* Bits 10-14: LP Calibration Value */ +#define SNVS_LPCR_LPCALBVAL_MASK (31 << SNVS_LPCR_LPCALBVAL_SHIFT) +# define SNVS_LPCR_LPCALBVAL(n) ((uint32_t)(n) << SNVS_LPCR_LPCALBVAL_SHIFT) +# define SNVS_LPCR_LPCALBVAL_ZERO (0 << SNVS_LPCR_LPCALBVAL_SHIFT) /* +0 counts per 32768 ticks */ +# define SNVS_LPCR_LPCALBVAL_P1 (1 << SNVS_LPCR_LPCALBVAL_SHIFT) /* +1 counts per 32768 ticks */ +# define SNVS_LPCR_LPCALBVAL_P2 (2 << SNVS_LPCR_LPCALBVAL_SHIFT) /* +2 counts per 32768 ticks */ +# define SNVS_LPCR_LPCALBVAL_P15 (15 << SNVS_LPCR_LPCALBVAL_SHIFT) /* +15 counts per 32768 ticks */ +# define SNVS_LPCR_LPCALBVAL_M16 (16 << SNVS_LPCR_LPCALBVAL_SHIFT) /* -16 counts per 32768 ticks */ +# define SNVS_LPCR_LPCALBVAL_M15 (17 << SNVS_LPCR_LPCALBVAL_SHIFT) /* -15 counts per 32768 ticks */ +# define SNVS_LPCR_LPCALBVAL_M2 (30 << SNVS_LPCR_LPCALBVAL_SHIFT) /* -2 counts per 32768 ticks */ +# define SNVS_LPCR_LPCALBVAL_M1 (31 << SNVS_LPCR_LPCALBVAL_SHIFT) /* -1 counts per 32768 ticks */ + /* Bit 15: Reserved */ #define SNVS_LPCR_BTNPRESSTIME_SHIFT (16) /* Bits 16-17: PMIC button press time out values */ #define SNVS_LPCR_BTNPRESSTIME_MASK (3 << SNVS_LPCR_BTNPRESSTIME_SHIFT) # define SNVS_LPCR_BTNPRESSTIME_5SEC (0 << SNVS_LPCR_BTNPRESSTIME_SHIFT) /* 5 secs */ @@ -229,7 +248,7 @@ /* Bits 0-1: Reserved */ #define SNVS_LPSR_MCR (1 << 2) /* Bit 2: Monotonic Counter Rollover */ - /* Bits 3-16: Reserved */ */ + /* Bits 3-16: Reserved */ #define SNVS_LPSR_EO (1 << 17) /* Bit 17: Emergency Off */ #define SNVS_LPSR_SPO (1 << 18) /* Bit 18: Set Power Off */ /* Bits 19-31: Reserved */ diff --git a/arch/arm/src/imxrt/imxrt_hprtc.c b/arch/arm/src/imxrt/imxrt_hprtc.c new file mode 100644 index 00000000000..5d817c4fae6 --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_hprtc.c @@ -0,0 +1,613 @@ +/************************************************************************************ + * arch/arm/src/imxrt/imxrt_lpsrtc.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 +#include + +#include + +#include "up_arch.h" + +#include "chip/imxrt_snvs.h" +#include "imxrt_periphclks.h" +#include "imxrt_lpsrtc.h" +#include "imxrt_hprtc.h" + +#ifdef CONFIG_IMXRT_SNVS_HPRTC + +/************************************************************************************ + * Private Data + ************************************************************************************/ + +/* Callback to use when the alarm expires */ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +static hprtc_alarm_callback_t g_hprtc_alarmcb; +#endif + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +#if !defined(CONFIG_IMXRT_SNVS_LPSRTC) && defined(CONFIG_RTC_DRIVER) +bool g_hprtc_timset; /* True: time has been set since power up */ +#endif + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: imxrt_snvs_interrupt + * + * Description: + * RTC 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. + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +static int imxrt_snvs_interrupt(int irq, void *context, FAR void *arg) +{ + hprtc_alarm_callback_t cb; + + /* The alarm is the only interrupt enabled */ + + DEBUGASSERT((getreg32(IMXRT_SNVS_HPSR) & SNVS_HPSR_HPTA) != 0); + + /* Sample and clear the callback */ + + cb = g_hprtc_alarmcb; + g_hprtc_alarmcb = NULL; + + /* Disable the alarm, alarm interrupts, clear pending alarm interrupt status */ + + imxrt_hprtc_alarmdisable(); + + /* Perform the callback */ + + cb(); + return 0; +} +#endif + +/************************************************************************************ + * Name: imxrt_hprtc_enable + * + * Description: + * Enable/start the HPRTC time counter. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ************************************************************************************/ + +static void imxrt_hprtc_enable(void) +{ + uint32_t regval; + + /* Enable the HPRTC */ + + regval = getreg32(IMXRT_SNVS_HPCR); + regval |= SNVS_HPCR_RTCEN; + putreg32(regval, IMXRT_SNVS_HPCR); + + while ((getreg32(IMXRT_SNVS_HPCR) & SNVS_HPCR_RTCEN) == 0) + { + } +} + +/************************************************************************************ + * Name: imxrt_hprtc_alarmenable + * + * Description: + * Enable alarm interrupts. This is currently only used internally at the time + * that alarm interrupts are enabled. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +static void imxrt_hprtc_alarmenable(void) +{ + uint32_t regval; + + /* Enable the alarm */ + + regval = getreg32(IMXRT_SNVS_HPCR); + regval |= SNVS_HPCR_HPTAEN; + putreg32(regval, IMXRT_SNVS_HPCR); + + /* Enable alarm interrupts at the NVIC */ + + up_enable_irq(IMXRT_IRQ_SNVS); +} +#endif + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Functions used only for HPRTC + ************************************************************************************/ + +#ifndef CONFIG_IMXRT_SNVS_LPSRTC + +/************************************************************************************ + * 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 + * + ************************************************************************************/ + +time_t up_rtc_time(void) +{ + /* Delegate to imxrt_hprtc_time() */ + + return imxrt_hprtc_time(); +} + +/************************************************************************************ + * 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) +{ + uint32_t regval; + + DEBUGASSERT(tp != NULL); + + /* Disable the HPRTC */ + + regval = getreg32(IMXRT_SNVS_HPCR); + regval = hcpr & ~SNVS_HPCR_RTCEN; + putreg32(regval, IMXRT_SNVS_HPCR); + + while ((getreg32(IMXRT_SNVS_HPCR) & SNVS_HPCR_RTCEN) != 0) + { + } + + /* Set HPRTC time in seconds. We could do better by accounting for the + * ts->tv_nsec unused residual. + * + * IMXRT_SNVS_HPTAMR Bits 9-14 = 15-bit MSB of alarm setting. + * IMXRT_SNVS_HPTALR 32-bit LSB of alarm setting. + */ + + putreg32((uint32_t)ts->tv_sec >> 17, IMXRT_SNVS_HPRTCMR); + putreg32((uint32_t)ts->tv_sec << 15, IMXRT_SNVS_HPRTCLR); + +#ifdef CONFIG_RTC_DRIVER + /* The time has been set */ + + g_hprtc_timset = true; +#endif + + /* Unconditionally re-enable the HPRTC */ + + imxrt_hprtc_enable(); + return OK; +} + +#endif /* !CONFIG_IMXRT_SNVS_LPSRTC */ + +/************************************************************************************ + * Logic Common to LPSRTC and HPRTC + ************************************************************************************/ + +/************************************************************************************ + * Name: up_rtc_initialize + * + * 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_rtc_initialize(void) +{ + int ret; + +#ifdef CONFIG_IMXRT_SNVS_LPSRTC + /* Perform LPSRTC initialization */ + + ret = imxrt_lpsrtc_initialize(); + if (ret < 0) + { + rtcerr("ERROR: imxrt_lpsrtc_initialize failed: %d\n", ret); + return ret; + } +#else + /* Initialize the HPRTC */ + + ret = imxrt_hprtc_initialize(); + if (ret < 0) + { + rtcerr("ERROR: imxrt_hprtc_initialize failed: %d\n", ret); + return ret; + } + + /* Start the HPRTC */ + + imxrt_hprtc_enable(); +#endif + +#if defined(CONFIG_IMXRT_SNVS_HPRTC) && defined(CONFIG_RTC_ALARM) && \ + defined(CONFIG_RTC_DRIVER) + /* Attach the alarm interrupt handler */ + + ret = irq_attach(IMXRT_IRQ_SNVS, imxrt_snvs_interrupt, NULL); + if (ret < 0) + { + rtcerr("ERROR: Failed to attach to IRQ%d\n", IMXRT_IRQ_SNVS); + return ret; + } +#endif + + return ret; +} + +/************************************************************************************ + * Name: imxrt_hprtc_initialize + * + * Description: + * Initialize the LPSRTC per the selected configuration. This function is called + * via up_rtc_initialize (see imxrt_hprtc.c). + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int imxrt_hprtc_initialize(void) +{ + uint32_t regval; + + /* Enable clocking to the the SNVS HP module. + * Clock is on in run mode, but off in WAIT and STOP modes. + */ + + imxrt_clockrun_snvs_hp(); + + /* Enable non-privileged access */ + + regval = getreg32(IMXRT_SNVS_HPCOMR); + regval |= (SNVS_HPCOMR_NPSWAEN | SNVS_HPCOMR_SWSV); + putreg32(regval, IMXRT_SNVS_HPCOMR); + + /* TODO: Set the periodic interrupt frequency */ + + putreg32(SNVS_HPCR_PIFREQ(0), IMXRT_SNVS_HPCR); + +#ifdef CONFIG_IMXRTC_HPRTC_CALENABLE + /* Set the HPRTC calibration value */ + + regval = getreg32(IMXRT_SNVS_HPCR); + regval &= ~SNVS_HPCR_HPCALBVAL_MASK; + regval |= SNVS_HPCR_HPCALBVAL(CONFIG_IMXRTC_HPRTC_CALVALUE); + regval |= SNVS_HPCR_HPCALBEN; + putreg32(regval, IMXRT_SNVS_HPCR); +#endif + + return OK; +} + +/************************************************************************************ + * Name: imxrt_hprtc_synchronize + * + * Description: + * Synchronize the HPRTC to the LPSRTC and enable the HPRTC timer. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ************************************************************************************/ + +#ifdef CONFIG_IMXRT_SNVS_LPSRTC +void imxrt_hprtc_synchronize(void) +{ + uint32_t regval; + uint32_t hpcr; + + /* Make sure that the RTC is disabled (it should be at this point in the LPSRTC + * initialization sequence). + */ + + hpcr = getreg32(IMXRT_SNVS_HPCR); + regval = hpcr; + regval &= ~SNVS_HPCR_RTCEN; + putreg32(regval, IMXRT_SNVS_HPCR); + + while ((getreg32(IMXRT_SNVS_HPCR) & SNVS_HPCR_RTCEN) != 0) + { + } + + /* Synchronize to the LPSRTC */ + + regval = getreg32(IMXRT_SNVS_HPCR); + regval |= SNVS_HPCR_HPTS; + putreg32(regval, IMXRT_SNVS_HPCR); + + /* Unconditionally enable the HPRTC */ + + imxrt_hprtc_enable(); +} +#endif + +/************************************************************************************ + * Name: imxrt_hprtc_time + * + * Description: + * Get the current time in seconds. This is the underlying implementation of the + * up_rtc_time() function that is used by the RTOS during initialization to set up + * the system time. + * + * Input Parameters: + * None + * + * Returned Value: + * The current time in seconds + * + ************************************************************************************/ + +uint32_t imxrt_hprtc_time(void) +{ + uint32_t seconds; + uint32_t verify = 0; + + /* Do consecutive reads until value is correct */ + + do + { + /* IMXRT_SNVS_HPRTCMR: Bits 9-14 = 15-bit MSB of counter. + * IMXRT_SNVS_HPRTCLR: 32-bit LSB of counter. + * + * REVISIT: This could be modified to support CONFIG_RTC_HI_RES + */ + + seconds = verify; + verify = (getreg32(IMXRT_SNVS_HPRTCMR) << 17) | + (getreg32(IMXRT_SNVS_HPRTCLR) >> 15); + } + while (verify != seconds); + + return seconds; +} + +/************************************************************************************ + * Name: imxrt_hprtc_getalarm + * + * Description: + * Get the current alarm setting in seconds. This is only used by the lower half + * RTC driver. + * + * Input Parameters: + * None + * + * Returned Value: + * The current alarm setting in seconds + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +uint32_t imxrt_hprtc_getalarm(void) +{ + /* Return the alarm setting in seconds + * + * IMXRT_SNVS_HPTAMR Bits 9-14 = 15-bit MSB of alarm setting. + * IMXRT_SNVS_HPTALR 32-bit LSB of alarm setting. + */ + + return (getreg32(IMXRT_SNVS_HPTAMR) << 17) | + (getreg32(IMXRT_SNVS_HPTALR) >> 15); +} +#endif + +/************************************************************************************ + * Name: imxrt_hprtc_setalarm + * + * Description: + * Set the alarm (in seconds) and enable alarm interrupts. This is only used by + * the lower half RTC driver. + * + * Input Parameters: + * None + * + * Returned Value: + * The current alarm setting in seconds + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +int imxrt_hprtc_setalarm(FAR struct timespec *ts, hprtc_alarm_callback_t cb) +{ + irqstate_t flags; + uint32_t regval; + uint32_t now; + + DEBUGASSERT(ts != NULL && cb != NULL); + + /* Disable interrupts so that the following sequence of events will not be + * interrupted or preempted. + */ + + flags = spin_lock_irqsave(); + + now = imxrt_hprtc_time(); + + /* Return error if the alarm time has passed. + * NOTES: (1) This will fail, of course, when the number of seconds since + * epoch wraps. (2) We could do better by accounting for the ts->tv_nsec + * unused residual. + */ + + if ((uint32_t)ts->tv_sec <= now) + { + rtcwarn("WARNING: time is in the past\n"); + return -EINVAL; + } + + /* Disable the RTC alarm interrupt */ + + regval = getreg32(IMXRT_SNVS_HPCR); + regval &= ~SNVS_HPCR_HPTAEN; + putreg32(regval, IMXRT_SNVS_HPCR); + + while ((getreg32(IMXRT_SNVS_HPCR) & SNVS_HPCR_HPTAEN) != 0) + { + } + + /* Save the alarm callback */ + + g_hprtc_alarmcb = cb; + + /* Set alarm in seconds + * + * IMXRT_SNVS_HPTAMR Bits 9-14 = 15-bit MSB of alarm setting. + * IMXRT_SNVS_HPTALR 32-bit LSB of alarm setting. + */ + + putreg32((uint32_t)ts->tv_sec >> 17, IMXRT_SNVS_HPTAMR); + putreg32((uint32_t)ts->tv_sec << 15, IMXRT_SNVS_HPTALR); + + /* Unconditionally enable the RTC alarm interrupt */ + + imxrt_hprtc_alarmenable(); + spin_unlock_irqrestore(flags); + return OK; +} +#endif + +/************************************************************************************ + * Name: imxrt_hprtc_alarmdisable + * + * Description: + * Disable alarm interrupts. Used internally after the receipt of the alarm + * interrupt. Also called by the lower-half RTC driver in order to cancel an + * alarm. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +void imxrt_hprtc_alarmdisable(void) +{ + uint32_t regval; + + /* Disable alarm interrupts at the NVIC */ + + up_disable_irq(IMXRT_IRQ_SNVS); + + /* Disable the alarm function */ + + regval = getreg32(IMXRT_SNVS_HPCR); + regval &= ~SNVS_HPCR_HPTAEN; + putreg32(regval, IMXRT_SNVS_HPCR); + + /* Clear any pending alarm interrupts */ + + putreg32(SNVS_HPSR_HPTA, IMXRT_SNVS_HPSR); +} +#endif + +#endif /* CONFIG_IMXRT_SNVS_HPRTC */ diff --git a/arch/arm/src/imxrt/imxrt_hprtc.h b/arch/arm/src/imxrt/imxrt_hprtc.h new file mode 100644 index 00000000000..2f9b338ac26 --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_hprtc.h @@ -0,0 +1,255 @@ +/**************************************************************************** + * arch/arm/src/imxrt/imxrt_hprtc.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMXRT_IMXRT_HPRTC_H +#define __ARCH_ARM_SRC_IMXRT_IMXRT_HPRTC_H + +#include + +#include "chip.h" + +#ifdef CONFIG_IMXRT_SNVS_HPRTC + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +#ifdef CONFIG_RTC_DATETIME +# error CONFIG_RTC_DATETIME should not be selected with this driver +#endif + +#ifdef CONFIG_RTC_PERIODIC +# error CONFIG_RTC_PERIODIC should not be selected with this driver +#endif + +/* REVISIT: This is probably supportable. The 47 bit timer does have + * accuracy greater than 1 second. + */ + +#ifdef CONFIG_RTC_HIRES +# error CONFIG_RTC_PERIODIC should not be selected with this driver +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Callback type used by the HPRTC log to notify the RTC driver when the + * alarm expires. + */ + +typedef CODE void (*hprtc_alarm_callback_t)(void); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#if !defined(CONFIG_IMXRT_SNVS_LPSRTC) && defined(CONFIG_RTC_DRIVER) +bool g_hprtc_timset; /* True: time has been set since power up */ +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/************************************************************************************ + * Functions used only for HPRTC + ************************************************************************************/ + +/************************************************************************************ + * Logic Common to LPSRTC and HPRTC + ************************************************************************************/ + +/**************************************************************************** + * Name: imxrt_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the i.MXRT. General usage: + * + * #include + * #include "imxrt_hprtc.h" + * + * struct rtc_lowerhalf_s *lower; + * lower = imxrt_hprtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. NULL is + * returned on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_DRIVER +struct rtc_lowerhalf_s; +FAR struct rtc_lowerhalf_s *imxrt_rtc_lowerhalf(void); +#endif + +/************************************************************************************ + * Name: imxrt_hprtc_initialize + * + * Description: + * Initialize the LPSRTC per the selected configuration. This function is called + * via up_rtc_initialize (see imxrt_hprtc.c). + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int imxrt_hprtc_initialize(void); + +/************************************************************************************ + * Name: imxrt_hprtc_synchronize + * + * Description: + * Synchronize the HPRTC to the LPSRTC and enable the HPRTC timer. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ************************************************************************************/ + +#ifdef CONFIG_IMXRT_SNVS_LPSRTC +void imxrt_hprtc_synchronize(void); +#endif + +/************************************************************************************ + * Name: imxrt_hprtc_time + * + * Description: + * Get the current time in seconds. This is the underlying implementation of the + * up_rtc_tim() function that is used by the RTOS during initialization to set up + * the system time. + * + * Input Parameters: + * None + * + * Returned Value: + * The current time in seconds + * + ************************************************************************************/ + +uint32_t imxrt_hprtc_time(void); + +/************************************************************************************ + * Name: imxrt_hprtc_getalarm + * + * Description: + * Get the current alarm setting in seconds. This is only used by the lower half + * RTC driver. + * + * Input Parameters: + * None + * + * Returned Value: + * The current alarm setting in seconds + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +uint32_t imxrt_hprtc_getalarm(void); +#endif + +/************************************************************************************ + * Name: imxrt_hprtc_setalarm + * + * Description: + * Set the alarm (in seconds) and enable alarm interrupts. This is only used by + * the lower half RTC driver. + * + * Input Parameters: + * sec - The new alarm setting + * + * Returned Value: + * The current alarm setting in seconds + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +int imxrt_hprtc_setalarm(FAR struct timespec *ts, hprtc_alarm_callback_t cb); +#endif + +/************************************************************************************ + * Name: imxrt_hprtc_alarmdisable + * + * Description: + * Disable alarm interrupts. Used internally after the receipt of the alarm + * interrupt. Also called by the lower-half RTC driver in order to cancel an + * alarm. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ************************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) && defined(CONFIG_RTC_DRIVER) +void imxrt_hprtc_alarmdisable(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* CONFIG_IMXRT_SNVS_HPRTC */ +#endif /* __ARCH_ARM_SRC_IMXRT_IMXRT_HPRTC_H */ diff --git a/arch/arm/src/imxrt/imxrt_lpsrtc.c b/arch/arm/src/imxrt/imxrt_lpsrtc.c new file mode 100644 index 00000000000..5362ac6f76e --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_lpsrtc.c @@ -0,0 +1,258 @@ +/************************************************************************************ + * arch/arm/src/imxrt/imxrt_lpsrtc.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 +#include + +#include + +#include "up_arch.h" + +#include "chip/imxrt_snvs.h" +#include "imxrt_periphclks.h" +#include "imxrt_hprtc.h" +#include "imxrt_lpsrtc.h" + +#ifdef CONFIG_IMXRT_SNVS_LPSRTC + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: imxrt_lpsrtc_enable + * + * Description: + * Enable/start the LPRTC time counter. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ************************************************************************************/ + +static void imxrt_lpsrtc_enable(void) +{ + uint32_t regval; + + /* Enable the LPSRTC */ + + regval = getreg32(IMXRT_SNVS_LPCR); + regval |= SNVS_LPCR_MCENV; + putreg32(regval, IMXRT_SNVS_LPCR); + + while ((getreg32(IMXRT_SNVS_LPCR) & SNVS_LPCR_MCENV) == 0) + { + } +} + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: imxrt_lpsrtc_initialize + * + * Description: + * Initialize the LPSRTC per the selected configuration. This function is called + * via up_rtc_initialize (see imxrt_hprtc.c). + * + * NOTE that the LPSRTC is always configured synchronized with the HPRTC. This + * means that the time is set via the LPSRTC but read via the HPRTC. Also, only + * the alarms from the HPRTC are used. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int imxrt_lpsrtc_initialize(void) +{ +#ifdef CONFIG_IMXRTC_LPSRTC_CALENABLE + uint32_t regval; +#endif + + /* Initialize the HPRTC */ + + imxrt_hprtc_initialize(); + + /* Enable clocking to the the SNVS LP module. + * Clock is on during all modes, except STOP mode. + */ + + imxrt_clockall_snvs_lp(); + +#ifdef CONFIG_IMXRTC_LPSRTC_CALENABLE + /* Set the LPSRTC calibration value */ + + regval = getreg32(IMXRT_SNVS_LPCR); + regval &= ~SNVS_LPCR_LPCALBVAL_MASK; + regval |= SNVS_LPCR_LPCALBVAL(CONFIG_IMXRTC_LPSRTC_CALVALUE); + regval |= SNVS_LPCR_LPCALBEN; + putreg32(regval, IMXRT_SNVS_LPCR); +#endif + + /* Disable tamper pins. + * TODO: I don't think this applies the currently supported device. + */ + + /* Enable the LPSRTC */ + + imxrt_lpsrtc_enable(); + + /* Synchronize HPRTC time with the LPSRTC and enable HPRTC */ + + imxrt_hprtc_synchronize(); + 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) +{ + /* Delegate to imxrt_hprtc_time() */ + + return imxrt_hprtc_time(); +} +#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 *ts) +{ + uint32_t regval; + + DEBUGASSERT(ts != NULL); + + /* Disable the LPSRTC */ + + regval = getreg32(IMXRT_SNVS_LPCR); + regval &= ~SNVS_LPCR_MCENV; + putreg32(regval, IMXRT_SNVS_LPCR); + + while ((getreg32(IMXRT_SNVS_LPCR) & SNVS_LPCR_MCENV) != 0) + { + } + + /* Set LPSRTC time in seconds. We could do better by accounting for the + * ts->tv_nsec unused residual. + * + * IMXRT_SNVS_LPSMCMR Bits 9-14 = 15-bit MSB of alarm setting. + * IMXRT_SNVS_LPSMCLR 32-bit LSB of alarm setting. + */ + + putreg32((uint32_t)ts->tv_sec >> 17, IMXRT_SNVS_LPSMCMR); + putreg32((uint32_t)ts->tv_sec << 15, IMXRT_SNVS_LPSMCLR); + + /* The time has been set */ + + putreg32(CONFIG_IMXRT_RTC_MAGIC, + IMXRT_SNVS_LPGPR(CONFIG_IMXRT_RTC_MAGIC_REG)); + + /* Unconditionally re-enable the LPSRTC */ + + imxrt_lpsrtc_enable(); + return OK; +} + +/**************************************************************************** + * Name: imxrt_lpsrtc_havesettime + * + * Description: + * Check if the LPSRTC time has been set + * + * Input Parameters: + * None + * + * Returned Value: + * Returns true if RTC date-time have been previously set. + * + ****************************************************************************/ + +bool imxrt_lpsrtc_havesettime(void) +{ + return (getreg32(IMXRT_SNVS_LPGPR(CONFIG_IMXRT_RTC_MAGIC_REG)) == + CONFIG_IMXRT_RTC_MAGIC); +} +#endif /* CONFIG_IMXRT_SNVS_LPSRTC */ diff --git a/arch/arm/src/imxrt/imxrt_lpsrtc.h b/arch/arm/src/imxrt/imxrt_lpsrtc.h new file mode 100644 index 00000000000..219b24133ad --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_lpsrtc.h @@ -0,0 +1,127 @@ +/**************************************************************************** + * arch/arm/src/imxrt/imxrt_lpsrtc.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMXRT_IMXRT_LPSRTC_H +#define __ARCH_ARM_SRC_IMXRT_IMXRT_LPSRTC_H + +#include + +#include "chip.h" + +#ifdef CONFIG_IMXRT_SNVS_LPSRTC + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +# ifdef CONFIG_RTC_DATETIME +# error CONFIG_RTC_DATETIME should not be selected with this driver +# endif + +# ifdef CONFIG_RTC_PERIODIC +# error CONFIG_RTC_PERIODIC should not be selected with this driver +# endif + +/* REVISIT: This is probably supportable. The 47 bit timer does have + * accuracy greater than 1 second. + */ + +# ifdef CONFIG_RTC_HIRES +# error CONFIG_RTC_PERIODIC should not be selected with this driver +# endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/************************************************************************************ + * Name: imxrt_lpsrtc_initialize + * + * Description: + * Initialize the LPSRTC per the selected configuration. This function is called + * via up_rtc_initialize (see imxrt_hprtc.c). + * + * NOTE that the LPSRTC is always configured synchronized with the HPRTC. This + * means that the time is set via the LPSRTC but read via the HPRTC. Also, only + * the alarms from the HPRTC are used. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int imxrt_lpsrtc_initialize(void); + +/**************************************************************************** + * Name: imxrt_lpsrtc_havesettime + * + * Description: + * Check if the LPSRTC time has been set + * + * Input Parameters: + * None + * + * Returned Value: + * Returns true if RTC date-time have been previously set. + * + ****************************************************************************/ + +bool imxrt_lpsrtc_havesettime(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_IMXRT_SNVS_LPSRTC */ +#endif /* __ARCH_ARM_SRC_IMXRT_IMXRT_LPSRTC_H */ diff --git a/arch/arm/src/imxrt/imxrt_rtc_lowerhalf.c b/arch/arm/src/imxrt/imxrt_rtc_lowerhalf.c new file mode 100644 index 00000000000..52189515652 --- /dev/null +++ b/arch/arm/src/imxrt/imxrt_rtc_lowerhalf.c @@ -0,0 +1,534 @@ +/**************************************************************************** + * arch/arm/src/imxrt/imxrt_rtc_lowerhalf.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 "imxrt_lpsrtc.h" +#include "imxrt_hprtc.h" + +#ifdef CONFIG_RTC_DRIVER + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This is the private type for the RTC state. It must be cast compatible + * with struct rtc_lowerhalf_s. + */ + +struct imxrt_lowerhalf_s +{ + /* This is the contained reference to the read-only, lower-half + * operations vtable (which may lie in FLASH or ROM) + */ + + FAR const struct rtc_ops_s *ops; + + /* Data following is private to this driver and not visible outside of + * this file. + */ + + sem_t devsem; /* Threads can only exclusively access the RTC */ + +#ifdef CONFIG_RTC_ALARM + /* Alarm callback information */ + + volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */ + volatile FAR void *priv; /* Private argument to accompany callback */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Prototypes for static methods in struct rtc_ops_s */ + +static int imxrt_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime); +static int imxrt_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime); +static bool imxrt_havesettime(FAR struct rtc_lowerhalf_s *lower); + +#ifdef CONFIG_RTC_ALARM +static int imxrt_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo); +static int imxrt_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo); +static int imxrt_cancelalarm(FAR struct rtc_lowerhalf_s *lower, + int alarmid); +static int imxrt_rdalarm(FAR struct rtc_lowerhalf_s *lower, + FAR struct lower_rdalarm_s *alarminfo); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ +/* i.MXRT RTC driver operations */ + +static const struct rtc_ops_s g_rtc_ops = +{ + .rdtime = imxrt_rdtime, + .settime = imxrt_settime, + .havesettime = imxrt_havesettime, +#ifdef CONFIG_RTC_ALARM + .setalarm = imxrt_setalarm, + .setrelative = imxrt_setrelative, + .cancelalarm = imxrt_cancelalarm, + .rdalarm = imxrt_rdalarm, +#endif +#ifdef CONFIG_RTC_PERIODIC + .setperiodic = NULL, /* Not implemented */ + .cancelperiodic = NULL, +#endif +#ifdef CONFIG_RTC_IOCTL + .ioctl = NULL, +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + .destroy = NULL, +#endif +}; + +/* i.MXRT RTC device state */ + +static struct imxrt_lowerhalf_s g_rtc_lowerhalf = +{ + .ops = &g_rtc_ops, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_alarm_callback + * + * Description: + * This is the function that is called from the RTC driver when the alarm + * goes off. It just invokes the upper half drivers callback. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static void imxrt_alarm_callback(void) +{ + FAR struct imxrt_lowerhalf_s *rtc = &g_rtc_lowerhalf; + + /* Sample and clear the callback information to minimize the window in + * time in which race conditions can occur. + */ + + rtc_alarm_callback_t cb = (rtc_alarm_callback_t)rtc->cb; + FAR void *arg = (FAR void *)rtc->priv; + + rtc->cb = NULL; + rtc->priv = NULL; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(arg, 0); + } +} +#endif /* CONFIG_RTC_ALARM */ + +/**************************************************************************** + * Name: imxrt_rdtime + * + * Description: + * Implements the rdtime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The location in which to return the current RTC time. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int imxrt_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime) +{ + time_t timer; + + /* The resolution of time is only 1 second */ + + timer = up_rtc_time(); + + /* Convert the one second epoch time to a struct tm */ + + if (gmtime_r(&timer, (FAR struct tm *)rtctime) == 0) + { + int errcode = get_errno(); + DEBUGASSERT(errcode > 0); + + rtcerr("ERROR: gmtime_r failed: %d\n", errcode); + return -errcode; + } + + return OK; +} + +/**************************************************************************** + * Name: imxrt_settime + * + * Description: + * Implements the settime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The new time to set + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int imxrt_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime) +{ + struct timespec ts; + + /* Convert the struct rtc_time to a time_t. Here we assume that struct + * rtc_time is cast compatible with struct tm. + */ + + ts.tv_sec = mktime((FAR struct tm *)rtctime); + ts.tv_nsec = 0; + + /* Now set the time (to one second accuracy) */ + + return up_rtc_settime(&ts); +} + +/**************************************************************************** + * Name: imxrt_havesettime + * + * Description: + * Implements the havesettime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * + * Returned Value: + * Returns true if RTC date-time have been previously set. + * + ****************************************************************************/ + +static bool imxrt_havesettime(FAR struct rtc_lowerhalf_s *lower) +{ +#ifdef CONFIG_IMXRT_SNVS_LPSRTC + return imxrt_lpsrtc_havesettime(); +#else + return g_hprtc_timset; +#endif +} + +/**************************************************************************** + * Name: imxrt_setalarm + * + * Description: + * Set a new alarm. This function implements the setalarm() method of the + * RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int imxrt_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo) +{ + FAR struct imxrt_lowerhalf_s *rtc; + int ret; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0); + rtc = (FAR struct imxrt_lowerhalf_s *)lower; + + /* Get exclusive access to the alarm */ + + ret = nxsem_wait(&rtc->devsem); + if (ret < 0) + { + rtcerr("ERROR: nxsem_wait failed: %d\n", ret); + return ret; + } + + ret = -EINVAL; + if (alarminfo->id == 0) + { + struct timespec ts; + + /* Convert the RTC time to a timespec (1 second accuracy) */ + + ts.tv_sec = mktime((FAR struct tm *)&alarminfo->time); + ts.tv_nsec = 0; + + /* Remember the callback information */ + + rtc->cb = alarminfo->cb; + rtc->priv = alarminfo->priv; + + /* And set the alarm */ + + ret = imxrt_hprtc_setalarm(&ts, imxrt_alarm_callback); + if (ret < 0) + { + rtc->cb = NULL; + rtc->priv = NULL; + } + } + + nxsem_post(&rtc->devsem); + return ret; +} +#endif + +/**************************************************************************** + * Name: imxrt_setrelative + * + * Description: + * Set a new alarm relative to the current time. This function implements + * the setrelative() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int imxrt_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo) +{ + FAR struct imxrt_lowerhalf_s *rtc; + FAR struct timespec ts; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0); + rtc = (FAR struct imxrt_lowerhalf_s *)lower; + + /* Get exclusive access to the alarm */ + + ret = nxsem_wait(&rtc->devsem); + if (ret < 0) + { + rtcerr("ERROR: nxsem_wait failed: %d\n", ret); + return ret; + } + + ret = -EINVAL; + if (alarminfo->id == 0 && alarminfo->reltime > 0) + { + /* Get the current time in seconds */ + /* The resolution of time is only 1 second */ + + ts.tv_sec = up_rtc_time(); + ts.tv_nsec = 0; + + /* Add the seconds offset. Add one to the number of seconds because + * we are unsure of the phase of the timer. + */ + + ts.tv_sec += (alarminfo->reltime + 1); + + /* Remember the callback information */ + + rtc->cb = alarminfo->cb; + rtc->priv = alarminfo->priv; + + /* And set the alarm */ + + ret = imxrt_hprtc_setalarm(&ts, imxrt_alarm_callback); + if (ret < 0) + { + rtc->cb = NULL; + rtc->priv = NULL; + } + } + + nxsem_post(&rtc->devsem); + return ret; +} +#endif + +/**************************************************************************** + * Name: imxrt_cancelalarm + * + * Description: + * Cancel the current alarm. This function implements the cancelalarm() + * method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int imxrt_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid) +{ + /* We cancel the alarm by alarm by disabling the alarm and the alarm + * interrupt. + */ + + imxrt_hprtc_alarmdisable(); + return OK; +} +#endif + +/**************************************************************************** + * Name: imxrt_rdalarm + * + * Description: + * Query the RTC alarm. + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to query the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int imxrt_rdalarm(FAR struct rtc_lowerhalf_s *lower, + FAR struct lower_rdalarm_s *alarminfo) +{ + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->time != NULL); + DEBUGASSERT(alarminfo->id == 0); + + /* There is only one alarm */ + + if (alarminfo->id == 0) + { + time_t alarm; + + /* Get the current alarm setting in seconds */ + + alarm = (time_t)imxrt_hprtc_getalarm(); + + /* Convert the one second epoch time to a struct tm */ + + ret = OK; + if (gmtime_r(&alarm, (FAR struct tm *)alarminfo->time) == 0) + { + int errcode = get_errno(); + DEBUGASSERT(errcode > 0); + ret = -errcode; + } + } + + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imxrt_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the i.MXRT. General usage: + * + * #include + * + * struct rtc_lowerhalf_s *lower; + * lower = imxrt_rtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. NULL is + * returned on any failure. + * + ****************************************************************************/ + +FAR struct rtc_lowerhalf_s *imxrt_rtc_lowerhalf(void) +{ + nxsem_init(&g_rtc_lowerhalf.devsem, 0, 1); + + return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf; +} + +#endif /* CONFIG_RTC_DRIVER */ diff --git a/configs/imxrt1050-evk/README.txt b/configs/imxrt1050-evk/README.txt index bfa5dc0b924..02aedfd1966 100644 --- a/configs/imxrt1050-evk/README.txt +++ b/configs/imxrt1050-evk/README.txt @@ -289,10 +289,6 @@ Configuration sub-directories CONFIG_NSH_NETINIT_THREAD_PRIORITY=80 CONFIG_NSH_NETINIT_THREAD_STACKSIZE=1568 - STATUS: As of this writing, I get a hardfault when I enable the PHY - interrupt so I suspect that there is something incorrect in that - pin configuration. - nsh: Configures the NuttShell (nsh) located at examples/nsh. This NSH