#include <tinyara/config.h>
#include <tinyara/arch.h>
-
#include <tinyara/irq.h>
-#include <tinyara/rtc.h>
-#include <arch/board/board.h>
-#include <arch/chip/chip_types.h>
-#include <chip.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
-#include "chip.h"
#include "up_arch.h"
-#include "s5j_rtc.h"
-#include <tinyara/kmalloc.h>
+#include "s5j_rtc.h"
#ifdef CONFIG_RTC
-
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/***************************************************************************
- * This is the private type for the RTC state. It must be cast compatible
- * with struct rtc_lowerhalf_s.
- ***************************************************************************/
-#ifdef CONFIG_RTC_DRIVER
-struct s5j_rtc_lowerhalf_s {
- FAR const struct rtc_ops_s *ops;
-
- /* Data following is private to this driver and not visible outside of
- * this file.
- */
-
- FAR struct s5j_rtc_lowerhalf_s *next;
- uint32_t irqno;
- uintptr_t base;
-};
-#endif
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-/* Prototypes for static methods in struct rtc_ops_s */
-
-#ifdef CONFIG_RTC_DRIVER
-static int s5j_rtc_rdtime(FAR struct rtc_lowerhalf_s *lower, FAR struct rtc_time *rtctime);
-static int s5j_rtc_settime(FAR struct rtc_lowerhalf_s *lower, FAR const struct rtc_time *rtctime);
-#endif
-
-#ifdef CONFIG_RTC_ALARM
-
-static int s5j_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower, FAR struct rtc_time *almtime);
-static int s5j_rtc_setalarm(FAR struct rtc_lowerhalf_s *lower, FAR const struct rtc_time *rtctime);
-static int s5j_rtc_aiealarm(FAR struct rtc_lowerhalf_s *lower, bool enable);
+#if !defined(CONFIG_RTC_DATETIME)
+#error "S5J does not support other than CONFIG_RTC_DATETIME."
#endif
-#ifdef CONFIG_RTC_PERIODIC
-static int s5j_rtc_set_tick_period(FAR struct rtc_lowerhalf_s *lower, FAR unsigned long irqpfreq);
-static int s5j_rtc_enable_tickirq(FAR struct rtc_lowerhalf_s *lower, bool enable);
-#endif
/****************************************************************************
* Private Data
****************************************************************************/
-
-#ifdef CONFIG_RTC_DRIVER
-static const struct rtc_ops_s g_rtc_ops = {
- .rdtime = s5j_rtc_rdtime,
- .settime = s5j_rtc_settime,
-#ifdef CONFIG_RTC_ALARM
- .almread = s5j_rtc_rdalarm,
- .almset = s5j_rtc_setalarm,
-#endif
-#ifdef CONFIG_RTC_PERIODIC
- .irqpread = NULL,
- .irqpset = s5j_rtc_set_tick_period,
-#endif
-#ifdef CONFIG_RTC_ALARM
- .aie = s5j_rtc_aiealarm,
-#endif
-#ifdef CONFIG_RTC_ONESEC
- .uie = NULL,
-#endif
-#ifdef CONFIG_RTC_PERIODIC
- .pie = s5j_rtc_enable_tickirq,
-#endif
-#ifdef CONFIG_RTC_EPOCHYEAR
- .rdepoch = NULL,
- .setepoch = NULL,
-#endif
#ifdef CONFIG_RTC_ALARM
- .rdwkalm = NULL,
- .setwkalm = NULL,
+/* Callback to use when the alarm expires */
+static alarmcb_t g_alarmcb;
#endif
-#ifdef CONFIG_RTC_IOCTL
- .ioctl = NULL,
-#endif
-};
-static struct rtc_lowerhalf_s g_rtc_lowerhalf = {
- .ops = &g_rtc_ops,
-};
-
-#endif
/****************************************************************************
* Public Data
****************************************************************************/
-
+/* g_rtc_enabled is set true after the RTC has successfully initialized */
volatile bool g_rtc_enabled = false;
/****************************************************************************
- * Private Functions
+ * Private Types
****************************************************************************/
+struct rtc_regvals_s
+{
+ uint8_t bcdsec;
+ uint8_t bcdmin;
+ uint8_t bcdhour;
+ uint8_t bcdday;
+#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
+ uint8_t bcddayweek;
+#endif
+ uint8_t bcdmon;
+ uint16_t bcdyear;
+};
/****************************************************************************
- * Name: rtc_bin2bcd
- *
- * Description:
- * Converts binary time format into bcd
- *
- * Input Parameters:
- * value - binary time value
- *
- * Returned Value:
- * BCD converted value
- *
+ * Private Functions
****************************************************************************/
static uint32_t rtc_bin2bcd(int value)
{
- uint32_t hundred = 0;
- uint32_t ten = 0;
+ uint32_t hundreds, tens;
+
+ hundreds = tens = 0;
while (value >= 100) {
- hundred++;
+ hundreds++;
value -= 100;
}
while (value >= 10) {
- ten++;
+ tens++;
value -= 10;
}
- return (hundred << 8) | (ten << 4) | value;
+ return (hundreds << 8) | (tens << 4) | value;
}
-/****************************************************************************
- * Name: rtc_bcd2bin
- *
- * Description:
- * Converts BCD time format into binary
- *
- * Input Parameters:
- * value - BCD value
- *
- * Returned Value:
- * binary converted value
- *
- ****************************************************************************/
static int rtc_bcd2bin(uint32_t value)
{
uint32_t tens = ((value >> 4) & 0xf) * 10;
- uint32_t hundred = ((value >> 8) & 0xf) * 100;
- return (int)(hundred + tens + (value & 0x0f));
+ uint32_t hundreds = ((value >> 8) & 0xf) * 100;
+ return (int)(hundreds + tens + (value & 0xf));
}
-/****************************************************************************
- * Name: __isr_rtc_tick
- *
- * Description:
- * RTC TICK ISR
- ****************************************************************************/
-void __isr_rtc_tick(void)
+static void rtc_breakout(FAR const struct tm *tm,
+ FAR struct rtc_regvals_s *regvals)
{
- lldbg("%s\n", __func__);
- HW_REG32(S5J_RTC_BASE, INTP) = RTC_INTP_TIC_MASK;
+ regvals->bcdsec = rtc_bin2bcd(tm->tm_sec);
+ regvals->bcdmin = rtc_bin2bcd(tm->tm_min);
+ regvals->bcdhour = rtc_bin2bcd(tm->tm_hour);
+ regvals->bcdday = rtc_bin2bcd(tm->tm_mday);
+#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
+ regvals->bcddayweek = rtc_bin2bcd(tm->tm_wday + 1);
+#endif
+ regvals->bcdmon = rtc_bin2bcd(tm->tm_mon + 1);
+ regvals->bcdyear = rtc_bin2bcd(tm->tm_year);
}
-/****************************************************************************
- * Name: __isr_rtc_alarm
- *
- * Description:
- * RTC ALARM ISR
- ****************************************************************************/
-void __isr_rtc_alarm(void)
+static void rtc_wprunlock(void)
{
- lldbg("%s\n", __func__);
- HW_REG32(S5J_RTC_BASE, INTP) = RTC_INTP_ALM_MASK;
+ modifyreg32(S5J_RTC_RTCCON, 0, RTC_RTCCON_CTLEN_ENABLE);
}
-/****************************************************************************
- * Name: s5j_gettime
- *
- * Description:
- * HW level get current time function call
- *
- * Input Parameters:
- * base - base address on RTC IP SFRs
- * t - pointer on tm structure where current time values will be stored
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-int s5j_gettime(uintptr_t base, struct tm *t)
+static void rtc_wprlock(void)
{
- uint32_t sec, min, hour, mday, mon, year;
- irqstate_t flags;
-#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
- uint32_t wday;
-#endif
- flags = irqsave();
-
- do {
- sec = getreg32(base + BCDSEC);
- min = getreg32(base + BCDMIN);
- hour = getreg32(base + BCDHOUR);
- mday = getreg32(base + BCDDAY);
- mon = getreg32(base + BCDMON);
- year = getreg32(base + BCDYEAR);
-#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
- wday = getreg32(base + BCDDAYWEEK);
-#endif
- } while (sec != getreg32(base + BCDSEC));
+ modifyreg32(S5J_RTC_RTCCON, RTC_RTCCON_CTLEN_ENABLE, 0);
+}
- irqrestore(flags);
+#if defined(CONFIG_RTC_ALARM)
+static int rtc_alarm_handler(int irq, void *context, FAR void *arg)
+{
+ if (getreg32(S5J_RTC_INTP) & RTC_INTP_ALARM) {
+ /* Clear pending flags */
+ putreg32(RTC_INTP_ALARM, S5J_RTC_INTP);
- t->tm_sec = rtc_bcd2bin(sec);
- t->tm_min = rtc_bcd2bin(min);
- t->tm_hour = rtc_bcd2bin(hour);
- t->tm_mday = rtc_bcd2bin(mday);
- t->tm_mon = rtc_bcd2bin(mon) - 1; /* range 0-11, need to -1 */
- t->tm_year = rtc_bcd2bin(year);
+ /* Disable alarm */
+ modifyreg32(S5J_RTC_RTCALM, RTC_RTCALM_ALMEN_MASK,
+ RTC_RTCALM_ALMEN_DISABLE);
-#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
- t->tm_wday = rtc_bcd2bin(wday);
-#endif
+ /* Alarm callback */
+ g_alarmcb();
+ g_alarmcb = NULL;
+ }
return OK;
}
+#endif
/****************************************************************************
- * Name: s5j_settime
+ * Public Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: up_rtc_getdatetime
*
* Description:
- * HW level set current time function call
+ * Get the current date and time from the date/time RTC. This interface
+ * is only supported by the date/time RTC hardware implementation.
+ * It is used to replace the system timer. It is only used by the RTOS
+ * during initialization to set up the system time when CONFIG_RTC and
+ * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not).
+ *
+ * NOTE: Some date/time RTC hardware is capability of sub-second accuracy.
+ * That sub-second accuracy is lost in this interface. However, since the
+ * system time is reinitialized on each power-up/reset, there will be no
+ * timing inaccuracy in the long run.
*
* Input Parameters:
- * base - base address on RTC IP SFRs
- * t - pointer on tm structure with values to set
+ * tp - The location to return the high resolution time value.
*
* Returned Value:
- * OK
+ * Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
-int s5j_settime(uintptr_t base, struct tm *t)
+int up_rtc_getdatetime(FAR struct tm *tp)
{
- uint32_t sec;
- uint32_t min;
- uint32_t hour;
- uint32_t mday;
- uint32_t mon;
- uint32_t year;
irqstate_t flags;
-#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
- uint32_t wday;
-#endif
+ struct rtc_regvals_s regvals;
flags = irqsave();
- sec = rtc_bin2bcd(t->tm_sec);
- min = rtc_bin2bcd(t->tm_min);
- hour = rtc_bin2bcd(t->tm_hour);
- mday = rtc_bin2bcd(t->tm_mday);
- mon = rtc_bin2bcd(t->tm_mon);
- year = rtc_bin2bcd(t->tm_year);
+ /* read bcd counters */
+ do {
+ regvals.bcdsec = getreg32(S5J_RTC_BCDSEC);
+ regvals.bcdmin = getreg32(S5J_RTC_BCDMIN);
+ regvals.bcdhour = getreg32(S5J_RTC_BCDHOUR);
+ regvals.bcdday = getreg32(S5J_RTC_BCDDAY);
#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
- wday = rtc_bin2bcd(t->tm_wday);
+ regvals.bcddayweek = getreg32(S5J_RTC_BCDDAYWEEK);
#endif
+ regvals.bcdmon = getreg32(S5J_RTC_BCDMON);
+ regvals.bcdyear = getreg32(S5J_RTC_BCDYEAR);
+ } while (regvals.bcdsec != getreg32(S5J_RTC_BCDSEC));
- putreg32(sec, base + BCDSEC);
- putreg32(min, base + BCDMIN);
- putreg32(hour, base + BCDHOUR);
- putreg32(mday, base + BCDDAY);
- putreg32(mon, base + BCDMON);
- putreg32(year, base + BCDYEAR);
+ irqrestore(flags);
+
+ tp->tm_sec = rtc_bcd2bin(regvals.bcdsec);
+ tp->tm_min = rtc_bcd2bin(regvals.bcdmin);
+ tp->tm_hour = rtc_bcd2bin(regvals.bcdhour);
+ tp->tm_mday = rtc_bcd2bin(regvals.bcdday);
#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
- putreg32(wday, base + BCDDAYWEEK);
+ tp->tm_wday = rtc_bcd2bin(regvals.bcddayweek) - 1;
#endif
-
- irqrestore(flags);
+ tp->tm_mon = rtc_bcd2bin(regvals.bcdmon) - 1;
+ tp->tm_year = rtc_bcd2bin(regvals.bcdyear);
return OK;
}
-#ifdef CONFIG_RTC_ALARM
-
/****************************************************************************
- * Name: s5j_getalarm
+ * Name: up_rtc_setdatetime
*
* Description:
- * HW level get alarm function call
+ * Set the RTC to the provided time. RTC implementations which provide
+ * up_rtc_getdatetime() (CONFIG_RTC_DATETIME is selected) should provide
+ * this function.
*
* Input Parameters:
- * base - base address on RTC IP SFRs
- * t - pointer on tm structure where alarm values will be stored
+ * tp - the time to use
*
* Returned Value:
- * OK
+ * Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
-static int s5j_getalarm(uintptr_t base, struct tm *t)
+int up_rtc_setdatetime(FAR struct tm *tm)
{
- uint32_t sec;
- uint32_t min;
- uint32_t hour;
- uint32_t mday;
- uint32_t mon;
- uint32_t year;
irqstate_t flags;
- flags = irqsave();
-
- do {
- sec = getreg32(base + ALMSEC);
- min = getreg32(base + ALMMIN);
- hour = getreg32(base + ALMHOUR);
- mday = getreg32(base + ALMDAY);
- mon = getreg32(base + ALMMON);
- year = getreg32(base + ALMYEAR);
- } while (sec != getreg32(base + ALMSEC));
+ struct rtc_regvals_s regvals;
- irqrestore(flags);
-
- t->tm_sec = rtc_bcd2bin(sec);
- t->tm_min = rtc_bcd2bin(min);
- t->tm_hour = rtc_bcd2bin(hour);
- t->tm_mday = rtc_bcd2bin(mday);
- t->tm_mon = rtc_bcd2bin(mon) - 1; /* range 0-11, need to -1 */
- t->tm_year = rtc_bcd2bin(year);
- return OK;
-}
-
-/****************************************************************************
- * Name: s5j_setalarm
- *
- * Description:
- * HW level set alarm function call
- *
- * Input Parameters:
- * base - base address on RTC IP SFRs
- * t - pointer on tm structure with values to set
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-static int s5j_setalarm(uintptr_t base, struct tm *t)
-{
- uint32_t sec;
- uint32_t min;
- uint32_t hour;
- uint32_t mday;
- uint32_t mon;
- uint32_t year;
- irqstate_t flags;
+ rtc_breakout(tm, ®vals);
flags = irqsave();
- sec = rtc_bin2bcd(t->tm_sec);
- min = rtc_bin2bcd(t->tm_min);
- hour = rtc_bin2bcd(t->tm_hour);
- mday = rtc_bin2bcd(t->tm_mday);
- mon = rtc_bin2bcd(t->tm_mon);
- year = rtc_bin2bcd(t->tm_year);
+ rtc_wprunlock();
- putreg32(sec, base + ALMSEC);
- putreg32(min, base + ALMMIN);
- putreg32(hour, base + ALMHOUR);
- putreg32(mday, base + ALMDAY);
- putreg32(mon, base + ALMMON);
- putreg32(year, base + ALMYEAR);
-
- irqrestore(flags);
-
- return OK;
-}
-
-#endif /* CONFIG_RTC_ALARM */
-
-/****************************************************************************
- * Name: s5j_rtc_rdtime
- *
- * Description:
- * Part of rtc_ops_s structure, used when CONFIG_RTC_ALARM is enabled.
- * Gets current time.
- *
- * Input Parameters:
- * lower - Lower half rtc structure pointer, corresponded to s5j_rtc
- * rtctime - pointer on rtc_time structure where current time
- * will be stored
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-#ifdef CONFIG_RTC_DRIVER
-static int s5j_rtc_rdtime(FAR struct rtc_lowerhalf_s *lower, FAR struct rtc_time *rtctime)
-{
- return s5j_gettime(S5J_RTC_BASE, (FAR struct tm *)rtctime);
-}
+ /* update BCD counters */
+ putreg32(regvals.bcdsec, S5J_RTC_BCDSEC);
+ putreg32(regvals.bcdmin, S5J_RTC_BCDMIN);
+ putreg32(regvals.bcdhour, S5J_RTC_BCDHOUR);
+ putreg32(regvals.bcdday, S5J_RTC_BCDDAY);
+#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED)
+ putreg32(regvals.bcddayweek, S5J_RTC_BCDDAYWEEK);
#endif
+ putreg32(regvals.bcdmon, S5J_RTC_BCDMON);
+ putreg32(regvals.bcdyear, S5J_RTC_BCDYEAR);
-#ifdef CONFIG_RTC_ALARM
-/****************************************************************************
- * Name: s5j_rtc_rdalarm
- *
- * Description:
- * Part of rtc_ops_s structure, used when CONFIG_RTC_ALARM is enabled.
- * Set ALARM time.
- *
- * Input Parameters:
- * lower - Lower half rtc structure pointer, corresponded to s5j_rtc
- * almtime - pointer on rtc_time structure where current alarm time
- * will be stored
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-static int s5j_rtc_rdalarm(FAR struct rtc_lowerhalf_s *lower, FAR struct rtc_time *almtime)
-{
- return s5j_getalarm(S5J_RTC_BASE, (FAR struct tm *)almtime);
-}
-
-/****************************************************************************
- * Name: s5j_rtc_setalarm
- *
- * Description:
- * Part of rtc_ops_s structure, used when CONFIG_RTC_ALARM is enabled.
- * Set ALARM time.
- *
- * Input Parameters:
- * lower - Lower half rtc structure pointer, corresponded to s5j_rtc
- * almtime - pointer on rtc_time structure with desired alarm time
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-static int s5j_rtc_setalarm(FAR struct rtc_lowerhalf_s *lower, FAR const struct rtc_time *almtime)
-{
- return s5j_setalarm(S5J_RTC_BASE, (FAR struct tm *)almtime);
-}
+ rtc_wprlock();
-/****************************************************************************
- * Name: s5j_rtc_aiealarm
- *
- * Description:
- * Part of rtc_ops_s structure, used when CONFIG_RTC_ALARM is enabled.
- * Enables ALARM interrupt.
- * RTC ISR __isr_rtc_alarm will be called.
- *
- * Input Parameters:
- * lower - Lower half rtc structure pointer, corresponded to s5j_rtc
- * enable - enable od disable alarm interrupt
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-static int s5j_rtc_aiealarm(FAR struct rtc_lowerhalf_s *lower, bool enable)
-{
- if (enable) {
- irq_attach(IRQ_TOP_RTC_ALARM, (xcpt_t) __isr_rtc_alarm, NULL);
- up_enable_irq(IRQ_TOP_RTC_ALARM);
-
- HW_REG32(S5J_RTC_BASE, RTCALM) |= RTC_GLB_ALM_EN; /* Enable Alarm Global */
- } else {
- HW_REG32(S5J_RTC_BASE, RTCALM) &= ~RTC_GLB_ALM_EN; /* Disable Alarm Global */
- }
- return OK;
-
- return OK;
-}
-#endif /* CONFIG_RTC_ALARM */
+ irqrestore(flags);
-#ifdef CONFIG_RTC_PERIODIC
-/****************************************************************************
- * Name: s5j_rtc_set_tick_period
- *
- * Description:
- * Part of rtc_ops_s structure, used when CONFIG_RTC_PERIODIC is enabled.
- * Defines period (not freq) of rtc interrupts with 1 sec resolution.
- *
- * Input Parameters:
- * lower - Lower half rtc structure pointer, corresponded to s5j_rtc
- * irqfreq - periodic interrupt period, in seconds
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-static int s5j_rtc_set_tick_period(FAR struct rtc_lowerhalf_s *lower, FAR unsigned long irqpfreq)
-{
- /* Set TICKCNT value for every 1 sec */
- /*
- * RTC Tick Interrupt Period
- * Period = (n + 1) /(Tick clock source frequency) second. (n = tick counter value
- * Refer to Tick Interrupt Resolution in S5JT200 UM
- */
- HW_REG32(S5J_RTC_BASE, TICCNT) = RTC_CLK_FREQ * irqpfreq + 1; /* in sec */
return OK;
}
/****************************************************************************
- * Name: s5j_rtc_enable_tickirq
+ * Name: up_rtc_settime
*
* Description:
- * Part of rtc_ops_s structure, used when CONFIG_RTC_PERIODIC is enabled.
- * Enables periodic interrupts, with defined period
- * by s5j_rtc_set_tick_period function call.
- * RTC ISR __isr_rtc_tick will be periodically called.
+ * Set the RTC to the provided time. All RTC implementations must be able
+ * to set their time based on a standard timespec.
*
* Input Parameters:
- * lower - Lower half rtc structure pointer, corresponded to s5j_rtc
- * enable - enable od disable periodic interrupt
+ * tp - the time to use
*
* Returned Value:
- * OK
+ * Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
-static int s5j_rtc_enable_tickirq(FAR struct rtc_lowerhalf_s *lower, bool enable)
+int up_rtc_settime(FAR const struct timespec *tp)
{
- if (enable) {
- irq_attach(IRQ_TOP_RTC_TIC, (xcpt_t) __isr_rtc_tick, NULL);
- up_enable_irq(IRQ_TOP_RTC_TIC);
+ struct tm t;
- HW_REG32(S5J_RTC_BASE, RTCCON) |= RTCCON_TICEN; /* Enable Tick Timer */
- } else {
- HW_REG32(S5J_RTC_BASE, RTCCON) &= ~RTCCON_TICEN; /* disable Tick Timer */
- }
- return OK;
-}
-#endif
+ /* convert timepsec to tm */
+ gmtime_r(&tp->tv_sec, &t);
-/****************************************************************************
- * Name: s5j_rtc_settime
- *
- * Description:
- * Initialize the hardware RTC per the selected configuration.
- * This function is called once during the OS initialization sequence
- *
- * Input Parameters:
- * lower - Lower half rtc structure pointer, corresponded to s5j_rtc
- * rtctime - pointer on rtc_time structure with values to set
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-#ifdef CONFIG_RTC_DRIVER
-static int s5j_rtc_settime(FAR struct rtc_lowerhalf_s *lower, FAR const struct rtc_time *rtctime)
-{
- return s5j_settime(S5J_RTC_BASE, (FAR struct tm *)rtctime);
+ return up_rtc_setdatetime(&t);
}
-#endif
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
+#ifdef CONFIG_RTC_ALARM
/****************************************************************************
- * Name: up_rtc_initialize
+ * Name: s5j_rtc_setalarm
*
* Description:
- * Initialize the hardware RTC per the selected configuration.
- * This function is called once during the OS initialization sequence.
+ * Set up an alarm
*
* Input Parameters:
- * None
+ * tp - the time to set the alarm
+ * callback - the function to call when the alarm expires
*
* Returned Value:
- * OK
+ * Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
-int s5j_rtc_initialize(void)
+int s5j_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback)
{
- irqstate_t flags;
struct tm t;
+ struct rtc_regvals_s regvals;
+ irqstate_t flags;
- /* No clocking setup need be performed. The Real-time Clock is continuously clocked
- * at 32768 Hz (SCLK). The Power Management Controller has no effect on RTC behavior.
- */
-
- flags = irqsave();
-
- /* Set RTC input clock to external XTAL oscillator (32768HZ) explicily*/
- HW_REG32(0x800A0000, 0x554) = 0x1;
-
- /* Reset RTC and Tick timer. */
- HW_REG32(S5J_RTC_BASE, RTCCON) = 0x0;
-
- /* Enable RTC counter, Tick clock 32768, Tick Timer enable */
- HW_REG32(S5J_RTC_BASE, RTCCON) |= RTCCON_CTLEN | RTCCON_TICCKSEL(clk_32768HZ);
+ /* convert timepsec to tm */
+ gmtime_r(&tp->tv_sec, &t);
- t.tm_sec = 0;
- t.tm_min = 0;
- t.tm_hour = 0;
- t.tm_mday = CONFIG_START_DAY;
- t.tm_mon = CONFIG_START_MONTH;
- t.tm_year = CONFIG_START_YEAR - CONFIG_RTC_BASE_YEAR;
+ rtc_breakout(&t, ®vals);
- s5j_settime(S5J_RTC_BASE, &t);
+ flags = irqsave();
-#ifdef CONFIG_RTC_ALARM
+ if (g_alarmcb != NULL) {
+ irqrestore(flags);
+ return -EBUSY;
+ }
- irq_attach(IRQ_TOP_RTC_ALARM, (xcpt_t) __isr_rtc_alarm, NULL);
+ /* Set the alarm */
+ putreg32(regvals.bcdsec, S5J_RTC_ALMSEC);
+ putreg32(regvals.bcdmin, S5J_RTC_ALMMIN);
+ putreg32(regvals.bcdhour, S5J_RTC_ALMHOUR);
+ putreg32(regvals.bcdday, S5J_RTC_ALMDAY);
+ putreg32(regvals.bcdmon, S5J_RTC_ALMMON);
+ putreg32(regvals.bcdyear, S5J_RTC_ALMYEAR);
+
+ /* Enable RTC alarm */
+ putreg32(RTC_RTCALM_ALMEN_ENABLE | RTC_RTCALM_YEAREN_ENABLE |
+ RTC_RTCALM_MONEN_ENABLE | RTC_RTCALM_DAYEN_ENABLE |
+ RTC_RTCALM_HOUREN_ENABLE | RTC_RTCALM_MINEN_ENABLE |
+ RTC_RTCALM_SECEN_ENABLE,
+ S5J_RTC_RTCALM);
+
+ /* save the callback function pointer */
+ g_alarmcb = callback;
+ irq_attach(IRQ_TOP_RTC_ALARM, rtc_alarm_handler, NULL);
up_enable_irq(IRQ_TOP_RTC_ALARM);
- /* Set Alarm after 1 min */
- t.tm_sec = 0;
- t.tm_min = 0;
- t.tm_hour = 0;
- t.tm_mday = CONFIG_START_DAY;
- t.tm_mon = CONFIG_START_MONTH;
- t.tm_year = CONFIG_START_YEAR - CONFIG_RTC_BASE_YEAR;
- s5j_setalarm(S5J_RTC_BASE, &t);
-
- HW_REG32(S5J_RTC_BASE, RTCALM) = RTC_YEAR_ALM_EN | RTC_MONTH_ALM_EN | RTC_DAY_ALM_EN | RTC_HOUR_ALM_EN | RTC_MIN_ALM_EN | RTC_SEC_ALM_EN;
-
-#endif
-
irqrestore(flags);
return OK;
}
/****************************************************************************
- * Name: up_rtc_getdatetime
+ * Name: s5j_rtc_cancelalarm
*
* Description:
- * Get the current date and time from the date/time RTC. This interface
- * is only supported by the date/time RTC hardware implementation.
- * It is used to replace the system timer. It is only used by the RTOS during
- * initialization to set up the system time when CONFIG_RTC and CONFIG_RTC_DATETIME
- * are selected (and CONFIG_RTC_HIRES is not). Due to low resoluton of RTC,
- * subsecond values will be lost.
- *
- * Input Parameters:
- * tp - pointer on tm type structure where date/time will be saved
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-
-int up_rtc_getdatetime(FAR struct tm *tp)
-{
- return s5j_gettime(S5J_RTC_BASE, tp);
-}
-
-/****************************************************************************
- * Name: up_rtc_time
- *
- * Description:
- * Get the current time in seconds. This is similar to the standard time()
- * function. This interface is only required if the low-resolution RTC/counter
- * hardware implementation selected. It is only used by the RTOS during
- * initialization to set up the system time when CONFIG_RTC is set but neither
- * CONFIG_RTC_HIRES nor CONFIG_RTC_DATETIME are set.
+ * Cancel a pending alarm
*
* Input Parameters:
* None
*
* Returned Value:
- * time_t value in seconds
- *
- ****************************************************************************/
-
-#ifndef CONFIG_RTC_HIRES
-time_t up_rtc_time(void)
-{
- struct tm t;
-
- s5j_gettime(S5J_RTC_BASE, &t);
-
- return mktime(&t);
-}
-#endif
-
-/****************************************************************************
- * Name: up_rtc_gettime
- *
- * Description:
- * Returns current time value in timespec structure.
- * Exists when RTC_HIRES configuration is enabled.
- * nsec value is always 0 due to low actual resolution of RTC counter.
- *
- * Input Parameters:
- * tp - pointer on timespec structure where time value will be stored.
- *
- * Returned Value:
- * OK
+ * Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
-
-#ifdef CONFIG_RTC_HIRES
-int up_rtc_gettime(FAR struct timespec *tp)
+int s5j_rtc_cancelalarm(void)
{
- struct tm t;
+ if (g_alarmcb == NULL)
+ return -ENODATA;
- s5j_gettime(S5J_RTC_BASE, &t);
+ /* Disable alarm */
+ modifyreg32(S5J_RTC_RTCALM, RTC_RTCALM_ALMEN_MASK,
+ RTC_RTCALM_ALMEN_DISABLE);
- tp->tv_sec = mktime(&t);
- tp->tv_nsec = 0;
+ g_alarmcb = NULL;
return OK;
}
-#endif
+#endif /* CONFIG_RTC_ALARM */
/****************************************************************************
- * Name: up_rtc_settime
+ * Name: up_rtc_initialize
*
* Description:
- * Function called by OS to set RTC date/time value.
+ * Initialize the hardware RTC per the selected configuration. This
+ * function is called once during the OS initialization sequence.
*
* Input Parameters:
- * tp - pointer on timespec structure with desired value.
+ * None
*
* Returned Value:
- * OK
+ * Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
-
-int up_rtc_settime(FAR const struct timespec *tp)
+int up_rtc_initialize(void)
{
- FAR struct tm newtime;
+ /* Disable RTC Alarm */
+ putreg32(0, S5J_RTC_RTCALM);
- (void)gmtime_r(&tp->tv_sec, &newtime);
+ /* Clear interrupt pending (if any) */
+ putreg32(RTC_INTP_ALARM | RTC_INTP_TIMETIC0, S5J_RTC_INTP);
- return s5j_settime(S5J_RTC_BASE, &newtime);
+ rtc_wprunlock();
-}
+ /* Reset to all initial state */
+ modifyreg32(S5J_RTC_RTCCON,
+ RTC_RTCCON_TICCKSEL0_MASK | RTC_RTCCON_CLKRST_MASK |
+ RTC_RTCCON_CNTSEL_MASK | RTC_RTCCON_CLKSEL_MASK,
+ RTC_RTCCON_TICCKSEL0_32768HZ |
+ RTC_RTCCON_CLKRST_ENABLE |
+ RTC_RTCCON_CNTSEL_MERGE_BCDCNT |
+ RTC_RTCCON_CLKSEL_DIV32768);
-/****************************************************************************
- * Name: up_rtc_initialize
- *
- * Description:
- * Function called by OS to initialize RTC.
- * Initialyizes HW and sublmits lower half OPS structure.
- *
- * Input Parameters:
- * None
- *
- * Returned Value:
- * OK
- *
- ****************************************************************************/
-
-int up_rtc_initialize(void)
-{
-#ifdef CONFIG_S5J_RTC
- int ret;
- s5j_rtc_initialize();
- ret = rtc_initialize(0, &g_rtc_lowerhalf);
- if (ret < 0) {
- lldbg("Failed the RTC initialize. (%d)\n", ret);
- return ret;
- }
+ rtc_wprlock();
- /* Set RTC enable flag */
g_rtc_enabled = true;
-#else
- lldbg("no support Hardware RTC functions\n");
-#endif
+
return OK;
}
-
-#endif
+#endif /* CONFIG_RTC */
/****************************************************************************
* Included Files
****************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <tinyara/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+#define S5J_RTC_INTP 0x80100030
+#define S5J_RTC_RTCCON 0x80100040
+#define S5J_RTC_TICCNT0 0x80100044
+#define S5J_RTC_RTCALM 0x80100050
+#define S5J_RTC_ALMSEC 0x80100054
+#define S5J_RTC_ALMMIN 0x80100058
+#define S5J_RTC_ALMHOUR 0x8010005C
+#define S5J_RTC_ALMDAY 0x80100060
+#define S5J_RTC_ALMMON 0x80100064
+#define S5J_RTC_ALMYEAR 0x80100068
+#define S5J_RTC_BCDSEC 0x80100070
+#define S5J_RTC_BCDMIN 0x80100074
+#define S5J_RTC_BCDHOUR 0x80100078
+#define S5J_RTC_BCDDAY 0x8010007C
+#define S5J_RTC_BCDDAYWEEK 0x80100080
+#define S5J_RTC_BCDMON 0x80100084
+#define S5J_RTC_BCDYEAR 0x80100088
+#define S5J_RTC_CURTICCNT0 0x80100090
-/* Register definition for RTC */
-#define INTP 0x0030
-#define RTCCON 0x0040
-#define TICCNT 0x0044
-#define RTCALM 0x0050
-#define ALMSEC 0x0054
-#define ALMMIN 0x0058
-#define ALMHOUR 0x005C
-#define ALMDAY 0x0060
-#define ALMMON 0x0064
-#define ALMYEAR 0x0068
-#define BCDSEC 0x0070
-#define BCDMIN 0x0074
-#define BCDHOUR 0x0078
-#define BCDDAY 0x007C
-#define BCDDAYWEEK 0x0080
-#define BCDMON 0x0084
-#define BCDYEAR 0x0088
-#define CURTICCNT 0x0090
-
-#define RTC_GLB_ALM_EN (0x1 << 6)
-#define RTC_YEAR_ALM_EN (0x1 << 5)
-#define RTC_MONTH_ALM_EN (0x1 << 4)
-#define RTC_DAY_ALM_EN (0x1 << 3)
-#define RTC_HOUR_ALM_EN (0x1 << 2)
-#define RTC_MIN_ALM_EN (0x1 << 1)
-#define RTC_SEC_ALM_EN (0x1 << 0)
+/* S5J_RTC_INTP */
+#define RTC_INTP_ALARM (0x1 << 1)
+#define RTC_INTP_TIMETIC0 (0x1 << 0)
+/* S5J_RTC_RTCCON */
+#define RTC_RTCCON_CLKOUTEN (0x1 << 9)
+#define RTC_RTCCON_TICKEN0 (0x1 << 8)
+#define RTC_RTCCON_TICCKSEL0_MASK (0xf << 4)
+#define RTC_RTCCON_TICCKSEL0_32768HZ (0x0 << 4)
+#define RTC_RTCCON_TICCKSEL0_16384HZ (0x1 << 4)
+#define RTC_RTCCON_TICCKSEL0_8192HZ (0x2 << 4)
+#define RTC_RTCCON_TICCKSEL0_4096HZ (0x3 << 4)
+#define RTC_RTCCON_TICCKSEL0_2048HZ (0x4 << 4)
+#define RTC_RTCCON_TICCKSEL0_1024HZ (0x5 << 4)
+#define RTC_RTCCON_TICCKSEL0_512HZ (0x6 << 4)
+#define RTC_RTCCON_TICCKSEL0_256HZ (0x7 << 4)
+#define RTC_RTCCON_TICCKSEL0_128HZ (0x8 << 4)
+#define RTC_RTCCON_TICCKSEL0_64HZ (0x9 << 4)
+#define RTC_RTCCON_TICCKSEL0_32HZ (0xa << 4)
+#define RTC_RTCCON_TICCKSEL0_16HZ (0xb << 4)
+#define RTC_RTCCON_TICCKSEL0_8HZ (0xc << 4)
+#define RTC_RTCCON_TICCKSEL0_4HZ (0xd << 4)
+#define RTC_RTCCON_TICCKSEL0_2HZ (0xe << 4)
+#define RTC_RTCCON_TICCKSEL0_1HZ (0xf << 4)
+#define RTC_RTCCON_CLKRST_MASK (0x1 << 3)
+#define RTC_RTCCON_CLKRST_ENABLE (0x0 << 3)
+#define RTC_RTCCON_CLKRST_DISABLE (0x1 << 3)
+#define RTC_RTCCON_CNTSEL_MASK (0x1 << 2)
+#define RTC_RTCCON_CNTSEL_MERGE_BCDCNT (0x0 << 2)
+#define RTC_RTCCON_CNTSEL_RESERVED (0x1 << 2)
+#define RTC_RTCCON_CLKSEL_MASK (0x1 << 1)
+#define RTC_RTCCON_CLKSEL_DIV32768 (0x0 << 1)
+#define RTC_RTCCON_CLKSEL_RESERVED (0x1 << 1)
+#define RTC_RTCCON_CTLEN_MASK (0x1 << 0)
+#define RTC_RTCCON_CTLEN_DISABLE (0x0 << 0)
+#define RTC_RTCCON_CTLEN_ENABLE (0x1 << 0)
-#define RTCCON_CLKOUTEN (1 << 9)
-#define RTCCON_TICEN (1 << 8)
-#define RTCCON_TICCKSEL(x) ((x & 0xf) << 4)
-#define RTCCON_CLKSTOP (1 << 3)
-#define RTCCON_CTLEN (1 << 0)
+/* S5J_RTC_RTCALM */
+#define RTC_RTCALM_ALMEN_MASK (0x1 << 6)
+#define RTC_RTCALM_ALMEN_DISABLE (0x0 << 6)
+#define RTC_RTCALM_ALMEN_ENABLE (0x1 << 6)
+#define RTC_RTCALM_YEAREN_MASK (0x1 << 5)
+#define RTC_RTCALM_YEAREN_DISABLE (0x0 << 5)
+#define RTC_RTCALM_YEAREN_ENABLE (0x1 << 5)
+#define RTC_RTCALM_MONEN_MASK (0x1 << 4)
+#define RTC_RTCALM_MONEN_DISABLE (0x0 << 4)
+#define RTC_RTCALM_MONEN_ENABLE (0x1 << 4)
+#define RTC_RTCALM_DAYEN_MASK (0x1 << 3)
+#define RTC_RTCALM_DAYEN_DISABLE (0x0 << 3)
+#define RTC_RTCALM_DAYEN_ENABLE (0x1 << 3)
+#define RTC_RTCALM_HOUREN_MASK (0x1 << 2)
+#define RTC_RTCALM_HOUREN_DISABLE (0x0 << 2)
+#define RTC_RTCALM_HOUREN_ENABLE (0x1 << 2)
+#define RTC_RTCALM_MINEN_MASK (0x1 << 1)
+#define RTC_RTCALM_MINEN_DISABLE (0x0 << 1)
+#define RTC_RTCALM_MINEN_ENABLE (0x1 << 1)
+#define RTC_RTCALM_SECEN_MASK (0x1 << 0)
+#define RTC_RTCALM_SECEN_DISABLE (0x0 << 0)
+#define RTC_RTCALM_SECEN_ENABLE (0x1 << 0)
-#define RTC_CLK_FREQ 32768
-
-typedef enum t_ticcksel {
- clk_32768HZ = 0,
- clk_16384HZ,
- clk_8192HZ,
- clk_4096HZ,
- clk_2048HZ,
- clk_1024HZ,
- clk_512HZ,
- clk_256HZ,
- clk_128HZ,
- clk_64HZ,
- clk_32HZ,
- clk_16HZ,
- clk_8HZ,
- clk_4HZ,
- clk_2HZ,
- clk_1HZ,
-} d_ticcksel;
+#ifndef __ASSEMBLY__
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
-#define RTC_INTP_TIC_MASK (1 << 0)
-#define RTC_INTP_ALM_MASK (1 << 1)
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+/* The form of an alarm callback */
+typedef void (*alarmcb_t)(void);
/****************************************************************************
* Public Functions
****************************************************************************/
+/****************************************************************************
+ * Name: s5j_rtc_lowerhalf
+ *
+ * Description:
+ * Instantiate the RTC lower half driver for the S5J.
+ * General usage:
+ *
+ * #include <tinyara/rtc.h>
+ * #include "s5j_rtc.h"
+ *
+ * struct rtc_lowerhalf_s *lower;
+ * lower = s5j_rtc_lowerhalf();
+ * rtc_initialize(0, lower);
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * On success, a non-NULL RTC lower interface is returned. NULL is
+ * returned on any failure.
+ *
+ ****************************************************************************/
+#ifdef CONFIG_RTC_DRIVER
+FAR struct rtc_lowerhalf_s *s5j_rtc_lowerhalf(void);
+#endif /* CONFIG_RTC_DRIVER */
-
-#ifdef __cplusplus
+#undef EXTERN
+#if defined(__cplusplus)
}
#endif
-#endif /* __ARCH_ARM_SRC_S5J_S5J_RTC_H */
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_ARM_SRC_S5J_S5J_RTC_H */
--- /dev/null
+/****************************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * arch/arm/src/s5j/s5j_rtc.c
+ *
+ * Copyright (C) 2009-2010, 2014-2015 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <tinyara/arch.h>
+#include <tinyara/rtc.h>
+
+#include "up_arch.h"
+
+#include "s5j_rtc.h"
+
+#ifdef CONFIG_RTC_DRIVER
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+#ifdef CONFIG_RTC_ALARM
+struct s5j_cbinfo_s
+{
+ volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */
+ volatile FAR void *priv; /* Private arg passed to callback */
+};
+#endif /* CONFIG_RTC_ALARM */
+
+struct s5j_lowerhalf_s
+{
+ /*
+ * This is the contained reference to the read-only, lower-half
+ * operations vtable (which may lie in FLASH or ROM
+ */
+ FAR const struct rtc_ops_s *ops;
+
+#ifdef CONFIG_RTC_ALARM
+ /*
+ * Data following is private to this driver and not visible
+ * outside of this file.
+ */
+ struct s5j_cbinfo_s cbinfo;
+#endif /* CONFIG_RTC_ALARM */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: s5j_alarm_callback
+ *
+ * Description:
+ * This is the function that is called from the RTC driver when the alarm
+ * goes off. It just invokes the upper half drivers callback.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+#ifdef CONFIG_RTC_ALARM
+static struct s5j_lowerhalf_s g_rtc_lowerhalf;
+static void s5j_alarm_callback(void)
+{
+ FAR struct s5j_cbinfo_s *cbinfo = &g_rtc_lowerhalf.cbinfo;
+
+ /*
+ * Sample and clear the callback information to minimize the window
+ * in time in which race conditions can occur.
+ */
+ rtc_alarm_callback_t cb = (rtc_alarm_callback_t)cbinfo->cb;
+ FAR void *arg = (FAR void *)cbinfo->priv;
+
+ cbinfo->cb = NULL;
+ cbinfo->priv = NULL;
+
+ /* Perform the callback */
+ if (cb != NULL) {
+ cb(arg, 0);
+ }
+}
+#endif /* CONFIG_RTC_ALARM */
+
+static int rtc_rdtime(FAR struct rtc_lowerhalf_s *lower,
+ FAR struct rtc_time *rtctime)
+{
+ return up_rtc_getdatetime((FAR struct tm *)rtctime);
+}
+
+static int rtc_settime(FAR struct rtc_lowerhalf_s *lower,
+ FAR const struct rtc_time *rtctime)
+{
+ return up_rtc_setdatetime((FAR struct tm *)rtctime);
+}
+
+#ifdef CONFIG_RTC_ALARM
+static int rtc_setalarm(FAR struct rtc_lowerhalf_s *lower,
+ FAR const struct lower_setalarm_s *alarminfo)
+{
+ FAR struct s5j_lowerhalf_s *priv;
+ FAR struct s5j_cbinfo_s *cbinfo;
+ int ret = -EINVAL;
+
+ DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0);
+ priv = (FAR struct s5j_lowerhalf_s *)lower;
+
+ if (alarminfo->id == 0) {
+ struct timespec ts;
+
+ /* Convert the RTC time to a timespec (1 second accuracy) */
+ ts.tv_sec = mktime((FAR struct tm *)&alarminfo->time);
+ ts.tv_nsec = 0;
+
+ /* Remember the callback information */
+ cbinfo = &priv->cbinfo;
+ cbinfo->cb = alarminfo->cb;
+ cbinfo->priv = alarminfo->priv;
+
+ /* And set the alarm */
+ ret = s5j_rtc_setalarm(&ts, s5j_alarm_callback);
+ if (ret < 0) {
+ cbinfo->cb = NULL;
+ cbinfo->priv = NULL;
+ }
+ }
+
+ return ret;
+}
+
+static int rtc_setrelative(FAR struct rtc_lowerhalf_s *lower,
+ FAR const struct lower_setrelative_s *alarminfo)
+{
+ FAR struct s5j_lowerhalf_s *priv;
+ FAR struct s5j_cbinfo_s *cbinfo;
+ struct tm time;
+ FAR struct timespec ts;
+ int ret = -EINVAL;
+
+ DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0);
+ priv = (FAR struct s5j_lowerhalf_s *)lower;
+
+ if (alarminfo->id == 0 && alarminfo->reltime > 0) {
+ /*
+ * Disable preemption while we do this so that we don't have
+ * to worry about being suspended and working on an old time.
+ */
+ sched_lock();
+
+ /* Get the current time in seconds */
+
+ ret = up_rtc_getdatetime(&time);
+ if (ret < 0) {
+ sched_unlock();
+ return ret;
+ }
+
+ ts.tv_sec = mktime(&time);
+ ts.tv_nsec = 0;
+
+ /*
+ * Add the seconds offset. Add one to the number of seconds
+ * because we are unsure of the phase of the timer.
+ */
+ ts.tv_sec += (alarminfo->reltime + 1);
+
+ /* Remember the callback information */
+ cbinfo = &priv->cbinfo;
+ cbinfo->cb = alarminfo->cb;
+ cbinfo->priv = alarminfo->priv;
+
+ /* And set the alarm */
+ ret = s5j_rtc_setalarm(&ts, s5j_alarm_callback);
+ if (ret < 0) {
+ cbinfo->cb = NULL;
+ cbinfo->priv = NULL;
+ }
+
+ sched_unlock();
+ }
+
+ return ret;
+}
+
+static int rtc_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid)
+{
+ FAR struct s5j_lowerhalf_s *priv;
+ FAR struct s5j_cbinfo_s *cbinfo;
+
+ DEBUGASSERT(lower != NULL);
+ DEBUGASSERT(alarmid == 0);
+ priv = (FAR struct s5j_lowerhalf_s *)lower;
+
+ /* Nullify callback information to reduce window for race conditions */
+ cbinfo = &priv->cbinfo;
+ cbinfo->cb = NULL;
+ cbinfo->priv = NULL;
+
+ /* Then, cancel the alarm */
+ return s5j_rtc_cancelalarm();
+}
+#endif /* CONFIG_RTC_ALARM */
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+static const struct rtc_ops_s g_rtc_ops = {
+ .rdtime = rtc_rdtime,
+ .settime = rtc_settime,
+#ifdef CONFIG_RTC_ALARM
+ .setalarm = rtc_setalarm,
+ .setrelative = rtc_setrelative,
+ .cancelalarm = rtc_cancelalarm,
+#endif
+#ifdef CONFIG_RTC_IOCTL
+ .ioctl = NULL,
+#endif
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+ .destroy = NULL,
+#endif
+};
+
+static struct s5j_lowerhalf_s g_rtc_lowerhalf = {
+ .ops = &g_rtc_ops,
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: s5j_rtc_lowerhalf
+ *
+ * Description:
+ * Instantiate the RTC lower half driver for the S5J.
+ * General usage:
+ *
+ * #include <tinyara/rtc.h>
+ * #include "s5j_rtc.h"
+ *
+ * struct rtc_lowerhalf_s *lower;
+ * lower = s5j_rtc_lowerhalf();
+ * rtc_initialize(0, lower);
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * On success, a non-NULL RTC lower interface is returned. NULL is
+ * returned on any failure.
+ *
+ ****************************************************************************/
+FAR struct rtc_lowerhalf_s *s5j_rtc_lowerhalf(void)
+{
+ return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf;
+}
+#endif /* CONFIG_RTC_DRIVER */