tc8521: first cut at an RTC driver for the NC100
authorAlan Cox <alan@linux.intel.com>
Sun, 7 Oct 2018 12:40:07 +0000 (13:40 +0100)
committerAlan Cox <alan@linux.intel.com>
Sun, 7 Oct 2018 12:40:07 +0000 (13:40 +0100)
I believe the NC200 needs an MC146818 driver writing

Kernel/platform-amstradnc/tc8521.c [new file with mode: 0644]

diff --git a/Kernel/platform-amstradnc/tc8521.c b/Kernel/platform-amstradnc/tc8521.c
new file mode 100644 (file)
index 0000000..3f437e9
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *     This is intended for the NC100. It assumes 24 hour clock mode, no
+ *     timer or alarm running. It also for now assumes a 1990 base as the
+ *     NC100 does.
+ *
+ *     This code breaks in 2089.
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <stdbool.h>
+#include <printf.h>
+#include <rtc.h>
+
+#define CLOCK_PORT     0xC0
+
+static uint8_t rtc_buf[7];
+
+static void read_clock(void) __naked
+{
+    __asm
+        ; select the time page (we should do this at init) ?
+        xor a
+        out (CLOCK_PORT+13),a
+
+retry:
+        ld bc,#(3*256 + CLOCK_PORT+12)
+        ld hl,#_rtc_buf
+
+        ld d,#2                ; loop count
+
+        in a,(CLOCK_PORT)
+        ld e,a         ; seconds on read start
+        
+        ; We do two passes of half of the data because there is a week digit
+        ; stuck in the middle we dont want
+
+l1:     ini            ; high bits of field in low bits of (hl)
+        dec c
+        in a,(c)
+        dec hl
+        rld            ; I have alwasy wanted an excuse to use RLD 8)
+        inc hl
+        dec c
+        djnz l1
+        ld b,#3
+        dec c          ; Skip day of week
+        dec d          ; Loop count
+        jr nz, l1
+        ; check if seconds changed (we read them last)
+        dec hl         ; back to seconds
+        ld a,(hl)      ; HL still points at the seconds
+        cp e
+        jr nz, retry
+    __endasm;
+}
+
+
+uint8_t platform_rtc_secs(void) __naked
+{
+    __asm
+        in a, (CLOCK_PORT)
+        ld l,a
+    __endasm;
+}
+
+/* Full RTC support (for read - no write yet) */
+int platform_rtc_read(void)
+{
+       uint16_t len = sizeof(struct cmos_rtc);
+       uint16_t y;
+       struct cmos_rtc cmos;
+       uint8_t *p = cmos.data.bytes;
+
+       if (udata.u_count < len)
+               len = udata.u_count;
+
+        /* Places 7 BCD pairs into rtc_buf */
+       read_clock();
+
+       y = *rtc_buf;
+       /* 1990 based year , if its 0x10 or more we are in 2000-2089 and
+          need to adjust the clock up by 2000 and back by 10. If not well
+          then its 1990-1999 so just needs 0x1990 adding to the 0-9 we have */
+       if (y >= 0x10)
+           y += 0x19F0;
+        else
+            y += 0x1990;
+       *p++ = y >> 8;
+       *p++ = y;
+       *p++ = rtc_buf[1];      /* month */
+       *p++ = rtc_buf[2];      /* day */
+       *p++ = rtc_buf[3];      /* Hour */
+       *p++ = rtc_buf[4];      /* Minute */
+       *p = rtc_buf[5];        /* Second */
+       cmos.type = CMOS_RTC_BCD;
+       if (uput(&cmos, udata.u_base, len) == -1)
+               return -1;
+       return len;
+}
+
+int platform_rtc_write(void)
+{
+       udata.u_error = -EOPNOTSUPP;
+       return -1;
+}