1 /* $NetBSD: rtclock.c,v 1.5 1999/03/24 14:07:39 minoura Exp $ */ 2 3 /* 4 * Copyright 1993, 1994 Masaru Oki 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Masaru Oki. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * X680x0 internal real time clock interface 35 * alarm is not supported. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/buf.h> 41 #include <sys/malloc.h> 42 #include <sys/proc.h> 43 #include <sys/reboot.h> 44 #include <sys/file.h> 45 #include <sys/kernel.h> 46 #include <sys/device.h> 47 48 #include <machine/bus.h> 49 50 #include <arch/x68k/dev/rtclock_var.h> 51 #include <arch/x68k/dev/intiovar.h> 52 53 static u_long rtgettod __P((void)); 54 static int rtsettod __P((long)); 55 56 static int rtc_match __P((struct device *, struct cfdata *, void *)); 57 static void rtc_attach __P((struct device *, struct device *, void *)); 58 59 int rtclockinit __P((void)); 60 61 struct cfattach rtc_ca = { 62 sizeof(struct rtc_softc), rtc_match, rtc_attach 63 }; 64 65 static int 66 rtc_match(parent, cf, aux) 67 struct device *parent; 68 struct cfdata *cf; 69 void *aux; 70 { 71 struct intio_attach_args *ia = aux; 72 73 if (strcmp (ia->ia_name, "rtc") != 0) 74 return (0); 75 if (cf->cf_unit != 0) 76 return (0); 77 78 /* fixed address */ 79 if (ia->ia_addr != RTC_ADDR) 80 return (0); 81 if (ia->ia_intr != -1) 82 return (0); 83 84 return (1); 85 } 86 87 88 static struct rtc_softc *rtc; /* XXX: softc cache */ 89 90 static void 91 rtc_attach(parent, self, aux) 92 struct device *parent, *self; 93 void *aux; 94 { 95 struct rtc_softc *sc = (struct rtc_softc *)self; 96 struct intio_attach_args *ia = aux; 97 int r; 98 99 ia->ia_size = 0x20; 100 r = intio_map_allocate_region (parent, ia, INTIO_MAP_ALLOCATE); 101 #ifdef DIAGNOSTIC 102 if (r) 103 panic ("IO map for RTC corruption??"); 104 #endif 105 106 107 sc->sc_bst = ia->ia_bst; 108 bus_space_map(sc->sc_bst, ia->ia_addr, 0x2000, 0, &sc->sc_bht); 109 rtc = sc; 110 111 rtclockinit(); 112 printf (": RP5C15\n"); 113 } 114 115 116 117 /* 118 * x68k/clock.c calls thru this vector, if it is set, to read 119 * the realtime clock. 120 */ 121 u_long (*gettod) __P((void)); 122 int (*settod) __P((long)); 123 124 int 125 rtclockinit() 126 { 127 if (rtgettod()) { 128 gettod = rtgettod; 129 settod = rtsettod; 130 } else { 131 return 0; 132 } 133 return 1; 134 } 135 136 static int month_days[12] = { 137 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 138 }; 139 140 static u_long 141 rtgettod() 142 { 143 register int i; 144 register u_long tmp; 145 int year, month, day, hour, min, sec; 146 147 /* hold clock */ 148 RTC_WRITE(RTC_MODE, RTC_HOLD_CLOCK); 149 150 /* read it */ 151 sec = RTC_REG(RTC_SEC10) * 10 + RTC_REG(RTC_SEC); 152 min = RTC_REG(RTC_MIN10) * 10 + RTC_REG(RTC_MIN); 153 hour = RTC_REG(RTC_HOUR10) * 10 + RTC_REG(RTC_HOUR); 154 day = RTC_REG(RTC_DAY10) * 10 + RTC_REG(RTC_DAY); 155 month = RTC_REG(RTC_MON10) * 10 + RTC_REG(RTC_MON); 156 year = RTC_REG(RTC_YEAR10) * 10 + RTC_REG(RTC_YEAR) + 1980; 157 158 /* let it run again.. */ 159 RTC_WRITE(RTC_MODE, RTC_FREE_CLOCK); 160 161 range_test(hour, 0, 23); 162 range_test(day, 1, 31); 163 range_test(month, 1, 12); 164 range_test(year, STARTOFTIME, 2000); 165 166 tmp = 0; 167 168 for (i = STARTOFTIME; i < year; i++) 169 tmp += days_in_year(i); 170 if (leapyear(year) && month > FEBRUARY) 171 tmp++; 172 173 for (i = 1; i < month; i++) 174 tmp += days_in_month(i); 175 176 tmp += (day - 1); 177 178 tmp = ((tmp * 24 + hour) * 60 + min + rtc_offset) * 60 + sec; 179 180 return tmp; 181 } 182 183 static int 184 rtsettod (tim) 185 long tim; 186 { 187 /* 188 * I don't know if setting the clock is analogous 189 * to reading it, I don't have demo-code for setting. 190 * just give it a try.. 191 */ 192 register int i; 193 register long hms, day; 194 u_char sec1, sec2; 195 u_char min1, min2; 196 u_char hour1, hour2; 197 u_char day1, day2; 198 u_char mon1, mon2; 199 u_char year1, year2; 200 201 tim -= (rtc_offset * 60); 202 203 /* prepare values to be written to clock */ 204 day = tim / SECDAY; 205 hms = tim % SECDAY; 206 207 hour2 = hms / 3600; 208 hour1 = hour2 / 10; 209 hour2 %= 10; 210 211 min2 = (hms % 3600) / 60; 212 min1 = min2 / 10; 213 min2 %= 10; 214 215 sec2 = (hms % 3600) % 60; 216 sec1 = sec2 / 10; 217 sec2 %= 10; 218 219 /* Number of years in days */ 220 for (i = STARTOFTIME - 1980; day >= days_in_year(i); i++) 221 day -= days_in_year(i); 222 year1 = i / 10; 223 year2 = i % 10; 224 225 /* Number of months in days left */ 226 if (leapyear(i)) 227 days_in_month(FEBRUARY) = 29; 228 for (i = 1; day >= days_in_month(i); i++) 229 day -= days_in_month(i); 230 days_in_month(FEBRUARY) = 28; 231 232 mon1 = i / 10; 233 mon2 = i % 10; 234 235 /* Days are what is left over (+1) from all that. */ 236 day ++; 237 day1 = day / 10; 238 day2 = day % 10; 239 240 RTC_WRITE(RTC_MODE, RTC_HOLD_CLOCK); 241 RTC_WRITE(RTC_SEC10, sec1); 242 RTC_WRITE(RTC_SEC, sec2); 243 RTC_WRITE(RTC_MIN10, min1); 244 RTC_WRITE(RTC_MIN, min2); 245 RTC_WRITE(RTC_HOUR10, hour1); 246 RTC_WRITE(RTC_HOUR, hour2); 247 RTC_WRITE(RTC_DAY10, day1); 248 RTC_WRITE(RTC_DAY, day2); 249 RTC_WRITE(RTC_MON10, mon1); 250 RTC_WRITE(RTC_MON, mon2); 251 RTC_WRITE(RTC_YEAR10, year1); 252 RTC_WRITE(RTC_YEAR, year2); 253 RTC_WRITE(RTC_MODE, RTC_FREE_CLOCK); 254 255 return 1; 256 } 257