1*e5fbc36aSthorpej /* $NetBSD: rtc.c,v 1.11 2023/12/20 15:34:45 thorpej Exp $ */
2fb3a817dSuwe
357675076Suwe /*-
457675076Suwe * Copyright (c) 2002 The NetBSD Foundation, Inc.
557675076Suwe * All rights reserved.
657675076Suwe *
757675076Suwe * This code is derived from software contributed to The NetBSD Foundation
857675076Suwe * by UCHIYAMA Yasushi.
957675076Suwe *
1057675076Suwe * Redistribution and use in source and binary forms, with or without
1157675076Suwe * modification, are permitted provided that the following conditions
1257675076Suwe * are met:
1357675076Suwe * 1. Redistributions of source code must retain the above copyright
1457675076Suwe * notice, this list of conditions and the following disclaimer.
1557675076Suwe * 2. Redistributions in binary form must reproduce the above copyright
1657675076Suwe * notice, this list of conditions and the following disclaimer in the
1757675076Suwe * documentation and/or other materials provided with the distribution.
1857675076Suwe *
1957675076Suwe * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2057675076Suwe * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2157675076Suwe * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2257675076Suwe * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2357675076Suwe * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2457675076Suwe * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2557675076Suwe * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2657675076Suwe * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2757675076Suwe * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2857675076Suwe * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2957675076Suwe * POSSIBILITY OF SUCH DAMAGE.
3057675076Suwe */
3157675076Suwe
3257675076Suwe #include <sys/cdefs.h>
33*e5fbc36aSthorpej __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.11 2023/12/20 15:34:45 thorpej Exp $");
3457675076Suwe
3557675076Suwe #include <sys/param.h>
3657675076Suwe #include <sys/kernel.h>
3757675076Suwe #include <sys/device.h>
3857675076Suwe #include <sys/systm.h>
3957675076Suwe #ifdef GPROF
4057675076Suwe #include <sys/gmon.h>
4157675076Suwe #endif
4257675076Suwe
4357675076Suwe #include <dev/clock_subr.h>
4457675076Suwe
4557675076Suwe #include <sh3/rtcreg.h>
4657675076Suwe
473ce2a9cbSuwe #if defined(DEBUG) && !defined(RTC_DEBUG)
483ce2a9cbSuwe #define RTC_DEBUG
493ce2a9cbSuwe #endif
503ce2a9cbSuwe
5157675076Suwe
5257675076Suwe struct rtc_softc {
5330cb91aaSuwe device_t sc_dev;
5457675076Suwe
553ce2a9cbSuwe int sc_valid;
5657675076Suwe struct todr_chip_handle sc_todr;
57cc0ad787Stsutsui u_int sc_year0;
5857675076Suwe };
5957675076Suwe
6030cb91aaSuwe static int rtc_match(device_t, cfdata_t, void *);
6130cb91aaSuwe static void rtc_attach(device_t, device_t, void *);
6257675076Suwe
6330cb91aaSuwe CFATTACH_DECL_NEW(rtc, sizeof(struct rtc_softc),
6457675076Suwe rtc_match, rtc_attach, NULL, NULL);
6557675076Suwe
6657675076Suwe
6757675076Suwe /* todr(9) methods */
6857675076Suwe static int rtc_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
6957675076Suwe static int rtc_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
7057675076Suwe
71cc0ad787Stsutsui #ifndef SH3_RTC_BASEYEAR
72cc0ad787Stsutsui #define SH3_RTC_BASEYEAR 1900
73cc0ad787Stsutsui #endif
74cc0ad787Stsutsui u_int sh3_rtc_baseyear = SH3_RTC_BASEYEAR;
7557675076Suwe
7657675076Suwe static int
rtc_match(device_t parent,cfdata_t cfp,void * aux)7730cb91aaSuwe rtc_match(device_t parent, cfdata_t cfp, void *aux)
7857675076Suwe {
7957675076Suwe
8057675076Suwe return 1;
8157675076Suwe }
8257675076Suwe
8357675076Suwe
8457675076Suwe static void
rtc_attach(device_t parent,device_t self,void * aux)8530cb91aaSuwe rtc_attach(device_t parent, device_t self, void *aux)
8657675076Suwe {
8730cb91aaSuwe struct rtc_softc *sc;
883ce2a9cbSuwe uint8_t r;
89cc0ad787Stsutsui prop_number_t prop_rtc_baseyear;
903ce2a9cbSuwe #ifdef RTC_DEBUG
913ce2a9cbSuwe char bits[128];
923ce2a9cbSuwe #endif
9357675076Suwe
9430cb91aaSuwe aprint_naive("\n");
9530cb91aaSuwe aprint_normal("\n");
9630cb91aaSuwe
9730cb91aaSuwe sc = device_private(self);
9830cb91aaSuwe sc->sc_dev = self;
9957675076Suwe
1003ce2a9cbSuwe r = _reg_read_1(SH_(RCR2));
10157675076Suwe
10257675076Suwe #ifdef RTC_DEBUG
1039a5d3f28Schristos snprintb(bits, sizeof(bits), SH_RCR2_BITS, r);
1049a5d3f28Schristos aprint_debug_dev(sc->sc_dev, "RCR2=%s\n", bits);
10557675076Suwe #endif
1063ce2a9cbSuwe
1073ce2a9cbSuwe /* Was the clock running? */
1083ce2a9cbSuwe if ((r & (SH_RCR2_ENABLE | SH_RCR2_START)) == (SH_RCR2_ENABLE
1093ce2a9cbSuwe | SH_RCR2_START))
1103ce2a9cbSuwe sc->sc_valid = 1;
1113ce2a9cbSuwe else {
1123ce2a9cbSuwe sc->sc_valid = 0;
11330cb91aaSuwe aprint_error_dev(sc->sc_dev, "WARNING: clock was stopped\n");
1143ce2a9cbSuwe }
1153ce2a9cbSuwe
1163ce2a9cbSuwe /* Disable carry and alarm interrupts */
1173ce2a9cbSuwe _reg_write_1(SH_(RCR1), 0);
1183ce2a9cbSuwe
1193ce2a9cbSuwe /* Clock runs, no periodic interrupts, no 30-sec adjustment */
1203ce2a9cbSuwe _reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START);
1213ce2a9cbSuwe
12257675076Suwe sc->sc_todr.cookie = sc;
12357675076Suwe sc->sc_todr.todr_gettime_ymdhms = rtc_gettime_ymdhms;
12457675076Suwe sc->sc_todr.todr_settime_ymdhms = rtc_settime_ymdhms;
12557675076Suwe
126cc0ad787Stsutsui prop_rtc_baseyear = prop_dictionary_get(device_properties(self),
127cc0ad787Stsutsui "sh3_rtc_baseyear");
128cc0ad787Stsutsui if (prop_rtc_baseyear != NULL) {
129cc0ad787Stsutsui sh3_rtc_baseyear =
130cc0ad787Stsutsui (u_int)prop_number_integer_value(prop_rtc_baseyear);
131cc0ad787Stsutsui #ifdef RTC_DEBUG
132cc0ad787Stsutsui aprint_debug_dev(self,
133cc0ad787Stsutsui "using baseyear %u passed via device property\n",
134cc0ad787Stsutsui sh3_rtc_baseyear);
135cc0ad787Stsutsui #endif
136cc0ad787Stsutsui }
137cc0ad787Stsutsui sc->sc_year0 = sh3_rtc_baseyear;
138cc0ad787Stsutsui
13957675076Suwe todr_attach(&sc->sc_todr);
1403ce2a9cbSuwe
1413ce2a9cbSuwe #ifdef RTC_DEBUG
1423ce2a9cbSuwe {
1433ce2a9cbSuwe struct clock_ymdhms dt;
1443ce2a9cbSuwe rtc_gettime_ymdhms(&sc->sc_todr, &dt);
1453ce2a9cbSuwe }
1463ce2a9cbSuwe #endif
147c68d2565Suwe
148c68d2565Suwe if (!pmf_device_register(self, NULL, NULL))
149c68d2565Suwe aprint_error_dev(self, "unable to establish power handler\n");
15057675076Suwe }
15157675076Suwe
15257675076Suwe
15357675076Suwe static int
rtc_gettime_ymdhms(todr_chip_handle_t h,struct clock_ymdhms * dt)15457675076Suwe rtc_gettime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt)
15557675076Suwe {
1563ce2a9cbSuwe struct rtc_softc *sc = h->cookie;
15757675076Suwe unsigned int year;
15857675076Suwe int retry = 8;
15957675076Suwe
1603ce2a9cbSuwe if (!sc->sc_valid) {
1613ce2a9cbSuwe #ifdef RTC_DEBUG
16230cb91aaSuwe aprint_debug_dev(sc->sc_dev, "gettime: not valid\n");
1633ce2a9cbSuwe /* but proceed and read/print it anyway */
1643ce2a9cbSuwe #else
1653ce2a9cbSuwe return EIO;
1663ce2a9cbSuwe #endif
1673ce2a9cbSuwe }
1683ce2a9cbSuwe
16957675076Suwe /* disable carry interrupt */
17057675076Suwe _reg_bclr_1(SH_(RCR1), SH_RCR1_CIE);
17157675076Suwe
17257675076Suwe do {
17357675076Suwe uint8_t r = _reg_read_1(SH_(RCR1));
17457675076Suwe r &= ~SH_RCR1_CF;
17557675076Suwe r |= SH_RCR1_AF; /* don't clear alarm flag */
17657675076Suwe _reg_write_1(SH_(RCR1), r);
17757675076Suwe
17857675076Suwe if (CPU_IS_SH3)
17957675076Suwe year = _reg_read_1(SH3_RYRCNT);
18057675076Suwe else
18157675076Suwe year = _reg_read_2(SH4_RYRCNT) & 0x00ff;
182b59f66e1Schristos dt->dt_year = bcdtobin(year);
18357675076Suwe
18457675076Suwe /* read counter */
18557675076Suwe #define RTCGET(x, y) \
186b59f66e1Schristos dt->dt_ ## x = bcdtobin(_reg_read_1(SH_(R ## y ## CNT)))
18757675076Suwe
18857675076Suwe RTCGET(mon, MON);
18957675076Suwe RTCGET(wday, WK);
19057675076Suwe RTCGET(day, DAY);
19157675076Suwe RTCGET(hour, HR);
19257675076Suwe RTCGET(min, MIN);
19357675076Suwe RTCGET(sec, SEC);
19457675076Suwe #undef RTCGET
19557675076Suwe } while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0);
19657675076Suwe
1973ce2a9cbSuwe if (retry == 0) {
1983ce2a9cbSuwe #ifdef RTC_DEBUG
19930cb91aaSuwe aprint_debug_dev(sc->sc_dev, "gettime: retry failed\n");
2003ce2a9cbSuwe #endif
20157675076Suwe return EIO;
2023ce2a9cbSuwe }
20357675076Suwe
204cc0ad787Stsutsui dt->dt_year += sc->sc_year0;
20557675076Suwe if (dt->dt_year < POSIX_BASE_YEAR)
20657675076Suwe dt->dt_year += 100;
20757675076Suwe
2083ce2a9cbSuwe #ifdef RTC_DEBUG
20930cb91aaSuwe aprint_debug_dev(sc->sc_dev,
210b1c3f603Smartin "gettime: %04lu-%02d-%02d %02d:%02d:%02d\n",
211b1c3f603Smartin (unsigned long)dt->dt_year, dt->dt_mon, dt->dt_day,
2123ce2a9cbSuwe dt->dt_hour, dt->dt_min, dt->dt_sec);
2133ce2a9cbSuwe
2143ce2a9cbSuwe if (!sc->sc_valid)
2153ce2a9cbSuwe return EIO;
2163ce2a9cbSuwe #endif
2173ce2a9cbSuwe
21857675076Suwe return 0;
21957675076Suwe }
22057675076Suwe
22157675076Suwe
22257675076Suwe static int
rtc_settime_ymdhms(todr_chip_handle_t h,struct clock_ymdhms * dt)22357675076Suwe rtc_settime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt)
22457675076Suwe {
2253ce2a9cbSuwe struct rtc_softc *sc = h->cookie;
22657675076Suwe unsigned int year;
22757675076Suwe uint8_t r;
22857675076Suwe
229cc0ad787Stsutsui year = dt->dt_year - sc->sc_year0;
230cc0ad787Stsutsui if (year > 99)
231cc0ad787Stsutsui year -= 100;
232cc0ad787Stsutsui
233b59f66e1Schristos year = bintobcd(year);
23457675076Suwe
23557675076Suwe r = _reg_read_1(SH_(RCR2));
2363ce2a9cbSuwe
2373ce2a9cbSuwe /* stop clock */
2383ce2a9cbSuwe _reg_write_1(SH_(RCR2), (r & ~SH_RCR2_START) | SH_RCR2_RESET);
23957675076Suwe
24057675076Suwe /* set time */
24157675076Suwe if (CPU_IS_SH3)
24257675076Suwe _reg_write_1(SH3_RYRCNT, year);
24357675076Suwe else
24457675076Suwe _reg_write_2(SH4_RYRCNT, year);
24557675076Suwe
24657675076Suwe #define RTCSET(x, y) \
247b59f66e1Schristos _reg_write_1(SH_(R ## x ## CNT), bintobcd(dt->dt_ ## y))
24857675076Suwe
24957675076Suwe RTCSET(MON, mon);
25057675076Suwe RTCSET(WK, wday);
25157675076Suwe RTCSET(DAY, day);
25257675076Suwe RTCSET(HR, hour);
25357675076Suwe RTCSET(MIN, min);
25457675076Suwe RTCSET(SEC, sec);
25557675076Suwe
25657675076Suwe #undef RTCSET
25757675076Suwe
25857675076Suwe /* start clock */
2593ce2a9cbSuwe _reg_write_1(SH_(RCR2), r);
2603ce2a9cbSuwe sc->sc_valid = 1;
2613ce2a9cbSuwe
2623ce2a9cbSuwe #ifdef RTC_DEBUG
26330cb91aaSuwe aprint_debug_dev(sc->sc_dev,
264b1c3f603Smartin "settime: %04lu-%02d-%02d %02d:%02d:%02d\n",
265b1c3f603Smartin (unsigned long)dt->dt_year, dt->dt_mon, dt->dt_day,
2663ce2a9cbSuwe dt->dt_hour, dt->dt_min, dt->dt_sec);
2673ce2a9cbSuwe #endif
26857675076Suwe
26957675076Suwe return 0;
27057675076Suwe }
271