fsl_snvs_hp.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /*
  2. * The Clear BSD License
  3. * Copyright (c) 2016, Freescale Semiconductor, Inc.
  4. * Copyright (c) 2017, NXP
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted (subject to the limitations in the disclaimer below) provided
  9. * that the following conditions are met:
  10. *
  11. * o Redistributions of source code must retain the above copyright notice, this list
  12. * of conditions and the following disclaimer.
  13. *
  14. * o Redistributions in binary form must reproduce the above copyright notice, this
  15. * list of conditions and the following disclaimer in the documentation and/or
  16. * other materials provided with the distribution.
  17. *
  18. * o Neither the name of the copyright holder nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  27. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  30. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include "fsl_snvs_hp.h"
  35. /*******************************************************************************
  36. * Definitions
  37. ******************************************************************************/
  38. /* Component ID definition, used by tools. */
  39. #ifndef FSL_COMPONENT_ID
  40. #define FSL_COMPONENT_ID "platform.drivers.snvs_hp"
  41. #endif
  42. #define SECONDS_IN_A_DAY (86400U)
  43. #define SECONDS_IN_A_HOUR (3600U)
  44. #define SECONDS_IN_A_MINUTE (60U)
  45. #define DAYS_IN_A_YEAR (365U)
  46. #define YEAR_RANGE_START (1970U)
  47. #define YEAR_RANGE_END (2099U)
  48. #if !(defined(SNVS_HPCOMR_SW_SV_MASK))
  49. #define SNVS_HPCOMR_SW_SV_MASK (0x100U)
  50. #endif
  51. #if !(defined(SNVS_HPSR_PI_MASK))
  52. #define SNVS_HPSR_PI_MASK (0x2U)
  53. #endif
  54. #if !(defined(SNVS_HPSR_HPTA_MASK))
  55. #define SNVS_HPSR_HPTA_MASK (0x1U)
  56. #endif
  57. /*******************************************************************************
  58. * Prototypes
  59. ******************************************************************************/
  60. /*!
  61. * @brief Checks whether the date and time passed in is valid
  62. *
  63. * @param datetime Pointer to structure where the date and time details are stored
  64. *
  65. * @return Returns false if the date & time details are out of range; true if in range
  66. */
  67. static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime);
  68. /*!
  69. * @brief Converts time data from datetime to seconds
  70. *
  71. * @param datetime Pointer to datetime structure where the date and time details are stored
  72. *
  73. * @return The result of the conversion in seconds
  74. */
  75. static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime);
  76. /*!
  77. * @brief Converts time data from seconds to a datetime structure
  78. *
  79. * @param seconds Seconds value that needs to be converted to datetime format
  80. * @param datetime Pointer to the datetime structure where the result of the conversion is stored
  81. */
  82. static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime);
  83. /*!
  84. * @brief Returns RTC time in seconds.
  85. *
  86. * This function is used internally to get actual RTC time in seconds.
  87. *
  88. * @param base SNVS peripheral base address
  89. *
  90. * @return RTC time in seconds
  91. */
  92. static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base);
  93. #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
  94. defined(SNVS_HP_CLOCKS))
  95. /*!
  96. * @brief Get the SNVS instance from peripheral base address.
  97. *
  98. * @param base SNVS peripheral base address.
  99. *
  100. * @return SNVS instance.
  101. */
  102. static uint32_t SNVS_HP_GetInstance(SNVS_Type *base);
  103. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  104. /*******************************************************************************
  105. * Variables
  106. ******************************************************************************/
  107. #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
  108. defined(SNVS_HP_CLOCKS))
  109. /*! @brief Pointer to snvs_hp clock. */
  110. const clock_ip_name_t s_snvsHpClock[] = SNVS_HP_CLOCKS;
  111. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  112. /*******************************************************************************
  113. * Code
  114. ******************************************************************************/
  115. static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime)
  116. {
  117. assert(datetime);
  118. /* Table of days in a month for a non leap year. First entry in the table is not used,
  119. * valid months start from 1
  120. */
  121. uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
  122. /* Check year, month, hour, minute, seconds */
  123. if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
  124. (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
  125. {
  126. /* If not correct then error*/
  127. return false;
  128. }
  129. /* Adjust the days in February for a leap year */
  130. if ((((datetime->year & 3U) == 0) && (datetime->year % 100 != 0)) || (datetime->year % 400 == 0))
  131. {
  132. daysPerMonth[2] = 29U;
  133. }
  134. /* Check the validity of the day */
  135. if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
  136. {
  137. return false;
  138. }
  139. return true;
  140. }
  141. static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime)
  142. {
  143. assert(datetime);
  144. /* Number of days from begin of the non Leap-year*/
  145. /* Number of days from begin of the non Leap-year*/
  146. uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
  147. uint32_t seconds;
  148. /* Compute number of days from 1970 till given year*/
  149. seconds = (datetime->year - 1970U) * DAYS_IN_A_YEAR;
  150. /* Add leap year days */
  151. seconds += ((datetime->year / 4) - (1970U / 4));
  152. /* Add number of days till given month*/
  153. seconds += monthDays[datetime->month];
  154. /* Add days in given month. We subtract the current day as it is
  155. * represented in the hours, minutes and seconds field*/
  156. seconds += (datetime->day - 1);
  157. /* For leap year if month less than or equal to Febraury, decrement day counter*/
  158. if ((!(datetime->year & 3U)) && (datetime->month <= 2U))
  159. {
  160. seconds--;
  161. }
  162. seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
  163. (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
  164. return seconds;
  165. }
  166. static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime)
  167. {
  168. assert(datetime);
  169. uint32_t x;
  170. uint32_t secondsRemaining, days;
  171. uint16_t daysInYear;
  172. /* Table of days in a month for a non leap year. First entry in the table is not used,
  173. * valid months start from 1
  174. */
  175. uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
  176. /* Start with the seconds value that is passed in to be converted to date time format */
  177. secondsRemaining = seconds;
  178. /* Calcuate the number of days, we add 1 for the current day which is represented in the
  179. * hours and seconds field
  180. */
  181. days = secondsRemaining / SECONDS_IN_A_DAY + 1;
  182. /* Update seconds left*/
  183. secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
  184. /* Calculate the datetime hour, minute and second fields */
  185. datetime->hour = secondsRemaining / SECONDS_IN_A_HOUR;
  186. secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
  187. datetime->minute = secondsRemaining / 60U;
  188. datetime->second = secondsRemaining % SECONDS_IN_A_MINUTE;
  189. /* Calculate year */
  190. daysInYear = DAYS_IN_A_YEAR;
  191. datetime->year = YEAR_RANGE_START;
  192. while (days > daysInYear)
  193. {
  194. /* Decrease day count by a year and increment year by 1 */
  195. days -= daysInYear;
  196. datetime->year++;
  197. /* Adjust the number of days for a leap year */
  198. if (datetime->year & 3U)
  199. {
  200. daysInYear = DAYS_IN_A_YEAR;
  201. }
  202. else
  203. {
  204. daysInYear = DAYS_IN_A_YEAR + 1;
  205. }
  206. }
  207. /* Adjust the days in February for a leap year */
  208. if (!(datetime->year & 3U))
  209. {
  210. daysPerMonth[2] = 29U;
  211. }
  212. for (x = 1U; x <= 12U; x++)
  213. {
  214. if (days <= daysPerMonth[x])
  215. {
  216. datetime->month = x;
  217. break;
  218. }
  219. else
  220. {
  221. days -= daysPerMonth[x];
  222. }
  223. }
  224. datetime->day = days;
  225. }
  226. #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
  227. defined(SNVS_HP_CLOCKS))
  228. static uint32_t SNVS_HP_GetInstance(SNVS_Type *base)
  229. {
  230. return 0U;
  231. }
  232. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  233. void SNVS_HP_RTC_Init(SNVS_Type *base, const snvs_hp_rtc_config_t *config)
  234. {
  235. assert(config);
  236. #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
  237. defined(SNVS_HP_CLOCKS))
  238. uint32_t instance = SNVS_HP_GetInstance(base);
  239. CLOCK_EnableClock(s_snvsHpClock[instance]);
  240. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  241. base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN_MASK | SNVS_HPCOMR_SW_SV_MASK;
  242. base->HPCR = SNVS_HPCR_PI_FREQ(config->periodicInterruptFreq);
  243. if (config->rtcCalEnable)
  244. {
  245. base->HPCR = SNVS_HPCR_HPCALB_VAL_MASK & (config->rtcCalValue << SNVS_HPCR_HPCALB_VAL_SHIFT);
  246. base->HPCR |= SNVS_HPCR_HPCALB_EN_MASK;
  247. }
  248. }
  249. void SNVS_HP_RTC_Deinit(SNVS_Type *base)
  250. {
  251. base->HPCR &= ~SNVS_HPCR_RTC_EN_MASK;
  252. #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
  253. defined(SNVS_HP_CLOCKS))
  254. uint32_t instance = SNVS_HP_GetInstance(base);
  255. CLOCK_DisableClock(s_snvsHpClock[instance]);
  256. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  257. }
  258. void SNVS_HP_RTC_GetDefaultConfig(snvs_hp_rtc_config_t *config)
  259. {
  260. assert(config);
  261. config->rtcCalEnable = false;
  262. config->rtcCalValue = 0U;
  263. config->periodicInterruptFreq = 0U;
  264. }
  265. static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base)
  266. {
  267. uint32_t seconds = 0;
  268. uint32_t tmp = 0;
  269. /* Do consecutive reads until value is correct */
  270. do
  271. {
  272. seconds = tmp;
  273. tmp = (base->HPRTCMR << 17U) | (base->HPRTCLR >> 15U);
  274. } while (tmp != seconds);
  275. return seconds;
  276. }
  277. status_t SNVS_HP_RTC_SetDatetime(SNVS_Type *base, const snvs_hp_rtc_datetime_t *datetime)
  278. {
  279. assert(datetime);
  280. uint32_t seconds = 0U;
  281. uint32_t tmp = base->HPCR;
  282. /* disable RTC */
  283. SNVS_HP_RTC_StopTimer(base);
  284. /* Return error if the time provided is not valid */
  285. if (!(SNVS_HP_CheckDatetimeFormat(datetime)))
  286. {
  287. return kStatus_InvalidArgument;
  288. }
  289. /* Set time in seconds */
  290. seconds = SNVS_HP_ConvertDatetimeToSeconds(datetime);
  291. base->HPRTCMR = (uint32_t)(seconds >> 17U);
  292. base->HPRTCLR = (uint32_t)(seconds << 15U);
  293. /* reenable RTC in case that it was enabled before */
  294. if (tmp & SNVS_HPCR_RTC_EN_MASK)
  295. {
  296. SNVS_HP_RTC_StartTimer(base);
  297. }
  298. return kStatus_Success;
  299. }
  300. void SNVS_HP_RTC_GetDatetime(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
  301. {
  302. assert(datetime);
  303. SNVS_HP_ConvertSecondsToDatetime(SNVS_HP_RTC_GetSeconds(base), datetime);
  304. }
  305. status_t SNVS_HP_RTC_SetAlarm(SNVS_Type *base, const snvs_hp_rtc_datetime_t *alarmTime)
  306. {
  307. assert(alarmTime);
  308. uint32_t alarmSeconds = 0U;
  309. uint32_t currSeconds = 0U;
  310. uint32_t tmp = base->HPCR;
  311. /* Return error if the alarm time provided is not valid */
  312. if (!(SNVS_HP_CheckDatetimeFormat(alarmTime)))
  313. {
  314. return kStatus_InvalidArgument;
  315. }
  316. alarmSeconds = SNVS_HP_ConvertDatetimeToSeconds(alarmTime);
  317. currSeconds = SNVS_HP_RTC_GetSeconds(base);
  318. /* Return error if the alarm time has passed */
  319. if (alarmSeconds < currSeconds)
  320. {
  321. return kStatus_Fail;
  322. }
  323. /* disable RTC alarm interrupt */
  324. base->HPCR &= ~SNVS_HPCR_HPTA_EN_MASK;
  325. while (base->HPCR & SNVS_HPCR_HPTA_EN_MASK)
  326. {
  327. }
  328. /* Set alarm in seconds*/
  329. base->HPTAMR = (uint32_t)(alarmSeconds >> 17U);
  330. base->HPTALR = (uint32_t)(alarmSeconds << 15U);
  331. /* reenable RTC alarm interrupt in case that it was enabled before */
  332. base->HPCR = tmp;
  333. return kStatus_Success;
  334. }
  335. void SNVS_HP_RTC_GetAlarm(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
  336. {
  337. assert(datetime);
  338. uint32_t alarmSeconds = 0U;
  339. /* Get alarm in seconds */
  340. alarmSeconds = (base->HPTAMR << 17U) | (base->HPTALR >> 15U);
  341. SNVS_HP_ConvertSecondsToDatetime(alarmSeconds, datetime);
  342. }
  343. #if (defined(FSL_FEATURE_SNVS_HAS_SRTC) && (FSL_FEATURE_SNVS_HAS_SRTC > 0))
  344. void SNVS_HP_RTC_TimeSynchronize(SNVS_Type *base)
  345. {
  346. uint32_t tmp = base->HPCR;
  347. /* disable RTC */
  348. SNVS_HP_RTC_StopTimer(base);
  349. base->HPCR |= SNVS_HPCR_HP_TS_MASK;
  350. /* reenable RTC in case that it was enabled before */
  351. if (tmp & SNVS_HPCR_RTC_EN_MASK)
  352. {
  353. SNVS_HP_RTC_StartTimer(base);
  354. }
  355. }
  356. #endif /* FSL_FEATURE_SNVS_HAS_SRTC */
  357. uint32_t SNVS_HP_RTC_GetStatusFlags(SNVS_Type *base)
  358. {
  359. uint32_t flags = 0U;
  360. if (base->HPSR & SNVS_HPSR_PI_MASK)
  361. {
  362. flags |= kSNVS_RTC_PeriodicInterruptFlag;
  363. }
  364. if (base->HPSR & SNVS_HPSR_HPTA_MASK)
  365. {
  366. flags |= kSNVS_RTC_AlarmInterruptFlag;
  367. }
  368. return flags;
  369. }
  370. uint32_t SNVS_HP_RTC_GetEnabledInterrupts(SNVS_Type *base)
  371. {
  372. uint32_t val = 0U;
  373. if (base->HPCR & SNVS_HPCR_PI_EN_MASK)
  374. {
  375. val |= kSNVS_RTC_PeriodicInterrupt;
  376. }
  377. if (base->HPCR & SNVS_HPCR_HPTA_EN_MASK)
  378. {
  379. val |= kSNVS_RTC_AlarmInterrupt;
  380. }
  381. return val;
  382. }