feat: serial device interfacing
[lunaix-os.git] / lunaix-os / hal / rtc / mc146818a.c
index 98ea807c37e41053cf2b3eee49822e1520427f23..c36412a8d293aa2a2f55ab08db05db66a4cfee73 100644 (file)
@@ -11,6 +11,8 @@
  */
 
 #include <lunaix/isrm.h>
  */
 
 #include <lunaix/isrm.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/status.h>
 
 #include <hal/rtc/mc146818a.h>
 
 
 #include <hal/rtc/mc146818a.h>
 
 #define RTC_REG_C 0xC
 #define RTC_REG_D 0xD
 
 #define RTC_REG_C 0xC
 #define RTC_REG_D 0xD
 
+#define RTC_SET 0x80
+#define RTC_BIN (1 << 2)
+#define RTC_HOURFORM24 (1 << 1)
+
 #define RTC_BIN_ENCODED(reg) (reg & 0x04)
 #define RTC_24HRS_ENCODED(reg) (reg & 0x02)
 
 #define RTC_BIN_ENCODED(reg) (reg & 0x04)
 #define RTC_24HRS_ENCODED(reg) (reg & 0x02)
 
@@ -52,8 +58,7 @@ struct mc146818
 {
     struct hwrtc* rtc_context;
     u32_t rtc_iv;
 {
     struct hwrtc* rtc_context;
     u32_t rtc_iv;
-    int ticking;
-    void (*on_tick_cb)(const struct hwrtc*);
+    u32_t tick_counts;
 };
 
 #define rtc_state(data) ((struct mc146818*)(data))
 };
 
 #define rtc_state(data) ((struct mc146818*)(data))
@@ -72,28 +77,22 @@ rtc_write_reg(u8_t reg_selector, u8_t val)
     port_wrbyte(RTC_TARGET_PORT, val);
 }
 
     port_wrbyte(RTC_TARGET_PORT, val);
 }
 
-static u8_t
-bcd2dec(u8_t bcd)
-{
-    return ((bcd & 0xF0) >> 1) + ((bcd & 0xF0) >> 3) + (bcd & 0xf);
-}
-
 static void
 rtc_enable_timer()
 {
 static void
 rtc_enable_timer()
 {
-    u8_t regB = rtc_read_reg(RTC_REG_B | WITH_NMI_DISABLED);
-    rtc_write_reg(RTC_REG_B | WITH_NMI_DISABLED, regB | RTC_TIMER_ON);
+    u8_t regB = rtc_read_reg(RTC_REG_B);
+    rtc_write_reg(RTC_REG_B, regB | RTC_TIMER_ON);
 }
 
 static void
 rtc_disable_timer()
 {
 }
 
 static void
 rtc_disable_timer()
 {
-    u8_t regB = rtc_read_reg(RTC_REG_B | WITH_NMI_DISABLED);
-    rtc_write_reg(RTC_REG_B | WITH_NMI_DISABLED, regB & ~RTC_TIMER_ON);
+    u8_t regB = rtc_read_reg(RTC_REG_B);
+    rtc_write_reg(RTC_REG_B, regB & ~RTC_TIMER_ON);
 }
 
 static void
 }
 
 static void
-clock_walltime(struct hwrtc* rtc, datetime_t* datetime)
+rtc_getwalltime(struct hwrtc* rtc, datetime_t* datetime)
 {
     datetime_t current;
 
 {
     datetime_t current;
 
@@ -111,24 +110,26 @@ clock_walltime(struct hwrtc* rtc, datetime_t* datetime)
         datetime->second = rtc_read_reg(RTC_REG_SEC);
     } while (!datatime_eq(datetime, &current));
 
         datetime->second = rtc_read_reg(RTC_REG_SEC);
     } while (!datatime_eq(datetime, &current));
 
-    u8_t regbv = rtc_read_reg(RTC_REG_B);
+    datetime->year += RTC_CURRENT_CENTRY * 100;
+}
 
 
-    // Convert from bcd to binary when needed
-    if (!RTC_BIN_ENCODED(regbv)) {
-        datetime->year = bcd2dec(datetime->year);
-        datetime->month = bcd2dec(datetime->month);
-        datetime->day = bcd2dec(datetime->day);
-        datetime->hour = bcd2dec(datetime->hour);
-        datetime->minute = bcd2dec(datetime->minute);
-        datetime->second = bcd2dec(datetime->second);
-    }
+static void
+rtc_setwalltime(struct hwrtc* rtc, datetime_t* datetime)
+{
+    u8_t reg = rtc_read_reg(RTC_REG_B);
+    reg = reg & ~RTC_SET;
 
 
-    // To 24 hour format
-    if (!RTC_24HRS_ENCODED(regbv) && (datetime->hour >> 7)) {
-        datetime->hour = 12 + (datetime->hour & 0x80);
-    }
+    rtc_write_reg(RTC_REG_B, reg | RTC_SET);
 
 
-    datetime->year += RTC_CURRENT_CENTRY * 100;
+    rtc_write_reg(RTC_REG_YRS, datetime->year - RTC_CURRENT_CENTRY * 100);
+    rtc_write_reg(RTC_REG_MTH, datetime->month);
+    rtc_write_reg(RTC_REG_DAY, datetime->day);
+    rtc_write_reg(RTC_REG_WDY, datetime->weekday);
+    rtc_write_reg(RTC_REG_HRS, datetime->hour);
+    rtc_write_reg(RTC_REG_MIN, datetime->minute);
+    rtc_write_reg(RTC_REG_SEC, datetime->second);
+
+    rtc_write_reg(RTC_REG_B, reg & ~RTC_SET);
 }
 
 static int
 }
 
 static int
