File indexing completed on 2025-05-11 08:22:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <bsp.h>
0029 #include <bsp/power.h>
0030 #include <bsp/irq.h>
0031
0032 #include <libchip/chip.h>
0033
0034 #define ATSAM_ENABLE_ALARM_INTERRUPT RTC_IER_ALREN
0035
0036 static void set_rtc_alarm_interrupt(uint32_t interval)
0037 {
0038 Rtc *rtc = RTC;
0039 uint8_t hour;
0040 uint8_t minute;
0041 uint8_t second;
0042 uint32_t time;
0043
0044
0045 RTC_ClearSCCR(rtc, 0x3F);
0046
0047 RTC_GetTime(rtc, &hour, &minute, &second);
0048
0049 time = UINT32_C(3600) * hour + UINT32_C(60) * minute + second;
0050 time = (time + interval) % (UINT32_C(24) * 3600);
0051
0052 second = (uint8_t) (time % 60);
0053 minute = (uint8_t) ((time / 60) % 60);
0054 hour = (uint8_t) (time / 3600);
0055
0056 if (interval < 60) {
0057 RTC_SetTimeAlarm(rtc, NULL, NULL, &second);
0058 } else if (interval < 3600) {
0059 RTC_SetTimeAlarm(rtc, NULL, &minute, &second);
0060 } else {
0061 RTC_SetTimeAlarm(rtc, &hour, &minute, &second);
0062 }
0063
0064 RTC_EnableIt(rtc, ATSAM_ENABLE_ALARM_INTERRUPT);
0065 }
0066
0067 static void rtc_interrupt_handler(void *arg)
0068 {
0069 atsam_power_data_rtc_driver *rtc_data;
0070
0071 rtc_data = (atsam_power_data_rtc_driver *)arg;
0072 set_rtc_alarm_interrupt(rtc_data->interval);
0073 }
0074
0075 static void rtc_alarm_handler(void *arg)
0076 {
0077 Rtc *rtc = RTC;
0078 rtems_status_code sc;
0079
0080
0081 RTC_ClearSCCR(rtc, 0x3F);
0082
0083
0084 RTC_DisableIt(rtc, 0x1F);
0085
0086
0087 sc = rtems_interrupt_handler_install(RTC_IRQn,
0088 "RTC",
0089 RTEMS_INTERRUPT_UNIQUE,
0090 rtc_interrupt_handler,
0091 arg
0092 );
0093 assert(sc == RTEMS_SUCCESSFUL);
0094 }
0095
0096 static void set_time(void)
0097 {
0098 rtems_time_of_day tod;
0099 rtems_status_code sc;
0100
0101 atsam_rtc_get_time(&tod);
0102 sc = rtems_clock_set(&tod);
0103 assert(sc == RTEMS_SUCCESSFUL);
0104 }
0105
0106 void atsam_power_handler_rtc_driver(
0107 const atsam_power_control *control,
0108 atsam_power_state state
0109 )
0110 {
0111 atsam_power_data_rtc_driver *rtc_data;
0112 rtems_interrupt_level level;
0113 Rtc *rtc = RTC;
0114
0115 rtc_data = (atsam_power_data_rtc_driver *)control->data.arg;
0116
0117 switch (state) {
0118 case ATSAM_POWER_ON:
0119 RTC_DisableIt(rtc, ATSAM_ENABLE_ALARM_INTERRUPT);
0120 set_time();
0121 break;
0122 case ATSAM_POWER_OFF:
0123 set_rtc_alarm_interrupt(rtc_data->interval);
0124 break;
0125 case ATSAM_POWER_INIT:
0126
0127 rtems_interrupt_disable(level);
0128 PMC->PMC_FSMR |= PMC_FSMR_RTCAL;
0129 rtems_interrupt_enable(level);
0130
0131 rtc_alarm_handler(rtc_data);
0132 break;
0133 default:
0134 break;
0135 }
0136 }