Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:48

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (c) 2016 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
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     /* Clear current status register */
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     /* Clear current status register */
0081     RTC_ClearSCCR(rtc, 0x3F);
0082 
0083     /* Switch off all RTC interrupts */
0084     RTC_DisableIt(rtc, 0x1F);
0085 
0086     /* Install RTC interrupt handler */
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             /* Enable fast startup via RTC alarm */
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 }