Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:01

0001 /*
0002  * Copyright (c) 2016, Freescale Semiconductor, Inc.
0003  * Copyright 2017-2022 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_snvs_hp.h"
0010 
0011 /*******************************************************************************
0012  * Definitions
0013  ******************************************************************************/
0014 
0015 /* Component ID definition, used by tools. */
0016 #ifndef FSL_COMPONENT_ID
0017 #define FSL_COMPONENT_ID "platform.drivers.snvs_hp"
0018 #endif
0019 
0020 #define SECONDS_IN_A_DAY    (86400U)
0021 #define SECONDS_IN_A_HOUR   (3600U)
0022 #define SECONDS_IN_A_MINUTE (60U)
0023 #define DAYS_IN_A_YEAR      (365U)
0024 #define YEAR_RANGE_START    (1970U)
0025 #define YEAR_RANGE_END      (2099U)
0026 
0027 #if !(defined(SNVS_HPSR_PI_MASK))
0028 #define SNVS_HPSR_PI_MASK (0x2U)
0029 #endif
0030 #if !(defined(SNVS_HPSR_HPTA_MASK))
0031 #define SNVS_HPSR_HPTA_MASK (0x1U)
0032 #endif
0033 
0034 /*******************************************************************************
0035  * Prototypes
0036  ******************************************************************************/
0037 /*!
0038  * @brief Checks whether the date and time passed in is valid
0039  *
0040  * @param datetime Pointer to structure where the date and time details are stored
0041  *
0042  * @return Returns false if the date & time details are out of range; true if in range
0043  */
0044 static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime);
0045 
0046 /*!
0047  * @brief Converts time data from datetime to seconds
0048  *
0049  * @param datetime Pointer to datetime structure where the date and time details are stored
0050  *
0051  * @return The result of the conversion in seconds
0052  */
0053 static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime);
0054 
0055 /*!
0056  * @brief Converts time data from seconds to a datetime structure
0057  *
0058  * @param seconds  Seconds value that needs to be converted to datetime format
0059  * @param datetime Pointer to the datetime structure where the result of the conversion is stored
0060  */
0061 static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime);
0062 
0063 /*!
0064  * @brief Returns RTC time in seconds.
0065  *
0066  * This function is used internally to get actual RTC time in seconds.
0067  *
0068  * @param base SNVS peripheral base address
0069  *
0070  * @return RTC time in seconds
0071  */
0072 static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base);
0073 
0074 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
0075      defined(SNVS_HP_CLOCKS))
0076 /*!
0077  * @brief Get the SNVS instance from peripheral base address.
0078  *
0079  * @param base SNVS peripheral base address.
0080  *
0081  * @return SNVS instance.
0082  */
0083 static uint32_t SNVS_HP_GetInstance(SNVS_Type *base);
0084 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0085 
0086 /*******************************************************************************
0087  * Variables
0088  ******************************************************************************/
0089 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
0090      defined(SNVS_HP_CLOCKS))
0091 /*! @brief Pointer to snvs_hp clock. */
0092 static const clock_ip_name_t s_snvsHpClock[] = SNVS_HP_CLOCKS;
0093 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0094 
0095 /*******************************************************************************
0096  * Code
0097  ******************************************************************************/
0098 static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime)
0099 {
0100     assert(datetime != NULL);
0101 
0102     /* Table of days in a month for a non leap year. First entry in the table is not used,
0103      * valid months start from 1
0104      */
0105     uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
0106 
0107     /* Check year, month, hour, minute, seconds */
0108     if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
0109         (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
0110     {
0111         /* If not correct then error*/
0112         return false;
0113     }
0114 
0115     /* Adjust the days in February for a leap year */
0116     if ((((datetime->year & 3U) == 0U) && (datetime->year % 100U != 0U)) || (datetime->year % 400U == 0U))
0117     {
0118         daysPerMonth[2] = 29U;
0119     }
0120 
0121     /* Check the validity of the day */
0122     if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
0123     {
0124         return false;
0125     }
0126 
0127     return true;
0128 }
0129 
0130 static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime)
0131 {
0132     assert(datetime != NULL);
0133 
0134     /* Number of days from begin of the non Leap-year*/
0135     /* Number of days from begin of the non Leap-year*/
0136     uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
0137     uint32_t seconds;
0138 
0139     /* Compute number of days from 1970 till given year*/
0140     seconds = (((uint32_t)datetime->year - 1970U) * DAYS_IN_A_YEAR);
0141     /* Add leap year days */
0142     seconds += (((uint32_t)datetime->year / 4U) - (1970U / 4U));
0143     /* Add number of days till given month*/
0144     seconds += monthDays[datetime->month];
0145     /* Add days in given month. We subtract the current day as it is
0146      * represented in the hours, minutes and seconds field*/
0147     seconds += ((uint32_t)datetime->day - 1U);
0148     /* For leap year if month less than or equal to Febraury, decrement day counter*/
0149     if ((0U == (datetime->year & 3U)) && (datetime->month <= 2U))
0150     {
0151         seconds--;
0152     }
0153 
0154     seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
0155               (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
0156 
0157     return seconds;
0158 }
0159 
0160 static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime)
0161 {
0162     assert(datetime != NULL);
0163 
0164     uint32_t x;
0165     uint32_t secondsRemaining, days;
0166     uint16_t daysInYear;
0167     /* Table of days in a month for a non leap year. First entry in the table is not used,
0168      * valid months start from 1
0169      */
0170     uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
0171 
0172     /* Start with the seconds value that is passed in to be converted to date time format */
0173     secondsRemaining = seconds;
0174 
0175     /* Calcuate the number of days, we add 1 for the current day which is represented in the
0176      * hours and seconds field
0177      */
0178     days = secondsRemaining / SECONDS_IN_A_DAY + 1U;
0179 
0180     /* Update seconds left*/
0181     secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
0182 
0183     /* Calculate the datetime hour, minute and second fields */
0184     datetime->hour   = (uint8_t)(secondsRemaining / SECONDS_IN_A_HOUR);
0185     secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
0186     datetime->minute = (uint8_t)(secondsRemaining / 60U);
0187     datetime->second = (uint8_t)(secondsRemaining % SECONDS_IN_A_MINUTE);
0188 
0189     /* Calculate year */
0190     daysInYear     = DAYS_IN_A_YEAR;
0191     datetime->year = YEAR_RANGE_START;
0192     while (days > daysInYear)
0193     {
0194         /* Decrease day count by a year and increment year by 1 */
0195         days -= daysInYear;
0196         datetime->year++;
0197 
0198         /* Adjust the number of days for a leap year */
0199         if ((datetime->year & 3U) != 0U)
0200         {
0201             daysInYear = DAYS_IN_A_YEAR;
0202         }
0203         else
0204         {
0205             daysInYear = DAYS_IN_A_YEAR + 1U;
0206         }
0207     }
0208 
0209     /* Adjust the days in February for a leap year */
0210     if (0U == (datetime->year & 3U))
0211     {
0212         daysPerMonth[2] = 29U;
0213     }
0214 
0215     for (x = 1U; x <= 12U; x++)
0216     {
0217         if (days <= daysPerMonth[x])
0218         {
0219             datetime->month = (uint8_t)x;
0220             break;
0221         }
0222         else
0223         {
0224             days -= daysPerMonth[x];
0225         }
0226     }
0227 
0228     datetime->day = (uint8_t)days;
0229 }
0230 
0231 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
0232      defined(SNVS_HP_CLOCKS))
0233 static uint32_t SNVS_HP_GetInstance(SNVS_Type *base)
0234 {
0235     return 0U;
0236 }
0237 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0238 
0239 /*!
0240  * brief Initialize the SNVS.
0241  *
0242  * note This API should be called at the beginning of the application using the SNVS driver.
0243  *
0244  * param base SNVS peripheral base address
0245  */
0246 void SNVS_HP_Init(SNVS_Type *base)
0247 {
0248 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
0249      defined(SNVS_HP_CLOCKS))
0250     uint32_t instance = SNVS_HP_GetInstance(base);
0251     CLOCK_EnableClock(s_snvsHpClock[instance]);
0252 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0253 }
0254 
0255 /*!
0256  * brief Deinitialize the SNVS.
0257  *
0258  * param base SNVS peripheral base address
0259  */
0260 void SNVS_HP_Deinit(SNVS_Type *base)
0261 {
0262 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
0263      defined(SNVS_HP_CLOCKS))
0264     uint32_t instance = SNVS_HP_GetInstance(base);
0265     CLOCK_DisableClock(s_snvsHpClock[instance]);
0266 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0267 }
0268 
0269 /*!
0270  * brief Ungates the SNVS clock and configures the peripheral for basic operation.
0271  *
0272  * note This API should be called at the beginning of the application using the SNVS driver.
0273  *
0274  * param base   SNVS peripheral base address
0275  * param config Pointer to the user's SNVS configuration structure.
0276  */
0277 void SNVS_HP_RTC_Init(SNVS_Type *base, const snvs_hp_rtc_config_t *config)
0278 {
0279     assert(config != NULL);
0280 
0281     SNVS_HP_Init(base);
0282 
0283     base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN_MASK;
0284 
0285     base->HPCR = (base->HPCR & ~SNVS_HPCR_PI_FREQ_MASK) | SNVS_HPCR_PI_FREQ(config->periodicInterruptFreq);
0286 
0287     if (config->rtcCalEnable)
0288     {
0289         base->HPCR = (base->HPCR & ~SNVS_HPCR_HPCALB_VAL_MASK) | SNVS_HPCR_HPCALB_VAL(config->rtcCalValue);
0290         base->HPCR |= SNVS_HPCR_HPCALB_EN_MASK;
0291     }
0292 }
0293 
0294 /*!
0295  * brief Stops the RTC and SRTC timers.
0296  *
0297  * param base SNVS peripheral base address
0298  */
0299 void SNVS_HP_RTC_Deinit(SNVS_Type *base)
0300 {
0301     base->HPCR &= ~SNVS_HPCR_RTC_EN_MASK;
0302 
0303     SNVS_HP_Deinit(base);
0304 }
0305 
0306 /*!
0307  * brief Fills in the SNVS config struct with the default settings.
0308  *
0309  * The default values are as follows.
0310  * code
0311  *    config->rtccalenable = false;
0312  *    config->rtccalvalue = 0U;
0313  *    config->PIFreq = 0U;
0314  * endcode
0315  * param config Pointer to the user's SNVS configuration structure.
0316  */
0317 void SNVS_HP_RTC_GetDefaultConfig(snvs_hp_rtc_config_t *config)
0318 {
0319     assert(config != NULL);
0320 
0321     /* Initializes the configure structure to zero. */
0322     (void)memset(config, 0, sizeof(*config));
0323 
0324     config->rtcCalEnable          = false;
0325     config->rtcCalValue           = 0U;
0326     config->periodicInterruptFreq = 0U;
0327 }
0328 
0329 static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base)
0330 {
0331     uint32_t seconds = 0;
0332     uint32_t tmp     = 0;
0333 
0334     /* Do consecutive reads until value is correct */
0335     do
0336     {
0337         seconds = tmp;
0338         tmp     = (base->HPRTCMR << 17U);
0339         tmp |= (base->HPRTCLR >> 15U);
0340     } while (tmp != seconds);
0341 
0342     return seconds;
0343 }
0344 
0345 /*!
0346  * brief Sets the SNVS RTC date and time according to the given time structure.
0347  *
0348  * param base     SNVS peripheral base address
0349  * param datetime Pointer to the structure where the date and time details are stored.
0350  *
0351  * return kStatus_Success: Success in setting the time and starting the SNVS RTC
0352  *         kStatus_InvalidArgument: Error because the datetime format is incorrect
0353  */
0354 status_t SNVS_HP_RTC_SetDatetime(SNVS_Type *base, const snvs_hp_rtc_datetime_t *datetime)
0355 {
0356     assert(datetime != NULL);
0357 
0358     uint32_t seconds = 0U;
0359     uint32_t tmp     = base->HPCR;
0360 
0361     /* disable RTC */
0362     SNVS_HP_RTC_StopTimer(base);
0363 
0364     /* Return error if the time provided is not valid */
0365     if (!(SNVS_HP_CheckDatetimeFormat(datetime)))
0366     {
0367         return kStatus_InvalidArgument;
0368     }
0369 
0370     /* Set time in seconds */
0371     seconds = SNVS_HP_ConvertDatetimeToSeconds(datetime);
0372 
0373     base->HPRTCMR = (uint32_t)(seconds >> 17U);
0374     base->HPRTCLR = (uint32_t)(seconds << 15U);
0375 
0376     /* reenable RTC in case that it was enabled before */
0377     if ((tmp & SNVS_HPCR_RTC_EN_MASK) != 0U)
0378     {
0379         SNVS_HP_RTC_StartTimer(base);
0380     }
0381 
0382     return kStatus_Success;
0383 }
0384 
0385 /*!
0386  * brief Gets the SNVS RTC time and stores it in the given time structure.
0387  *
0388  * param base     SNVS peripheral base address
0389  * param datetime Pointer to the structure where the date and time details are stored.
0390  */
0391 void SNVS_HP_RTC_GetDatetime(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
0392 {
0393     assert(datetime != NULL);
0394 
0395     SNVS_HP_ConvertSecondsToDatetime(SNVS_HP_RTC_GetSeconds(base), datetime);
0396 }
0397 
0398 /*!
0399  * brief Sets the SNVS RTC alarm time.
0400  *
0401  * The function sets the RTC alarm. It also checks whether the specified alarm time
0402  * is greater than the present time. If not, the function does not set the alarm
0403  * and returns an error.
0404  *
0405  * param base      SNVS peripheral base address
0406  * param alarmTime Pointer to the structure where the alarm time is stored.
0407  *
0408  * return kStatus_Success: success in setting the SNVS RTC alarm
0409  *         kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
0410  *         kStatus_Fail: Error because the alarm time has already passed
0411  */
0412 status_t SNVS_HP_RTC_SetAlarm(SNVS_Type *base, const snvs_hp_rtc_datetime_t *alarmTime)
0413 {
0414     assert(alarmTime != NULL);
0415 
0416     uint32_t alarmSeconds = 0U;
0417     uint32_t currSeconds  = 0U;
0418     uint32_t tmp          = base->HPCR;
0419 
0420     /* Return error if the alarm time provided is not valid */
0421     if (!(SNVS_HP_CheckDatetimeFormat(alarmTime)))
0422     {
0423         return kStatus_InvalidArgument;
0424     }
0425 
0426     alarmSeconds = SNVS_HP_ConvertDatetimeToSeconds(alarmTime);
0427     currSeconds  = SNVS_HP_RTC_GetSeconds(base);
0428 
0429     /* Return error if the alarm time has passed */
0430     if (alarmSeconds < currSeconds)
0431     {
0432         return kStatus_Fail;
0433     }
0434 
0435     /* disable RTC alarm interrupt */
0436     base->HPCR &= ~SNVS_HPCR_HPTA_EN_MASK;
0437     while ((base->HPCR & SNVS_HPCR_HPTA_EN_MASK) != 0U)
0438     {
0439     }
0440 
0441     /* Set alarm in seconds*/
0442     base->HPTAMR = (uint32_t)(alarmSeconds >> 17U);
0443     base->HPTALR = (uint32_t)(alarmSeconds << 15U);
0444 
0445     /* reenable RTC alarm interrupt in case that it was enabled before */
0446     base->HPCR = tmp;
0447 
0448     return kStatus_Success;
0449 }
0450 
0451 /*!
0452  * brief Returns the SNVS RTC alarm time.
0453  *
0454  * param base     SNVS peripheral base address
0455  * param datetime Pointer to the structure where the alarm date and time details are stored.
0456  */
0457 void SNVS_HP_RTC_GetAlarm(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
0458 {
0459     assert(datetime != NULL);
0460 
0461     uint32_t alarmSeconds = 0U;
0462 
0463     /* Get alarm in seconds  */
0464     alarmSeconds = (base->HPTAMR << 17U);
0465     alarmSeconds |= (base->HPTALR >> 15U);
0466 
0467     SNVS_HP_ConvertSecondsToDatetime(alarmSeconds, datetime);
0468 }
0469 
0470 #if (defined(FSL_FEATURE_SNVS_HAS_SRTC) && (FSL_FEATURE_SNVS_HAS_SRTC > 0))
0471 /*!
0472  * brief The function synchronizes RTC counter value with SRTC.
0473  *
0474  * param base SNVS peripheral base address
0475  */
0476 void SNVS_HP_RTC_TimeSynchronize(SNVS_Type *base)
0477 {
0478     uint32_t tmp = base->HPCR;
0479 
0480     /* disable RTC */
0481     SNVS_HP_RTC_StopTimer(base);
0482 
0483     base->HPCR |= SNVS_HPCR_HP_TS_MASK;
0484 
0485     /* reenable RTC in case that it was enabled before */
0486     if ((tmp & SNVS_HPCR_RTC_EN_MASK) != 0U)
0487     {
0488         SNVS_HP_RTC_StartTimer(base);
0489     }
0490 }
0491 #endif /* FSL_FEATURE_SNVS_HAS_SRTC */
0492 
0493 /*!
0494  * brief Gets the SNVS status flags.
0495  *
0496  * param base SNVS peripheral base address
0497  *
0498  * return The status flags. This is the logical OR of members of the
0499  *         enumeration ::snvs_status_flags_t
0500  */
0501 uint32_t SNVS_HP_RTC_GetStatusFlags(SNVS_Type *base)
0502 {
0503     uint32_t flags = 0U;
0504 
0505     if ((base->HPSR & SNVS_HPSR_PI_MASK) != 0U)
0506     {
0507         flags |= (uint32_t)kSNVS_RTC_PeriodicInterruptFlag;
0508     }
0509 
0510     if ((base->HPSR & SNVS_HPSR_HPTA_MASK) != 0U)
0511     {
0512         flags |= (uint32_t)kSNVS_RTC_AlarmInterruptFlag;
0513     }
0514 
0515     return flags;
0516 }
0517 
0518 /*!
0519  * brief Gets the enabled SNVS interrupts.
0520  *
0521  * param base SNVS peripheral base address
0522  *
0523  * return The enabled interrupts. This is the logical OR of members of the
0524  *         enumeration ::snvs_interrupt_enable_t
0525  */
0526 uint32_t SNVS_HP_RTC_GetEnabledInterrupts(SNVS_Type *base)
0527 {
0528     uint32_t val = 0U;
0529 
0530     if ((base->HPCR & SNVS_HPCR_PI_EN_MASK) != 0U)
0531     {
0532         val |= (uint32_t)kSNVS_RTC_PeriodicInterrupt;
0533     }
0534 
0535     if ((base->HPCR & SNVS_HPCR_HPTA_EN_MASK) != 0U)
0536     {
0537         val |= (uint32_t)kSNVS_RTC_AlarmInterrupt;
0538     }
0539 
0540     return val;
0541 }
0542 
0543 #if defined(FSL_FEATURE_SNVS_HAS_SET_LOCK) && (FSL_FEATURE_SNVS_HAS_SET_LOCK > 0)
0544 /*!
0545  * brief Set SNVS HP Set locks.
0546  *
0547  * param base SNVS peripheral base address
0548  *
0549  */
0550 void SNVS_HP_SetLocks(SNVS_Type *base)
0551 {
0552     uint32_t sec_config = ((OCOTP_CTRL->HW_OCOTP_OTFAD_CFG3 & OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_MASK) >>
0553                            OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_SHIFT);
0554 
0555     if (sec_config == SEC_CONFIG_OPEN)
0556     {
0557         /* Enable non-secure SW access */
0558         base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN(1);
0559     }
0560 
0561     /* Set LP Software Reset Disable lock and ZMK Write Soft Lock */
0562     base->HPCOMR |= SNVS_HPCOMR_LP_SWR_DIS(1);
0563     base->HPLR |= SNVS_HPLR_ZMK_WSL(1);
0564 }
0565 #endif /* FSL_FEATURE_SNVS_HAS_SET_LOCK */