xref: /netbsd-src/sys/arch/sh3/dev/rtc.c (revision e5fbc36ada28f9b9a5836ecffaf4a06aa1ebb687)
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