forked from Imagelibrary/rtems
159 lines
4.2 KiB
C
159 lines
4.2 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* @ingroup RTEMSBSPsARMLPC32XX
|
|
*
|
|
* @brief RTC configuration.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2009, 2011 embedded brains GmbH & Co. KG
|
|
*
|
|
* 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 <libchip/rtc.h>
|
|
|
|
#include <bsp.h>
|
|
#include <bsp/lpc32xx.h>
|
|
#include <rtems/rtems/clockimpl.h>
|
|
|
|
#include <time.h>
|
|
|
|
#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
|
|
}
|
|
};
|