Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: rtc.c,v 1.12 2025/09/07 21:45:14 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by UCHIYAMA Yasushi.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.12 2025/09/07 21:45:14 thorpej Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/kernel.h>
     37 #include <sys/device.h>
     38 #include <sys/systm.h>
     39 #ifdef GPROF
     40 #include <sys/gmon.h>
     41 #endif
     42 
     43 #include <dev/clock_subr.h>
     44 
     45 #include <sh3/rtcreg.h>
     46 
     47 #if defined(DEBUG) && !defined(RTC_DEBUG)
     48 #define RTC_DEBUG
     49 #endif
     50 
     51 
     52 struct rtc_softc {
     53 	device_t sc_dev;
     54 
     55 	int sc_valid;
     56 	struct todr_chip_handle sc_todr;
     57 	u_int sc_year0;
     58 };
     59 
     60 static int	rtc_match(device_t, cfdata_t, void *);
     61 static void	rtc_attach(device_t, device_t, void *);
     62 
     63 CFATTACH_DECL_NEW(rtc, sizeof(struct rtc_softc),
     64     rtc_match, rtc_attach, NULL, NULL);
     65 
     66 
     67 /* todr(9) methods */
     68 static int rtc_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
     69 static int rtc_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
     70 
     71 #ifndef SH3_RTC_BASEYEAR
     72 #define SH3_RTC_BASEYEAR	1900
     73 #endif
     74 u_int sh3_rtc_baseyear = SH3_RTC_BASEYEAR;
     75 
     76 static int
     77 rtc_match(device_t parent, cfdata_t cfp, void *aux)
     78 {
     79 
     80 	return 1;
     81 }
     82 
     83 
     84 static void
     85 rtc_attach(device_t parent, device_t self, void *aux)
     86 {
     87 	struct rtc_softc *sc;
     88 	uint8_t r;
     89 	prop_number_t prop_rtc_baseyear;
     90 #ifdef RTC_DEBUG
     91 	char bits[128];
     92 #endif
     93 
     94 	aprint_naive("\n");
     95 	aprint_normal("\n");
     96 
     97 	sc = device_private(self);
     98 	sc->sc_dev = self;
     99 
    100 	r = _reg_read_1(SH_(RCR2));
    101 
    102 #ifdef RTC_DEBUG
    103 	snprintb(bits, sizeof(bits), SH_RCR2_BITS, r);
    104 	aprint_debug_dev(sc->sc_dev, "RCR2=%s\n", bits);
    105 #endif
    106 
    107 	/* Was the clock running? */
    108 	if ((r & (SH_RCR2_ENABLE | SH_RCR2_START)) == (SH_RCR2_ENABLE
    109 						       | SH_RCR2_START))
    110 		sc->sc_valid = 1;
    111 	else {
    112 		sc->sc_valid = 0;
    113 		aprint_error_dev(sc->sc_dev, "WARNING: clock was stopped\n");
    114 	}
    115 
    116 	/* Disable carry and alarm interrupts */
    117 	_reg_write_1(SH_(RCR1), 0);
    118 
    119 	/* Clock runs, no periodic interrupts, no 30-sec adjustment */
    120 	_reg_write_1(SH_(RCR2), SH_RCR2_ENABLE | SH_RCR2_START);
    121 
    122 	sc->sc_todr.todr_dev = self;
    123 	sc->sc_todr.todr_gettime_ymdhms = rtc_gettime_ymdhms;
    124 	sc->sc_todr.todr_settime_ymdhms = rtc_settime_ymdhms;
    125 
    126 	prop_rtc_baseyear = prop_dictionary_get(device_properties(self),
    127 	    "sh3_rtc_baseyear");
    128 	if (prop_rtc_baseyear != NULL) {
    129 		sh3_rtc_baseyear =
    130 		    (u_int)prop_number_integer_value(prop_rtc_baseyear);
    131 #ifdef RTC_DEBUG
    132 		aprint_debug_dev(self,
    133 		    "using baseyear %u passed via device property\n",
    134 		    sh3_rtc_baseyear);
    135 #endif
    136 	}
    137 	sc->sc_year0 = sh3_rtc_baseyear;
    138 
    139 	todr_attach(&sc->sc_todr);
    140 
    141 #ifdef RTC_DEBUG
    142 	{
    143 		struct clock_ymdhms dt;
    144 		rtc_gettime_ymdhms(&sc->sc_todr, &dt);
    145 	}
    146 #endif
    147 
    148 	if (!pmf_device_register(self, NULL, NULL))
    149 		aprint_error_dev(self, "unable to establish power handler\n");
    150 }
    151 
    152 
    153 static int
    154 rtc_gettime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt)
    155 {
    156 	struct rtc_softc *sc = device_private(h->todr_dev);
    157 	unsigned int year;
    158 	int retry = 8;
    159 
    160 	if (!sc->sc_valid) {
    161 #ifdef RTC_DEBUG
    162 		aprint_debug_dev(sc->sc_dev, "gettime: not valid\n");
    163 		/* but proceed and read/print it anyway */
    164 #else
    165 		return EIO;
    166 #endif
    167 	}
    168 
    169 	/* disable carry interrupt */
    170 	_reg_bclr_1(SH_(RCR1), SH_RCR1_CIE);
    171 
    172 	do {
    173 		uint8_t r = _reg_read_1(SH_(RCR1));
    174 		r &= ~SH_RCR1_CF;
    175 		r |= SH_RCR1_AF; /* don't clear alarm flag */
    176 		_reg_write_1(SH_(RCR1), r);
    177 
    178 		if (CPU_IS_SH3)
    179 			year = _reg_read_1(SH3_RYRCNT);
    180 		else
    181 			year = _reg_read_2(SH4_RYRCNT) & 0x00ff;
    182 		dt->dt_year = bcdtobin(year);
    183 
    184 		/* read counter */
    185 #define	RTCGET(x, y) \
    186 		dt->dt_ ## x = bcdtobin(_reg_read_1(SH_(R ## y ## CNT)))
    187 
    188 		RTCGET(mon, MON);
    189 		RTCGET(wday, WK);
    190 		RTCGET(day, DAY);
    191 		RTCGET(hour, HR);
    192 		RTCGET(min, MIN);
    193 		RTCGET(sec, SEC);
    194 #undef RTCGET
    195 	} while ((_reg_read_1(SH_(RCR1)) & SH_RCR1_CF) && --retry > 0);
    196 
    197 	if (retry == 0) {
    198 #ifdef RTC_DEBUG
    199 		aprint_debug_dev(sc->sc_dev, "gettime: retry failed\n");
    200 #endif
    201 		return EIO;
    202 	}
    203 
    204 	dt->dt_year += sc->sc_year0;
    205 	if (dt->dt_year < POSIX_BASE_YEAR)
    206 		dt->dt_year += 100;
    207 
    208 #ifdef RTC_DEBUG
    209 	aprint_debug_dev(sc->sc_dev,
    210 			 "gettime: %04lu-%02d-%02d %02d:%02d:%02d\n",
    211 			 (unsigned long)dt->dt_year, dt->dt_mon, dt->dt_day,
    212 			 dt->dt_hour, dt->dt_min, dt->dt_sec);
    213 
    214 	if (!sc->sc_valid)
    215 		return EIO;
    216 #endif
    217 
    218 	return 0;
    219 }
    220 
    221 
    222 static int
    223 rtc_settime_ymdhms(todr_chip_handle_t h, struct clock_ymdhms *dt)
    224 {
    225 	struct rtc_softc *sc = device_private(h->todr_dev);
    226 	unsigned int year;
    227 	uint8_t r;
    228 
    229 	year = dt->dt_year - sc->sc_year0;
    230 	if (year > 99)
    231 		year -= 100;
    232 
    233 	year = bintobcd(year);
    234 
    235 	r = _reg_read_1(SH_(RCR2));
    236 
    237 	/* stop clock */
    238 	_reg_write_1(SH_(RCR2), (r & ~SH_RCR2_START) | SH_RCR2_RESET);
    239 
    240 	/* set time */
    241 	if (CPU_IS_SH3)
    242 		_reg_write_1(SH3_RYRCNT, year);
    243 	else
    244 		_reg_write_2(SH4_RYRCNT, year);
    245 
    246 #define	RTCSET(x, y) \
    247 	_reg_write_1(SH_(R ## x ## CNT), bintobcd(dt->dt_ ## y))
    248 
    249 	RTCSET(MON, mon);
    250 	RTCSET(WK, wday);
    251 	RTCSET(DAY, day);
    252 	RTCSET(HR, hour);
    253 	RTCSET(MIN, min);
    254 	RTCSET(SEC, sec);
    255 
    256 #undef RTCSET
    257 
    258 	/* start clock */
    259 	_reg_write_1(SH_(RCR2), r);
    260 	sc->sc_valid = 1;
    261 
    262 #ifdef RTC_DEBUG
    263 	aprint_debug_dev(sc->sc_dev,
    264 			 "settime: %04lu-%02d-%02d %02d:%02d:%02d\n",
    265 			 (unsigned long)dt->dt_year, dt->dt_mon, dt->dt_day,
    266 			 dt->dt_hour, dt->dt_min, dt->dt_sec);
    267 #endif
    268 
    269 	return 0;
    270 }
    271