@@ -142,78 +143,81 @@ mc146818_check_support(struct hwrtc* rtc)
 }
 
 static void
 }
 
 static void
-rtc_init(struct hwrtc* rtc)
+__rtc_tick(const isr_param* param)
 {
 {
-    u8_t regA = rtc_read_reg(RTC_REG_A | WITH_NMI_DISABLED);
-    regA = (regA & ~0x7f) | RTC_FREQUENCY_1024HZ | RTC_DIVIDER_33KHZ;
-    rtc_write_reg(RTC_REG_A | WITH_NMI_DISABLED, regA);
+    struct mc146818* state = (struct mc146818*)isrm_get_payload(param);
 
 
-    rtc_state(rtc->data)->rtc_context = rtc;
+    state->tick_counts++;
 
 
-    // Make sure the rtc timer is disabled by default
-    rtc_disable_timer();
+    (void)rtc_read_reg(RTC_REG_C);
 }
 
 }
 
-static struct mc146818 rtc_state = { .ticking = 0 };
-
 static void
 static void
-__rtc_tick(const isr_param* param)
+rtc_set_mask(struct hwrtc* rtc)
 {
 {
-    rtc_state.on_tick_cb(rtc_state.rtc_context);
-
-    (void)rtc_read_reg(RTC_REG_C);
+    rtc->state = RTC_STATE_MASKED;
+    rtc_disable_timer();
 }
 
 static void
 }
 
 static void
-rtc_do_ticking(struct hwrtc* rtc, void (*on_tick)())
+rtc_cls_mask(struct hwrtc* rtc)
 {
 {
-    if (!on_tick || rtc_state(rtc->data)->ticking) {
-        return;
-    }
-
     struct mc146818* state = rtc_state(rtc->data);
     struct mc146818* state = rtc_state(rtc->data);
-    state->ticking = 1;
-    state->on_tick_cb = on_tick;
-
-    /* We realise that using rtc to tick something has an extremely rare use
-     * case (e.g., calibrating some timer). Therefore, we will release this
-     * allocated IV when rtc ticking is no longer required to save IV
-     * resources.
-     */
-    state->rtc_iv = isrm_bindirq(PC_AT_IRQ_RTC, __rtc_tick);
 
 
+    rtc->state = 0;
+    state->tick_counts = 0;
     rtc_enable_timer();
 }
 
     rtc_enable_timer();
 }
 
-static void
-rtc_end_ticking(struct hwrtc* rtc)
+static int
+rtc_chfreq(struct hwrtc* rtc, int freq)
+{
+    return ENOTSUP;
+}
+
+static int
+rtc_getcnt(struct hwrtc* rtc)
+{
+    struct mc146818* state = rtc_state(rtc->data);
+    return state->tick_counts;
+}
+
+static int
+rtc_init(struct device_def* devdef)
 {
 {
-    if (!rtc_state(rtc->data)->ticking) {
-        return;
-    }
+    u8_t reg = rtc_read_reg(RTC_REG_A);
+    reg = (reg & ~0x7f) | RTC_FREQUENCY_1024HZ | RTC_DIVIDER_33KHZ;
+    rtc_write_reg(RTC_REG_A, reg);
 
 
+    reg = RTC_BIN | RTC_HOURFORM24;
+    rtc_write_reg(RTC_REG_B, reg);
+
+    // Make sure the rtc timer is disabled by default
     rtc_disable_timer();
 
     rtc_disable_timer();
 
-    // do some delay, ensure there is no more interrupt from rtc before we
-    // release isr
-    port_delay(1000);
+    struct hwrtc* rtc = hwrtc_alloc_new("mc146818");
+    struct mc146818* state = valloc(sizeof(struct mc146818));
 
 
-    isrm_ivfree(rtc_state(rtc->data)->rtc_iv);
+    state->rtc_context = rtc;
+    state->rtc_iv = isrm_bindirq(PC_AT_IRQ_RTC, __rtc_tick);
+    isrm_set_payload(state->rtc_iv, (ptr_t)state);
+
+    rtc->state = RTC_STATE_MASKED;
+    rtc->data = state;
+    rtc->base_freq = RTC_TIMER_BASE_FREQUENCY;
+    rtc->get_walltime = rtc_getwalltime;
+    rtc->set_walltime = rtc_setwalltime;
+    rtc->set_mask = rtc_set_mask;
+    rtc->cls_mask = rtc_cls_mask;
+    rtc->get_counts = rtc_getcnt;
+    rtc->chfreq = rtc_chfreq;
 
 
-    rtc_state(rtc->data)->ticking = 0;
+    return 0;
 }
 
 }
 
-static struct hwrtc hwrtc_mc146818a = { .name = "mc146818a",
-                                        .data = &rtc_state,
-                                        .init = rtc_init,
-                                        .base_freq = RTC_TIMER_BASE_FREQUENCY,
-                                        .supported = mc146818_check_support,
-                                        .get_walltime = clock_walltime,
-                                        .do_ticking = rtc_do_ticking,
-                                        .end_ticking = rtc_end_ticking };
-
-struct hwrtc*
-mc146818a_rtc_context()
-{
-    return &hwrtc_mc146818a;
-}
+static struct device_def devrtc_mc146818 = {
+    .name = "MC146818 RTC",
+    .class = DEVCLASS(DEVIF_SOC, DEVFN_TIME, DEV_RTC, 1),
+    .init = rtc_init
+};
+EXPORT_DEVICE(mc146818, &devrtc_mc146818, load_earlystage);
\ No newline at end of file