1*b59f66e1Schristos /* $NetBSD: ds1743.c,v 1.10 2014/11/20 16:34:25 christos Exp $ */
25448df2eSscw
35448df2eSscw /*
45448df2eSscw * Copyright (c) 2001-2002 Wasabi Sysetms, Inc.
55448df2eSscw * Copyright (c) 1998 Mark Brinicombe.
65448df2eSscw * Copyright (c) 1998 Causality Limited.
75448df2eSscw * All rights reserved.
85448df2eSscw *
95448df2eSscw * Written by Mark Brinicombe, Causality Limited
105448df2eSscw *
115448df2eSscw * Redistribution and use in source and binary forms, with or without
125448df2eSscw * modification, are permitted provided that the following conditions
135448df2eSscw * are met:
145448df2eSscw * 1. Redistributions of source code must retain the above copyright
155448df2eSscw * notice, this list of conditions and the following disclaimer.
165448df2eSscw * 2. Redistributions in binary form must reproduce the above copyright
175448df2eSscw * notice, this list of conditions and the following disclaimer in the
185448df2eSscw * documentation and/or other materials provided with the distribution.
195448df2eSscw * 3. All advertising materials mentioning features or use of this software
205448df2eSscw * must display the following acknowledgement:
215448df2eSscw * This product includes software developed by Mark Brinicombe
225448df2eSscw * for the NetBSD Project.
235448df2eSscw * 4. The name of the company nor the name of the author may be used to
245448df2eSscw * endorse or promote products derived from this software without specific
255448df2eSscw * prior written permission.
265448df2eSscw *
275448df2eSscw * THIS SOFTWARE IS PROVIDED BY CAUASLITY LIMITED ``AS IS'' AND ANY EXPRESS
285448df2eSscw * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
295448df2eSscw * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
305448df2eSscw * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED OR CONTRIBUTORS BE LIABLE
315448df2eSscw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
325448df2eSscw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
335448df2eSscw * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
345448df2eSscw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
355448df2eSscw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
365448df2eSscw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
375448df2eSscw * SUCH DAMAGE.
385448df2eSscw */
395448df2eSscw
4014172728Slukem #include <sys/cdefs.h>
41*b59f66e1Schristos __KERNEL_RCSID(0, "$NetBSD: ds1743.c,v 1.10 2014/11/20 16:34:25 christos Exp $");
4214172728Slukem
435448df2eSscw #include <sys/param.h>
445448df2eSscw #include <sys/systm.h>
455448df2eSscw #include <sys/device.h>
46825211a4Sgdamore #include <dev/clock_subr.h>
475448df2eSscw
485448df2eSscw #include <machine/rtc.h>
49cf10107dSdyoung #include <sys/bus.h>
505448df2eSscw
515448df2eSscw #include <evbppc/walnut/dev/ds1743reg.h>
525448df2eSscw #include <evbppc/walnut/dev/pbusvar.h>
535448df2eSscw
545448df2eSscw struct dsrtc_softc {
5545f9bc98Scliff device_t sc_dev;
565448df2eSscw bus_space_tag_t sc_iot;
575448df2eSscw bus_space_handle_t sc_ioh;
58825211a4Sgdamore struct todr_chip_handle sc_todr;
595448df2eSscw };
605448df2eSscw
6145f9bc98Scliff static void dsrtcattach(device_t, device_t, void *);
6245f9bc98Scliff static int dsrtcmatch(device_t, cfdata_t, void *);
635448df2eSscw #if 0 /* Nothing uses these yet */
645448df2eSscw static int ds1743_ram_read(struct dsrtc_softc *, int);
655448df2eSscw static void ds1743_ram_write(struct dsrtc_softc *, int, int);
665448df2eSscw #endif
675448df2eSscw
68825211a4Sgdamore static int dsrtc_read(todr_chip_handle_t, struct clock_ymdhms *);
69825211a4Sgdamore static int dsrtc_write(todr_chip_handle_t, struct clock_ymdhms *);
705448df2eSscw static inline u_char ds1743_read(struct dsrtc_softc *, int);
715448df2eSscw static inline void ds1743_write(struct dsrtc_softc *, int, u_char);
725448df2eSscw static u_char ds1743_lock(struct dsrtc_softc *, u_char);
735448df2eSscw static void ds1743_unlock(struct dsrtc_softc *, u_char);
745448df2eSscw
755448df2eSscw /* device and attach structures */
7645f9bc98Scliff CFATTACH_DECL_NEW(ds1743rtc, sizeof(struct dsrtc_softc),
775448df2eSscw dsrtcmatch, dsrtcattach, NULL, NULL);
785448df2eSscw
795448df2eSscw /*
805448df2eSscw * dsrtcmatch()
815448df2eSscw *
825448df2eSscw * Validate the IIC address to make sure its an RTC we understand
835448df2eSscw */
845448df2eSscw int ds1743found = 0;
855448df2eSscw
865448df2eSscw #define DS_SCRATCH_ADDR 0x1FF7
875448df2eSscw
885448df2eSscw static int
dsrtcmatch(device_t parent,cfdata_t cf,void * aux)8945f9bc98Scliff dsrtcmatch(device_t parent, cfdata_t cf, void *aux)
905448df2eSscw {
915448df2eSscw struct pbus_attach_args *paa = aux;
925448df2eSscw int retval = !ds1743found;
935448df2eSscw bus_space_handle_t h;
945448df2eSscw u_int8_t x;
955448df2eSscw
965448df2eSscw /* match only RTC devices */
975448df2eSscw if (strcmp(paa->pb_name, cf->cf_name) != 0)
985448df2eSscw return 0;
995448df2eSscw
1000b0e493eSscw if (bus_space_map(paa->pb_bt, paa->pb_addr, DS_SIZE, 0, &h)) {
1015448df2eSscw printf("%s: can't map i/o space\n", paa->pb_name);
1025448df2eSscw return 0;
1035448df2eSscw }
1045448df2eSscw
1055448df2eSscw /* Read one byte of what's supposed to be NVRAM */
1060b0e493eSscw x = bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR);
1070b0e493eSscw bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, 0xAA);
1080b0e493eSscw if (bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR) != 0xAA) {
1095448df2eSscw retval = 0;
1105448df2eSscw goto done;
1115448df2eSscw }
1125448df2eSscw
1130b0e493eSscw bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, 0x55);
1140b0e493eSscw if (bus_space_read_1(paa->pb_bt, h, DS_SCRATCH_ADDR) != 0x55) {
1155448df2eSscw retval = 0;
1165448df2eSscw goto done;
1175448df2eSscw }
1185448df2eSscw
1195448df2eSscw /* Restore scratch byte value */
1200b0e493eSscw bus_space_write_1(paa->pb_bt, h, DS_SCRATCH_ADDR, x);
1215448df2eSscw done:
1220b0e493eSscw bus_space_unmap(paa->pb_bt, h, DS_SIZE);
1235448df2eSscw
1245448df2eSscw return retval;
1255448df2eSscw }
1265448df2eSscw
1275448df2eSscw /*
1285448df2eSscw * dsrtcattach()
1295448df2eSscw *
1305448df2eSscw * Attach the rtc device
1315448df2eSscw */
1325448df2eSscw
1335448df2eSscw static void
dsrtcattach(device_t parent,device_t self,void * aux)13445f9bc98Scliff dsrtcattach(device_t parent, device_t self, void *aux)
1355448df2eSscw {
13645f9bc98Scliff struct dsrtc_softc *sc = device_private(self);
1375448df2eSscw struct pbus_attach_args *paa = aux;
1385448df2eSscw
1395448df2eSscw ds1743found = 1;
1405448df2eSscw
14145f9bc98Scliff sc->sc_dev = self;
1420b0e493eSscw sc->sc_iot = paa->pb_bt;
1435448df2eSscw if (bus_space_map(sc->sc_iot, paa->pb_addr, DS_SIZE, 0, &sc->sc_ioh)) {
1445448df2eSscw printf(": can't map i/o space\n");
1455448df2eSscw return;
1465448df2eSscw }
1475448df2eSscw
1485448df2eSscw ds1743_unlock(sc, 0); /* Make sure the clock is running */
1495448df2eSscw if ((ds1743_read(sc, DS_DAY) & DS_CTL_BF) == 0)
1505448df2eSscw printf(": lithium cell is dead, RTC unreliable");
1515448df2eSscw printf("\n");
1525448df2eSscw
153825211a4Sgdamore sc->sc_todr.todr_gettime_ymdhms = dsrtc_read;
154825211a4Sgdamore sc->sc_todr.todr_settime_ymdhms = dsrtc_write;
155825211a4Sgdamore sc->sc_todr.cookie = sc;
15645f9bc98Scliff
15745f9bc98Scliff #ifdef DEBUG
15845f9bc98Scliff {
15945f9bc98Scliff struct clock_ymdhms dt;
16045f9bc98Scliff dsrtc_read(&sc->sc_todr, &dt);
16145f9bc98Scliff printf("RTC: %d/%d/%04d %d:%02d:%02d\n",
16245f9bc98Scliff dt.dt_mon, dt.dt_day, dt.dt_year,
16345f9bc98Scliff dt.dt_hour, dt.dt_min, dt.dt_sec);
16445f9bc98Scliff }
16545f9bc98Scliff #endif
16645f9bc98Scliff
167825211a4Sgdamore todr_attach(&sc->sc_todr);
1685448df2eSscw }
1695448df2eSscw
1705448df2eSscw static inline u_char
ds1743_read(struct dsrtc_softc * sc,int addr)1715448df2eSscw ds1743_read(struct dsrtc_softc *sc, int addr)
1725448df2eSscw {
1735448df2eSscw
1745448df2eSscw return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, addr));
1755448df2eSscw }
1765448df2eSscw
1775448df2eSscw static inline void
ds1743_write(struct dsrtc_softc * sc,int addr,u_char data)1785448df2eSscw ds1743_write(struct dsrtc_softc *sc, int addr, u_char data)
1795448df2eSscw {
1805448df2eSscw
1815448df2eSscw bus_space_write_1(sc->sc_iot, sc->sc_ioh, addr, data);
1825448df2eSscw }
1835448df2eSscw
1845448df2eSscw
1855448df2eSscw #if 0 /* Nothing uses these yet */
1865448df2eSscw static u_char
1875448df2eSscw ds1743_ram_read(struct dsrtc_softc *sc, int addr)
1885448df2eSscw {
1895448df2eSscw
1905448df2eSscw if (addr >= DS_RAM_SIZE)
1915448df2eSscw return(-1);
1925448df2eSscw return(ds1743_read(sc, addr));
1935448df2eSscw }
1945448df2eSscw
1955448df2eSscw static void
1965448df2eSscw ds1743_ram_write(struct dsrtc_softc *sc, int addr, u_char val)
1975448df2eSscw {
1985448df2eSscw
1995448df2eSscw if (addr >= DS_RAM_SIZE)
2005448df2eSscw return (-1);
2015448df2eSscw ds1743_write(sc, addr, val);
2025448df2eSscw }
2035448df2eSscw #endif
2045448df2eSscw
2055448df2eSscw #define BCD(x) ((((x) / 10) << 4) | (x % 10))
2065448df2eSscw #define unBCD(v, x) v = x; v = ((v >> 4) & 0xf) * 10 + (v & 0xf)
2075448df2eSscw
2085448df2eSscw static u_char
ds1743_lock(struct dsrtc_softc * sc,u_char mode)2095448df2eSscw ds1743_lock(struct dsrtc_softc *sc, u_char mode)
2105448df2eSscw {
2115448df2eSscw u_char octl, ctl;
2125448df2eSscw
2135448df2eSscw octl = ds1743_read(sc, DS_CENTURY);
2145448df2eSscw ctl = octl | (mode & DS_CTL_RW);
2155448df2eSscw ds1743_write(sc, DS_CENTURY, ctl); /* Lock RTC for both reading and writing */
2165448df2eSscw return octl;
2175448df2eSscw }
2185448df2eSscw
2195448df2eSscw static void
ds1743_unlock(struct dsrtc_softc * sc,u_char key)2205448df2eSscw ds1743_unlock(struct dsrtc_softc *sc, u_char key)
2215448df2eSscw {
2225448df2eSscw int ctl;
2235448df2eSscw
2245448df2eSscw ctl = ds1743_read(sc, DS_CENTURY);
2255448df2eSscw ctl = (ctl & 0x3f) | (key & DS_CTL_RW);
2265448df2eSscw ds1743_write(sc, DS_CENTURY, ctl); /* Enable updates */
2275448df2eSscw }
2285448df2eSscw
2295448df2eSscw static int
dsrtc_write(todr_chip_handle_t tch,struct clock_ymdhms * dt)230825211a4Sgdamore dsrtc_write(todr_chip_handle_t tch, struct clock_ymdhms *dt)
2315448df2eSscw {
232825211a4Sgdamore struct dsrtc_softc *sc = tch->cookie;
2335448df2eSscw u_char key;
2345448df2eSscw
2355448df2eSscw key = ds1743_lock(sc, DS_CTL_W);
2365448df2eSscw
237*b59f66e1Schristos ds1743_write(sc, DS_SECONDS, bintobcd(dt->dt_sec) & 0x7f);
238*b59f66e1Schristos ds1743_write(sc, DS_MINUTES, bintobcd(dt->dt_min) & 0x7f);
239*b59f66e1Schristos ds1743_write(sc, DS_HOURS, bintobcd(dt->dt_hour) & 0x3f);
240*b59f66e1Schristos ds1743_write(sc, DS_DATE, bintobcd(dt->dt_day) & 0x3f);
241*b59f66e1Schristos ds1743_write(sc, DS_MONTH, bintobcd(dt->dt_mon) & 0x1f);
242*b59f66e1Schristos ds1743_write(sc, DS_YEAR, bintobcd(dt->dt_year % 100));
2435448df2eSscw ds1743_write(sc, DS_CENTURY, ((ds1743_read(sc, DS_CENTURY) & DS_CTL_RW)
244*b59f66e1Schristos | bintobcd(dt->dt_year / 100)));
2455448df2eSscw
2465448df2eSscw ds1743_unlock(sc, key);
247825211a4Sgdamore return(0);
2485448df2eSscw }
2495448df2eSscw
2505448df2eSscw static int
dsrtc_read(todr_chip_handle_t tch,struct clock_ymdhms * dt)251825211a4Sgdamore dsrtc_read(todr_chip_handle_t tch, struct clock_ymdhms *dt)
2525448df2eSscw {
253825211a4Sgdamore struct dsrtc_softc *sc = tch->cookie;
2545448df2eSscw u_char key;
2555448df2eSscw
2565448df2eSscw key = ds1743_lock(sc, DS_CTL_R);
257*b59f66e1Schristos dt->dt_sec = bcdtobin(ds1743_read(sc, DS_SECONDS) & 0x7f);
258*b59f66e1Schristos dt->dt_min = bcdtobin(ds1743_read(sc, DS_MINUTES) & 0x7f);
259*b59f66e1Schristos dt->dt_hour = bcdtobin(ds1743_read(sc, DS_HOURS) & 0x3f);
260*b59f66e1Schristos dt->dt_day = bcdtobin(ds1743_read(sc, DS_DATE) & 0x3f);
261*b59f66e1Schristos dt->dt_mon = bcdtobin(ds1743_read(sc, DS_MONTH) & 0x1f);
262825211a4Sgdamore dt->dt_year =
263*b59f66e1Schristos bcdtobin(ds1743_read(sc, DS_YEAR)) +
264*b59f66e1Schristos bcdtobin(ds1743_read(sc, DS_CENTURY) & ~DS_CTL_RW) * 100;
2655448df2eSscw
2665448df2eSscw ds1743_unlock(sc, key);
267825211a4Sgdamore return(0);
2685448df2eSscw }
269