s5j/rtc: rework rtc driver
authorHeesub Shin <heesub.shin@samsung.com>
Mon, 3 Apr 2017 00:16:45 +0000 (09:16 +0900)
committerHeesub Shin <heesub.shin@samsung.com>
Tue, 18 Apr 2017 03:02:05 +0000 (12:02 +0900)
This commit completely rewrites the RTC driver. Unnecessary code lines
were removed and overcall callflow were designed, following the
conventions at upstream.

As a result, overall binary footprint reduced, when CONFIG_RTC_ALARM=n:

    Before
       text    data     bss     dec filename
       1736       4       1    1741 s5j_rtc.o

    After
       text    data     bss     dec filename
       1248       0       1    1249 s5j_rtc.o
        108       4       0     112 s5j_rtc_lowerhalf.o

Change-Id: Ic641828546827cdff51f8bbf2ee05eb3f501ac88
Signed-off-by: Heesub Shin <heesub.shin@samsung.com>
apps/examples/testcase/le_tc/kernel/tc_clock.c
os/arch/arm/src/s5j/Kconfig
os/arch/arm/src/s5j/Make.defs
os/arch/arm/src/s5j/s5j_rtc.c
os/arch/arm/src/s5j/s5j_rtc.h
os/arch/arm/src/s5j/s5j_rtc_lowerhalf.c [new file with mode: 0644]

index 8b126cf..86a4c44 100644 (file)
@@ -40,6 +40,10 @@ extern struct timespec g_basetime;
 #define SEC_10  10
 #define NSEC_20 20
 
+#define START_YEAR     2017
+#define START_MONTH    4
+#define START_DAY      1
+
 /**
 * @fn                   :tc_clock_clock_initialize
 * @brief                :Initialize the time value to match the RTC
@@ -54,7 +58,7 @@ static void tc_clock_clock_initialize(void)
        g_basetime.tv_nsec = NSEC_20;
        time_t jdn = 0;
 
-       jdn = clock_calendar2utc(CONFIG_START_YEAR, CONFIG_START_MONTH, CONFIG_START_DAY);
+       jdn = clock_calendar2utc(START_YEAR, START_MONTH, START_DAY);
 
        clock_initialize();
 
index 760d472..5b299bf 100644 (file)
@@ -174,40 +174,6 @@ config S5J_WDT_DEFTIMEOUT
 
 endmenu
 
-menu "S5J RTC(Real Time Clock)"
-config S5J_RTC
-       bool "S5J RTC support"
-       default n
-       select RTC
-       select RTC_DRIVER
-       select RTC_DATETIME
-
-config START_YEAR
-       int "year"
-       default 2016
-       depends on S5J_RTC
-
-config START_MONTH
-       int "month"
-       default 8
-       depends on S5J_RTC
-
-config START_DAY
-       int "day"
-       default 11
-       depends on S5J_RTC
-
-config GREGORIAN_TIME
-       bool "S5J RTC for GREGORIAN TIME"
-       default n
-       depends on S5J_RTC
-
-config RTC_BASE_YEAR
-       int "Offset of year for S5JRTC(BASE + BCD)"
-       default 1900
-       depends on S5J_RTC
-endmenu #"S5J_RTC"
-
 menu "S5J ADC"
 config S5J_ADC
        bool "S5J ADC support"
index dd03a5f..a0d5d77 100644 (file)
@@ -189,6 +189,9 @@ endif
 
 ifeq ($(CONFIG_RTC),y)
 CHIP_CSRCS += s5j_rtc.c
+ifeq ($(CONFIG_RTC_DRIVER),y)
+CHIP_CSRCS += s5j_rtc_lowerhalf.c
+endif
 endif
 
 ifeq ($(CONFIG_S5J_MAILBOX),y)
index bde9e6d..361f6f0 100644 (file)
 
 #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, &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);
+       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, &regvals);
 
-       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 */
index 50d3793..7f8e5ca 100644 (file)
 /****************************************************************************
  * 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 */
diff --git a/os/arch/arm/src/s5j/s5j_rtc_lowerhalf.c b/os/arch/arm/src/s5j/s5j_rtc_lowerhalf.c
new file mode 100644 (file)
index 0000000..237abc8
--- /dev/null
@@ -0,0 +1,320 @@
+/****************************************************************************
+ *
+ * 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 */