exrtc.c revision 1.1
1/*	$OpenBSD: exrtc.c,v 1.1 2017/03/11 00:11:47 kettenis Exp $	*/
2/*
3 * Copyright (c) 2017 Mark kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/param.h>
19#include <sys/systm.h>
20#include <sys/device.h>
21#include <sys/time.h>
22
23#include <machine/bus.h>
24#include <machine/fdt.h>
25
26#include <dev/ofw/openfirm.h>
27#include <dev/ofw/fdt.h>
28
29#include <dev/clock_subr.h>
30
31extern todr_chip_handle_t todr_handle;
32
33#define RTCCTRL		0x40
34#define RTCCTRL_RTCEN	(1 << 0)
35
36#define RTCSEC		0x70
37#define RTCMIN		0x74
38#define RTCHOUR		0x78
39#define RTCDAY		0x7c
40#define RTCMON		0x84
41#define RTCYEAR		0x88
42
43#define HREAD4(sc, reg)							\
44	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
45#define HWRITE4(sc, reg, val)						\
46	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
47
48struct exrtc_softc {
49	struct device	sc_dev;
50	bus_space_tag_t		sc_iot;
51	bus_space_handle_t	sc_ioh;
52	struct todr_chip_handle sc_todr;
53};
54
55int	exrtc_match(struct device *, void *, void *);
56void	exrtc_attach(struct device *, struct device *, void *);
57
58struct cfattach exrtc_ca = {
59	sizeof(struct exrtc_softc), exrtc_match, exrtc_attach
60};
61
62struct cfdriver exrtc_cd = {
63	NULL, "exrtc", DV_DULL
64};
65
66int	exrtc_gettime(todr_chip_handle_t, struct timeval *);
67int	exrtc_settime(todr_chip_handle_t, struct timeval *);
68
69int
70exrtc_match(struct device *parent, void *match, void *aux)
71{
72	struct fdt_attach_args *faa = aux;
73
74	return OF_is_compatible(faa->fa_node, "samsung,s3c6410-rtc");
75}
76
77void
78exrtc_attach(struct device *parent, struct device *self, void *aux)
79{
80	struct exrtc_softc *sc = (struct exrtc_softc *)self;
81	struct fdt_attach_args *faa = aux;
82	struct clock_ymdhms dt;
83
84	sc->sc_iot = faa->fa_iot;
85
86	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
87	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
88		panic("%s: bus_space_map failed!", __func__);
89
90	printf("\n");
91
92	sc->sc_todr.cookie = sc;
93	sc->sc_todr.todr_gettime = exrtc_gettime;
94	sc->sc_todr.todr_settime = exrtc_settime;
95	todr_handle = &sc->sc_todr;
96}
97
98int
99exrtc_gettime(todr_chip_handle_t handle, struct timeval *tv)
100{
101	struct exrtc_softc *sc = handle->cookie;
102	struct clock_ymdhms dt;
103	int retried = 0;
104
105retry:
106	dt.dt_sec = FROMBCD(HREAD4(sc, RTCSEC));
107	dt.dt_min = FROMBCD(HREAD4(sc, RTCMIN));
108	dt.dt_hour = FROMBCD(HREAD4(sc, RTCHOUR));
109	dt.dt_day = FROMBCD(HREAD4(sc, RTCDAY));
110	dt.dt_mon = FROMBCD(HREAD4(sc, RTCMON));
111	dt.dt_year = FROMBCD(HREAD4(sc, RTCYEAR)) + 1900;
112
113	/* If the second counter rolled over, retry. */
114	if (dt.dt_sec > FROMBCD(HREAD4(sc, RTCSEC)) && !retried) {
115		retried = 1;
116		goto retry;
117	}
118
119	if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 ||
120	    dt.dt_day > 31 || dt.dt_day == 0 ||
121	    dt.dt_mon > 12 || dt.dt_mon == 0 ||
122	    dt.dt_year < POSIX_BASE_YEAR)
123		return 1;
124
125	tv->tv_sec = clock_ymdhms_to_secs(&dt);
126	tv->tv_usec = 0;
127	return 0;
128}
129
130int
131exrtc_settime(todr_chip_handle_t handle, struct timeval *tv)
132{
133	struct exrtc_softc *sc = handle->cookie;
134	struct clock_ymdhms dt;
135	uint32_t val;
136
137	clock_secs_to_ymdhms(tv->tv_sec, &dt);
138
139	HWRITE4(sc, RTCSEC, TOBCD(dt.dt_sec));
140	HWRITE4(sc, RTCMIN, TOBCD(dt.dt_min));
141	HWRITE4(sc, RTCHOUR, TOBCD(dt.dt_hour));
142	HWRITE4(sc, RTCDAY, TOBCD(dt.dt_day));
143	HWRITE4(sc, RTCMON, TOBCD(dt.dt_mon));
144	HWRITE4(sc, RTCYEAR, TOBCD(dt.dt_year - 1900));
145
146	val = HREAD4(sc, RTCCTRL);
147	HWRITE4(sc, RTCCTRL, val | RTCCTRL_RTCEN);
148
149	return 0;
150}
151