1 /* $NetBSD: mcclock.c,v 1.15 2001/12/05 10:54:51 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: mcclock.c,v 1.15 2001/12/05 10:54:51 simonb Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/systm.h> 36 #include <sys/device.h> 37 38 #include <dev/dec/clockvar.h> 39 #include <dev/dec/mcclockvar.h> 40 #include <dev/ic/mc146818reg.h> 41 42 /* 43 * XXX default rate is machine-dependent. 44 */ 45 #ifdef __alpha__ 46 #define MC_DFEAULTHZ 1024 47 #endif 48 #ifdef pmax 49 #define MC_DEFAULTHZ 256 50 #endif 51 52 53 void mcclock_init __P((struct device *)); 54 void mcclock_get __P((struct device *, time_t, struct clocktime *)); 55 void mcclock_set __P((struct device *, struct clocktime *)); 56 57 const struct clockfns mcclock_clockfns = { 58 mcclock_init, mcclock_get, mcclock_set, 59 }; 60 61 #define mc146818_write(dev, reg, datum) \ 62 (*(dev)->sc_busfns->mc_bf_write)(dev, reg, datum) 63 #define mc146818_read(dev, reg) \ 64 (*(dev)->sc_busfns->mc_bf_read)(dev, reg) 65 66 void 67 mcclock_attach(sc, busfns) 68 struct mcclock_softc *sc; 69 const struct mcclock_busfns *busfns; 70 { 71 72 printf(": mc146818 or compatible"); 73 74 sc->sc_busfns = busfns; 75 76 /* Turn interrupts off, just in case. */ 77 mc146818_write(sc, MC_REGB, MC_REGB_BINARY | MC_REGB_24HR); 78 79 clockattach(&sc->sc_dev, &mcclock_clockfns); 80 } 81 82 void 83 mcclock_init(dev) 84 struct device *dev; 85 { 86 struct mcclock_softc *sc = (struct mcclock_softc *)dev; 87 int rate; 88 89 again: 90 switch (hz) { 91 case 32: 92 rate = MC_BASE_32_KHz | MC_RATE_32_Hz; 93 break; 94 case 64: 95 rate = MC_BASE_32_KHz | MC_RATE_64_Hz; 96 break; 97 case 128: 98 rate = MC_BASE_32_KHz | MC_RATE_128_Hz; 99 break; 100 case 256: 101 rate = MC_BASE_32_KHz | MC_RATE_256_Hz; 102 break; 103 case 512: 104 rate = MC_BASE_32_KHz | MC_RATE_512_Hz; 105 break; 106 case 1024: 107 rate = MC_BASE_32_KHz | MC_RATE_1024_Hz; 108 break; 109 case 2048: 110 rate = MC_BASE_32_KHz | MC_RATE_2048_Hz; 111 break; 112 case 4096: 113 rate = MC_BASE_32_KHz | MC_RATE_4096_Hz; 114 break; 115 case 8192: 116 rate = MC_BASE_32_KHz | MC_RATE_8192_Hz; 117 break; 118 case 16384: 119 rate = MC_BASE_4_MHz | MC_RATE_1; 120 break; 121 case 32768: 122 rate = MC_BASE_4_MHz | MC_RATE_2; 123 break; 124 default: 125 printf("%s: Cannot get %d Hz clock; using %d Hz\n", 126 sc->sc_dev.dv_xname, hz, MC_DEFAULTHZ); 127 hz = MC_DEFAULTHZ; 128 goto again; 129 } 130 mc146818_write(sc, MC_REGA, rate); 131 mc146818_write(sc, MC_REGB, 132 MC_REGB_PIE | MC_REGB_SQWE | MC_REGB_BINARY | MC_REGB_24HR); 133 } 134 135 /* 136 * Get the time of day, based on the clock's value and/or the base value. 137 */ 138 void 139 mcclock_get(dev, base, ct) 140 struct device *dev; 141 time_t base; 142 struct clocktime *ct; 143 { 144 struct mcclock_softc *sc = (struct mcclock_softc *)dev; 145 mc_todregs regs; 146 int s; 147 148 s = splclock(); 149 MC146818_GETTOD(sc, ®s) 150 splx(s); 151 152 ct->sec = regs[MC_SEC]; 153 ct->min = regs[MC_MIN]; 154 ct->hour = regs[MC_HOUR]; 155 ct->dow = regs[MC_DOW]; 156 ct->day = regs[MC_DOM]; 157 ct->mon = regs[MC_MONTH]; 158 ct->year = regs[MC_YEAR]; 159 } 160 161 /* 162 * Reset the TODR based on the time value. 163 */ 164 void 165 mcclock_set(dev, ct) 166 struct device *dev; 167 struct clocktime *ct; 168 { 169 struct mcclock_softc *sc = (struct mcclock_softc *)dev; 170 mc_todregs regs; 171 int s; 172 173 s = splclock(); 174 MC146818_GETTOD(sc, ®s); 175 splx(s); 176 177 regs[MC_SEC] = ct->sec; 178 regs[MC_MIN] = ct->min; 179 regs[MC_HOUR] = ct->hour; 180 regs[MC_DOW] = ct->dow; 181 regs[MC_DOM] = ct->day; 182 regs[MC_MONTH] = ct->mon; 183 regs[MC_YEAR] = ct->year; 184 185 s = splclock(); 186 MC146818_PUTTOD(sc, ®s); 187 splx(s); 188 } 189