diff options
Diffstat (limited to 'os/sa1110/devrtc.c')
| -rw-r--r-- | os/sa1110/devrtc.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/os/sa1110/devrtc.c b/os/sa1110/devrtc.c new file mode 100644 index 00000000..54680fc2 --- /dev/null +++ b/os/sa1110/devrtc.c @@ -0,0 +1,169 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "io.h" + +/* + * SA11x0 real time clock + * TO DO: alarms, wakeup, allow trim setting(?) + */ + +enum{ + Qdir, + Qrtc, + Qrtctrim, +}; + +static Dirtab rtcdir[]={ + ".", {Qdir,0,QTDIR}, 0, 0555, + "rtc", {Qrtc}, NUMSIZE, 0664, + "rtctrim", {Qrtctrim}, 0, 0664, +}; +#define NRTC (sizeof(rtcdir)/sizeof(rtcdir[0])) + +extern ulong boottime; + +enum { + RTSR_al= 1<<0, /* RTC alarm detected */ + RTSR_hz= 1<<1, /* 1-Hz rising-edge detected */ + RTSR_ale= 1<<2, /* RTC alarm interrupt enabled */ + RTSR_hze= 1<<3, /* 1-Hz interrupt enable */ +}; + +static void +rtcreset(void) +{ + RtcReg *r; + + r = RTCREG; + if((r->rttr & 0xFFFF) == 0){ /* reset state */ + r->rttr = 32768-1; + r->rcnr = boottime; /* typically zero */ + } + r->rtar = ~0; + r->rtsr = RTSR_al | RTSR_hz; +} + +static Chan* +rtcattach(char *spec) +{ + return devattach('r', spec); +} + +static Walkqid* +rtcwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, rtcdir, NRTC, devgen); +} + +static int +rtcstat(Chan *c, uchar *dp, int n) +{ + return devstat(c, dp, n, rtcdir, NRTC, devgen); +} + +static Chan* +rtcopen(Chan *c, int omode) +{ + return devopen(c, omode, rtcdir, NRTC, devgen); +} + +static void +rtcclose(Chan*) +{ +} + +static long +rtcread(Chan *c, void *buf, long n, vlong off) +{ + if(c->qid.type & QTDIR) + return devdirread(c, buf, n, rtcdir, NRTC, devgen); + + switch((ulong)c->qid.path){ + case Qrtc: + return readnum(off, buf, n, RTCREG->rcnr, NUMSIZE); + case Qrtctrim: + return readnum(off, buf, n, RTCREG->rttr, NUMSIZE); + } + error(Egreg); + return 0; /* not reached */ +} + +static long +rtcwrite(Chan *c, void *buf, long n, vlong off) +{ + ulong offset = off; + ulong secs; + char *cp, sbuf[32]; + + switch((ulong)c->qid.path){ + case Qrtc: + /* + * write the time + */ + if(offset != 0 || n >= sizeof(sbuf)-1) + error(Ebadarg); + memmove(sbuf, buf, n); + sbuf[n] = '\0'; + cp = sbuf; + while(*cp){ + if(*cp>='0' && *cp<='9') + break; + cp++; + } + secs = strtoul(cp, 0, 0); + RTCREG->rcnr = secs; + return n; + + case Qrtctrim: + if(offset != 0 || n >= sizeof(sbuf)-1) + error(Ebadarg); + memmove(sbuf, buf, n); + sbuf[n] = '\0'; + RTCREG->rttr = strtoul(sbuf, 0, 0); + return n; + } + error(Egreg); + return 0; /* not reached */ +} + +static void +rtcpower(int on) +{ + if(on) + boottime = RTCREG->rcnr - TK2SEC(MACHP(0)->ticks); + else + RTCREG->rcnr = seconds(); +} + +long +rtctime(void) +{ + return RTCREG->rcnr; +} + +Dev rtcdevtab = { + 'r', + "rtc", + + rtcreset, + devinit, + devshutdown, + rtcattach, + rtcwalk, + rtcstat, + rtcopen, + devcreate, + rtcclose, + rtcread, + devbread, + rtcwrite, + devbwrite, + devremove, + devwstat, + rtcpower, +}; |
