1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2017-2019, NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_snvs_hp.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.snvs_hp"
18 #endif
19
20 #define SECONDS_IN_A_DAY (86400U)
21 #define SECONDS_IN_A_HOUR (3600U)
22 #define SECONDS_IN_A_MINUTE (60U)
23 #define DAYS_IN_A_YEAR (365U)
24 #define YEAR_RANGE_START (1970U)
25 #define YEAR_RANGE_END (2099U)
26
27 #if !(defined(SNVS_HPSR_PI_MASK))
28 #define SNVS_HPSR_PI_MASK (0x2U)
29 #endif
30 #if !(defined(SNVS_HPSR_HPTA_MASK))
31 #define SNVS_HPSR_HPTA_MASK (0x1U)
32 #endif
33
34 /*******************************************************************************
35 * Prototypes
36 ******************************************************************************/
37 /*!
38 * @brief Checks whether the date and time passed in is valid
39 *
40 * @param datetime Pointer to structure where the date and time details are stored
41 *
42 * @return Returns false if the date & time details are out of range; true if in range
43 */
44 static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime);
45
46 /*!
47 * @brief Converts time data from datetime to seconds
48 *
49 * @param datetime Pointer to datetime structure where the date and time details are stored
50 *
51 * @return The result of the conversion in seconds
52 */
53 static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime);
54
55 /*!
56 * @brief Converts time data from seconds to a datetime structure
57 *
58 * @param seconds Seconds value that needs to be converted to datetime format
59 * @param datetime Pointer to the datetime structure where the result of the conversion is stored
60 */
61 static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime);
62
63 /*!
64 * @brief Returns RTC time in seconds.
65 *
66 * This function is used internally to get actual RTC time in seconds.
67 *
68 * @param base SNVS peripheral base address
69 *
70 * @return RTC time in seconds
71 */
72 static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base);
73
74 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
75 defined(SNVS_HP_CLOCKS))
76 /*!
77 * @brief Get the SNVS instance from peripheral base address.
78 *
79 * @param base SNVS peripheral base address.
80 *
81 * @return SNVS instance.
82 */
83 static uint32_t SNVS_HP_GetInstance(SNVS_Type *base);
84 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
85
86 /*******************************************************************************
87 * Variables
88 ******************************************************************************/
89 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
90 defined(SNVS_HP_CLOCKS))
91 /*! @brief Pointer to snvs_hp clock. */
92 static const clock_ip_name_t s_snvsHpClock[] = SNVS_HP_CLOCKS;
93 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
94
95 /*******************************************************************************
96 * Code
97 ******************************************************************************/
SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t * datetime)98 static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime)
99 {
100 assert(datetime != NULL);
101
102 /* Table of days in a month for a non leap year. First entry in the table is not used,
103 * valid months start from 1
104 */
105 uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
106
107 /* Check year, month, hour, minute, seconds */
108 if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
109 (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
110 {
111 /* If not correct then error*/
112 return false;
113 }
114
115 /* Adjust the days in February for a leap year */
116 if ((((datetime->year & 3U) == 0U) && (datetime->year % 100U != 0U)) || (datetime->year % 400U == 0U))
117 {
118 daysPerMonth[2] = 29U;
119 }
120
121 /* Check the validity of the day */
122 if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
123 {
124 return false;
125 }
126
127 return true;
128 }
129
SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t * datetime)130 static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime)
131 {
132 assert(datetime != NULL);
133
134 /* Number of days from begin of the non Leap-year*/
135 /* Number of days from begin of the non Leap-year*/
136 uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
137 uint32_t seconds;
138
139 /* Compute number of days from 1970 till given year*/
140 seconds = (((uint32_t)datetime->year - 1970U) * DAYS_IN_A_YEAR);
141 /* Add leap year days */
142 seconds += (((uint32_t)datetime->year / 4U) - (1970U / 4U));
143 /* Add number of days till given month*/
144 seconds += monthDays[datetime->month];
145 /* Add days in given month. We subtract the current day as it is
146 * represented in the hours, minutes and seconds field*/
147 seconds += ((uint32_t)datetime->day - 1U);
148 /* For leap year if month less than or equal to Febraury, decrement day counter*/
149 if ((0U == (datetime->year & 3U)) && (datetime->month <= 2U))
150 {
151 seconds--;
152 }
153
154 seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
155 (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
156
157 return seconds;
158 }
159
SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds,snvs_hp_rtc_datetime_t * datetime)160 static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime)
161 {
162 assert(datetime != NULL);
163
164 uint32_t x;
165 uint32_t secondsRemaining, days;
166 uint16_t daysInYear;
167 /* Table of days in a month for a non leap year. First entry in the table is not used,
168 * valid months start from 1
169 */
170 uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
171
172 /* Start with the seconds value that is passed in to be converted to date time format */
173 secondsRemaining = seconds;
174
175 /* Calcuate the number of days, we add 1 for the current day which is represented in the
176 * hours and seconds field
177 */
178 days = secondsRemaining / SECONDS_IN_A_DAY + 1U;
179
180 /* Update seconds left*/
181 secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
182
183 /* Calculate the datetime hour, minute and second fields */
184 datetime->hour = (uint8_t)(secondsRemaining / SECONDS_IN_A_HOUR);
185 secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
186 datetime->minute = (uint8_t)(secondsRemaining / 60U);
187 datetime->second = (uint8_t)(secondsRemaining % SECONDS_IN_A_MINUTE);
188
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
198 /* Adjust the number of days for a leap year */
199 if ((datetime->year & 3U) != 0U)
200 {
201 daysInYear = DAYS_IN_A_YEAR;
202 }
203 else
204 {
205 daysInYear = DAYS_IN_A_YEAR + 1U;
206 }
207 }
208
209 /* Adjust the days in February for a leap year */
210 if (0U == (datetime->year & 3U))
211 {
212 daysPerMonth[2] = 29U;
213 }
214
215 for (x = 1U; x <= 12U; x++)
216 {
217 if (days <= daysPerMonth[x])
218 {
219 datetime->month = (uint8_t)x;
220 break;
221 }
222 else
223 {
224 days -= daysPerMonth[x];
225 }
226 }
227
228 datetime->day = (uint8_t)days;
229 }
230
231 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
232 defined(SNVS_HP_CLOCKS))
SNVS_HP_GetInstance(SNVS_Type * base)233 static uint32_t SNVS_HP_GetInstance(SNVS_Type *base)
234 {
235 return 0U;
236 }
237 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
238
239 /*!
240 * brief Initialize the SNVS.
241 *
242 * note This API should be called at the beginning of the application using the SNVS driver.
243 *
244 * param base SNVS peripheral base address
245 */
SNVS_HP_Init(SNVS_Type * base)246 void SNVS_HP_Init(SNVS_Type *base)
247 {
248 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
249 defined(SNVS_HP_CLOCKS))
250 uint32_t instance = SNVS_HP_GetInstance(base);
251 CLOCK_EnableClock(s_snvsHpClock[instance]);
252 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
253 }
254
255 /*!
256 * brief Deinitialize the SNVS.
257 *
258 * param base SNVS peripheral base address
259 */
SNVS_HP_Deinit(SNVS_Type * base)260 void SNVS_HP_Deinit(SNVS_Type *base)
261 {
262 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
263 defined(SNVS_HP_CLOCKS))
264 uint32_t instance = SNVS_HP_GetInstance(base);
265 CLOCK_DisableClock(s_snvsHpClock[instance]);
266 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
267 }
268
269 /*!
270 * brief Ungates the SNVS clock and configures the peripheral for basic operation.
271 *
272 * note This API should be called at the beginning of the application using the SNVS driver.
273 *
274 * param base SNVS peripheral base address
275 * param config Pointer to the user's SNVS configuration structure.
276 */
SNVS_HP_RTC_Init(SNVS_Type * base,const snvs_hp_rtc_config_t * config)277 void SNVS_HP_RTC_Init(SNVS_Type *base, const snvs_hp_rtc_config_t *config)
278 {
279 assert(config != NULL);
280
281 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
282 defined(SNVS_HP_CLOCKS))
283 uint32_t instance = SNVS_HP_GetInstance(base);
284 CLOCK_EnableClock(s_snvsHpClock[instance]);
285 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
286
287 base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN_MASK;
288
289 base->HPCR = SNVS_HPCR_PI_FREQ(config->periodicInterruptFreq);
290
291 if (config->rtcCalEnable)
292 {
293 base->HPCR |= SNVS_HPCR_HPCALB_VAL_MASK & (config->rtcCalValue << SNVS_HPCR_HPCALB_VAL_SHIFT);
294 base->HPCR |= SNVS_HPCR_HPCALB_EN_MASK;
295 }
296 }
297
298 /*!
299 * brief Stops the RTC and SRTC timers.
300 *
301 * param base SNVS peripheral base address
302 */
SNVS_HP_RTC_Deinit(SNVS_Type * base)303 void SNVS_HP_RTC_Deinit(SNVS_Type *base)
304 {
305 base->HPCR &= ~SNVS_HPCR_RTC_EN_MASK;
306
307 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
308 defined(SNVS_HP_CLOCKS))
309 uint32_t instance = SNVS_HP_GetInstance(base);
310 CLOCK_DisableClock(s_snvsHpClock[instance]);
311 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
312 }
313
314 /*!
315 * brief Fills in the SNVS config struct with the default settings.
316 *
317 * The default values are as follows.
318 * code
319 * config->rtccalenable = false;
320 * config->rtccalvalue = 0U;
321 * config->PIFreq = 0U;
322 * endcode
323 * param config Pointer to the user's SNVS configuration structure.
324 */
SNVS_HP_RTC_GetDefaultConfig(snvs_hp_rtc_config_t * config)325 void SNVS_HP_RTC_GetDefaultConfig(snvs_hp_rtc_config_t *config)
326 {
327 assert(config != NULL);
328
329 /* Initializes the configure structure to zero. */
330 (void)memset(config, 0, sizeof(*config));
331
332 config->rtcCalEnable = false;
333 config->rtcCalValue = 0U;
334 config->periodicInterruptFreq = 0U;
335 }
336
SNVS_HP_RTC_GetSeconds(SNVS_Type * base)337 static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base)
338 {
339 uint32_t seconds = 0;
340 uint32_t tmp = 0;
341
342 /* Do consecutive reads until value is correct */
343 do
344 {
345 seconds = tmp;
346 tmp = (base->HPRTCMR << 17U);
347 tmp |= (base->HPRTCLR >> 15U);
348 } while (tmp != seconds);
349
350 return seconds;
351 }
352
353 /*!
354 * brief Sets the SNVS RTC date and time according to the given time structure.
355 *
356 * param base SNVS peripheral base address
357 * param datetime Pointer to the structure where the date and time details are stored.
358 *
359 * return kStatus_Success: Success in setting the time and starting the SNVS RTC
360 * kStatus_InvalidArgument: Error because the datetime format is incorrect
361 */
SNVS_HP_RTC_SetDatetime(SNVS_Type * base,const snvs_hp_rtc_datetime_t * datetime)362 status_t SNVS_HP_RTC_SetDatetime(SNVS_Type *base, const snvs_hp_rtc_datetime_t *datetime)
363 {
364 assert(datetime != NULL);
365
366 uint32_t seconds = 0U;
367 uint32_t tmp = base->HPCR;
368
369 /* disable RTC */
370 SNVS_HP_RTC_StopTimer(base);
371
372 /* Return error if the time provided is not valid */
373 if (!(SNVS_HP_CheckDatetimeFormat(datetime)))
374 {
375 return kStatus_InvalidArgument;
376 }
377
378 /* Set time in seconds */
379 seconds = SNVS_HP_ConvertDatetimeToSeconds(datetime);
380
381 base->HPRTCMR = (uint32_t)(seconds >> 17U);
382 base->HPRTCLR = (uint32_t)(seconds << 15U);
383
384 /* reenable RTC in case that it was enabled before */
385 if ((tmp & SNVS_HPCR_RTC_EN_MASK) != 0U)
386 {
387 SNVS_HP_RTC_StartTimer(base);
388 }
389
390 return kStatus_Success;
391 }
392
393 /*!
394 * brief Gets the SNVS RTC time and stores it in the given time structure.
395 *
396 * param base SNVS peripheral base address
397 * param datetime Pointer to the structure where the date and time details are stored.
398 */
SNVS_HP_RTC_GetDatetime(SNVS_Type * base,snvs_hp_rtc_datetime_t * datetime)399 void SNVS_HP_RTC_GetDatetime(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
400 {
401 assert(datetime != NULL);
402
403 SNVS_HP_ConvertSecondsToDatetime(SNVS_HP_RTC_GetSeconds(base), datetime);
404 }
405
406 /*!
407 * brief Sets the SNVS RTC alarm time.
408 *
409 * The function sets the RTC alarm. It also checks whether the specified alarm time
410 * is greater than the present time. If not, the function does not set the alarm
411 * and returns an error.
412 *
413 * param base SNVS peripheral base address
414 * param alarmTime Pointer to the structure where the alarm time is stored.
415 *
416 * return kStatus_Success: success in setting the SNVS RTC alarm
417 * kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
418 * kStatus_Fail: Error because the alarm time has already passed
419 */
SNVS_HP_RTC_SetAlarm(SNVS_Type * base,const snvs_hp_rtc_datetime_t * alarmTime)420 status_t SNVS_HP_RTC_SetAlarm(SNVS_Type *base, const snvs_hp_rtc_datetime_t *alarmTime)
421 {
422 assert(alarmTime != NULL);
423
424 uint32_t alarmSeconds = 0U;
425 uint32_t currSeconds = 0U;
426 uint32_t tmp = base->HPCR;
427
428 /* Return error if the alarm time provided is not valid */
429 if (!(SNVS_HP_CheckDatetimeFormat(alarmTime)))
430 {
431 return kStatus_InvalidArgument;
432 }
433
434 alarmSeconds = SNVS_HP_ConvertDatetimeToSeconds(alarmTime);
435 currSeconds = SNVS_HP_RTC_GetSeconds(base);
436
437 /* Return error if the alarm time has passed */
438 if (alarmSeconds < currSeconds)
439 {
440 return kStatus_Fail;
441 }
442
443 /* disable RTC alarm interrupt */
444 base->HPCR &= ~SNVS_HPCR_HPTA_EN_MASK;
445 while ((base->HPCR & SNVS_HPCR_HPTA_EN_MASK) != 0U)
446 {
447 }
448
449 /* Set alarm in seconds*/
450 base->HPTAMR = (uint32_t)(alarmSeconds >> 17U);
451 base->HPTALR = (uint32_t)(alarmSeconds << 15U);
452
453 /* reenable RTC alarm interrupt in case that it was enabled before */
454 base->HPCR = tmp;
455
456 return kStatus_Success;
457 }
458
459 /*!
460 * brief Returns the SNVS RTC alarm time.
461 *
462 * param base SNVS peripheral base address
463 * param datetime Pointer to the structure where the alarm date and time details are stored.
464 */
SNVS_HP_RTC_GetAlarm(SNVS_Type * base,snvs_hp_rtc_datetime_t * datetime)465 void SNVS_HP_RTC_GetAlarm(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
466 {
467 assert(datetime != NULL);
468
469 uint32_t alarmSeconds = 0U;
470
471 /* Get alarm in seconds */
472 alarmSeconds = (base->HPTAMR << 17U);
473 alarmSeconds |= (base->HPTALR >> 15U);
474
475 SNVS_HP_ConvertSecondsToDatetime(alarmSeconds, datetime);
476 }
477
478 #if (defined(FSL_FEATURE_SNVS_HAS_SRTC) && (FSL_FEATURE_SNVS_HAS_SRTC > 0))
479 /*!
480 * brief The function synchronizes RTC counter value with SRTC.
481 *
482 * param base SNVS peripheral base address
483 */
SNVS_HP_RTC_TimeSynchronize(SNVS_Type * base)484 void SNVS_HP_RTC_TimeSynchronize(SNVS_Type *base)
485 {
486 uint32_t tmp = base->HPCR;
487
488 /* disable RTC */
489 SNVS_HP_RTC_StopTimer(base);
490
491 base->HPCR |= SNVS_HPCR_HP_TS_MASK;
492
493 /* reenable RTC in case that it was enabled before */
494 if ((tmp & SNVS_HPCR_RTC_EN_MASK) != 0U)
495 {
496 SNVS_HP_RTC_StartTimer(base);
497 }
498 }
499 #endif /* FSL_FEATURE_SNVS_HAS_SRTC */
500
501 /*!
502 * brief Gets the SNVS status flags.
503 *
504 * param base SNVS peripheral base address
505 *
506 * return The status flags. This is the logical OR of members of the
507 * enumeration ::snvs_status_flags_t
508 */
SNVS_HP_RTC_GetStatusFlags(SNVS_Type * base)509 uint32_t SNVS_HP_RTC_GetStatusFlags(SNVS_Type *base)
510 {
511 uint32_t flags = 0U;
512
513 if ((base->HPSR & SNVS_HPSR_PI_MASK) != 0U)
514 {
515 flags |= (uint32_t)kSNVS_RTC_PeriodicInterruptFlag;
516 }
517
518 if ((base->HPSR & SNVS_HPSR_HPTA_MASK) != 0U)
519 {
520 flags |= (uint32_t)kSNVS_RTC_AlarmInterruptFlag;
521 }
522
523 return flags;
524 }
525
526 /*!
527 * brief Gets the enabled SNVS interrupts.
528 *
529 * param base SNVS peripheral base address
530 *
531 * return The enabled interrupts. This is the logical OR of members of the
532 * enumeration ::snvs_interrupt_enable_t
533 */
SNVS_HP_RTC_GetEnabledInterrupts(SNVS_Type * base)534 uint32_t SNVS_HP_RTC_GetEnabledInterrupts(SNVS_Type *base)
535 {
536 uint32_t val = 0U;
537
538 if ((base->HPCR & SNVS_HPCR_PI_EN_MASK) != 0U)
539 {
540 val |= (uint32_t)kSNVS_RTC_PeriodicInterrupt;
541 }
542
543 if ((base->HPCR & SNVS_HPCR_HPTA_EN_MASK) != 0U)
544 {
545 val |= (uint32_t)kSNVS_RTC_AlarmInterrupt;
546 }
547
548 return val;
549 }
550
551 #if defined(FSL_FEATURE_SNVS_HAS_SET_LOCK) && (FSL_FEATURE_SNVS_HAS_SET_LOCK > 0)
552 /*!
553 * brief Set SNVS HP Set locks.
554 *
555 * param base SNVS peripheral base address
556 *
557 */
SNVS_HP_SetLocks(SNVS_Type * base)558 void SNVS_HP_SetLocks(SNVS_Type *base)
559 {
560 uint32_t sec_config = ((OCOTP_CTRL->HW_OCOTP_OTFAD_CFG3 & OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_MASK) >>
561 OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_SHIFT);
562
563 if (sec_config == SEC_CONFIG_OPEN)
564 {
565 /* Enable non-secure SW access */
566 base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN(1);
567 }
568
569 /* Set LP Software Reset Disable lock and ZMK Write Soft Lock */
570 base->HPCOMR |= SNVS_HPCOMR_LP_SWR_DIS(1);
571 base->HPLR |= SNVS_HPLR_ZMK_WSL(1);
572 }
573 #endif /* FSL_FEATURE_SNVS_HAS_SET_LOCK */
574