1 /* $NetBSD: omap_rtc.c,v 1.3 2008/11/21 17:13:07 matt Exp $ */
4 * OMAP RTC driver, based on i80321_timer.c.
6 * Copyright (c) 2007 Microsoft
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Microsoft
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTERS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: omap_rtc.c,v 1.3 2008/11/21 17:13:07 matt Exp $");
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <dev/clock_subr.h>
45 #include <machine/bus.h>
46 #include <machine/intr.h>
48 #include <arm/omap/omap_reg.h>
49 #include <arm/omap/omap_tipb.h>
51 /* RTC year values relative to this year */
55 /* Register offsets and bit fields. */
57 #define SECONDS_REG 0x00
58 #define MINUTES_REG 0x04
59 #define HOURS_REG 0x08
61 #define MONTHS_REG 0x10
62 #define YEARS_REG 0x14
63 #define WEEKS_REG 0x18
64 #define ALARM_SECONDS_REG 0x20
65 #define ALARM_MINUTES_REG 0x24
66 #define ALARM_HOURS_REG 0x28
67 #define ALARM_DAYS_REG 0x2c
68 #define ALARM_MONTHS_REG 0x30
69 #define ALARM_YEARS_REG 0x34
71 #define RTC_CTRL_REG 0x40
74 #define RTC_STATUS_REG 0x44
78 #define RTC_INTERRUPTS_REG 0x48
81 static int omaprtc_match(device_t
, cfdata_t
, void *);
82 static void omaprtc_attach(device_t
, device_t
, void *);
84 struct omaprtc_softc
{
86 bus_space_tag_t sc_iot
;
87 bus_space_handle_t sc_ioh
;
90 struct todr_chip_handle sc_todr
;
93 CFATTACH_DECL_NEW(omaprtc
, sizeof(struct omaprtc_softc
),
94 omaprtc_match
, omaprtc_attach
, NULL
, NULL
);
96 static int omaprtc_gettime(todr_chip_handle_t
, struct clock_ymdhms
*);
97 static int omaprtc_settime(todr_chip_handle_t
, struct clock_ymdhms
*);
99 #define rtc_is_busy() (bus_space_read_1(sc->sc_iot, sc->sc_ioh, \
100 RTC_STATUS_REG) & 1<<BUSY)
103 omaprtc_gettime(todr_chip_handle_t tch
, struct clock_ymdhms
*dt
)
105 struct omaprtc_softc
*sc
= tch
->cookie
;
108 /* Wait for RTC_STATUS_REG:BUSY to go low to
109 * guarantee our read is correct. BUSY will
110 * only be high for one 32kHz period (30.5us)
111 * each second, so we'll usually pass right
114 * Watch RTC_CTRL_REG:STOP_RTC as well so
115 * we don't spin forever if someone disables the RTC.
117 * Turn interrupts off, because we are only allowed
118 * to read/write the registers for 1/2 of a 32kHz
119 * clock period (= 15us) after detecting that BUSY
123 s
= disable_interrupts(I32_bit
);
125 while (rtc_is_busy()) {
130 FROMBCD(bus_space_read_1(sc
->sc_iot
,
132 YEARS_REG
)) + BASEYEAR
;
134 FROMBCD(bus_space_read_1(sc
->sc_iot
,
138 FROMBCD(bus_space_read_1(sc
->sc_iot
,
142 FROMBCD(bus_space_read_1(sc
->sc_iot
,
146 FROMBCD(bus_space_read_1(sc
->sc_iot
,
150 FROMBCD(bus_space_read_1(sc
->sc_iot
,
154 FROMBCD(bus_space_read_1(sc
->sc_iot
,
157 restore_interrupts(s
);
162 omaprtc_settime(todr_chip_handle_t tch
, struct clock_ymdhms
*dt
)
164 struct omaprtc_softc
*sc
= tch
->cookie
;
167 s
= disable_interrupts(I32_bit
);
169 while (rtc_is_busy()) {
173 /* It's ok to write these without stopping the
174 * RTC, because the BUSY mechanism lets us guarantee
175 * that we're not in the middle of, e.g., rolling
176 * seconds into minutes.
179 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
180 YEARS_REG
, TOBCD(dt
->dt_year
- BASEYEAR
));
181 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
182 MONTHS_REG
, TOBCD(dt
->dt_mon
));
183 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
184 WEEKS_REG
, TOBCD(dt
->dt_wday
& 0x0f));
185 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
186 DAYS_REG
, TOBCD(dt
->dt_day
));
187 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
188 SECONDS_REG
, TOBCD(dt
->dt_sec
));
189 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
190 HOURS_REG
, TOBCD(dt
->dt_hour
));
191 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
192 MINUTES_REG
, TOBCD(dt
->dt_min
));
193 restore_interrupts(s
);
198 omaprtc_match(device_t parent
, cfdata_t match
, void *aux
)
200 struct tipb_attach_args
*tipb
= aux
;
202 if (tipb
->tipb_addr
== -1)
203 panic("omaprtc must have addr specified in config.");
205 if (tipb
->tipb_size
== 0)
206 tipb
->tipb_size
= 2048; /* Per the OMAP TRM. */
208 /* We implicitly trust the config file. */
213 omaprtc_attach(device_t parent
, device_t self
, void *aux
)
215 struct omaprtc_softc
*sc
= device_private(self
);
216 struct tipb_attach_args
*tipb
= aux
;
218 sc
->sc_iot
= tipb
->tipb_iot
;
219 sc
->sc_intr
= tipb
->tipb_intr
;
221 if (bus_space_map(tipb
->tipb_iot
, tipb
->tipb_addr
, tipb
->tipb_size
, 0,
223 panic("%s: Cannot map registers", device_xname(self
));
225 aprint_normal(": OMAP RTC\n");
229 * Start RTC (STOP_RTC=1 starts it, go figure), 24 hour mode,
230 * no autocompensation, no rounding, 32KHz clock enabled,
231 * cannot use split power, no test mode.
234 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, RTC_CTRL_REG
,
237 sc
->sc_todr
.cookie
= sc
;
238 sc
->sc_todr
.todr_gettime_ymdhms
= omaprtc_gettime
;
239 sc
->sc_todr
.todr_settime_ymdhms
= omaprtc_settime
;
240 todr_attach(&sc
->sc_todr
);