xref: /netbsd-src/sys/arch/evbppc/walnut/dev/ds1743.c (revision b59f66e17c500a0d8ac8904c4c2fe7f387334983)
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