/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup RTEMSBSPsARMLPC32XX * * @brief RTC configuration. */ /* * Copyright (c) 2009-2011 embedded brains GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #define LPC32XX_RTC_COUNT 1U #define LPC32XX_RTC_COUNTER_DELTA 0xfffffffeU #define LPC32XX_RTC_KEY 0xb5c13f27U #define LPC32XX_RTC_CTRL_FORCE_ONSW (1U << 7) #define LPC32XX_RTC_CTRL_STOP (1U << 6) #define LPC32XX_RTC_CTRL_RESET (1U << 4) #define LPC32XX_RTC_CTRL_MATCH_1_ONSW (1U << 3) #define LPC32XX_RTC_CTRL_MATCH_0_ONSW (1U << 2) #define LPC32XX_RTC_CTRL_MATCH_1_INTR (1U << 1) #define LPC32XX_RTC_CTRL_MATCH_0_INTR (1U << 0) static void lpc32xx_rtc_set(uint32_t val) { unsigned i = lpc32xx_arm_clk() / LPC32XX_OSCILLATOR_RTC; lpc32xx.rtc.ctrl |= LPC32XX_RTC_CTRL_STOP; lpc32xx.rtc.ucount = val; lpc32xx.rtc.dcount = LPC32XX_RTC_COUNTER_DELTA - val; lpc32xx.rtc.ctrl &= ~LPC32XX_RTC_CTRL_STOP; /* It needs some time before we can read the values back */ while (i != 0) { __asm__ volatile ("nop"); --i; } } static void lpc32xx_rtc_reset(void) { lpc32xx.rtc.ctrl = LPC32XX_RTC_CTRL_RESET; lpc32xx.rtc.ctrl = 0; lpc32xx.rtc.key = LPC32XX_RTC_KEY; lpc32xx_rtc_set(0); } static void lpc32xx_rtc_initialize(int minor) { uint32_t up_first = 0; uint32_t up_second = 0; uint32_t down_first = 0; uint32_t down_second = 0; if (lpc32xx.rtc.key != LPC32XX_RTC_KEY) { lpc32xx_rtc_reset(); } do { up_first = lpc32xx.rtc.ucount; down_first = lpc32xx.rtc.dcount; up_second = lpc32xx.rtc.ucount; down_second = lpc32xx.rtc.dcount; } while (up_first != up_second || down_first != down_second); if (up_first + down_first != LPC32XX_RTC_COUNTER_DELTA) { lpc32xx_rtc_reset(); } } static int lpc32xx_rtc_get_time(int minor, rtems_time_of_day *tod) { struct timeval now = { .tv_sec = lpc32xx.rtc.ucount, .tv_usec = 0 }; struct tm time; gmtime_r(&now.tv_sec, &time); tod->year = time.tm_year + 1900; tod->month = time.tm_mon + 1; tod->day = time.tm_mday; tod->hour = time.tm_hour; tod->minute = time.tm_min; tod->second = time.tm_sec; tod->ticks = 0; return RTEMS_SUCCESSFUL; } static int lpc32xx_rtc_set_time(int minor, const rtems_time_of_day *tod) { lpc32xx_rtc_set(_TOD_To_seconds(tod)); return 0; } static bool lpc32xx_rtc_probe(int minor) { return true; } const rtc_fns lpc32xx_rtc_ops = { .deviceInitialize = lpc32xx_rtc_initialize, .deviceGetTime = lpc32xx_rtc_get_time, .deviceSetTime = lpc32xx_rtc_set_time }; size_t RTC_Count = LPC32XX_RTC_COUNT; rtc_tbl RTC_Table [LPC32XX_RTC_COUNT] = { { .sDeviceName = "/dev/rtc", .deviceType = RTC_CUSTOM, .pDeviceFns = &lpc32xx_rtc_ops, .deviceProbe = lpc32xx_rtc_probe, .pDeviceParams = NULL, .ulCtrlPort1 = 0, .ulDataPort = 0, .getRegister = NULL, .setRegister = NULL } };