dsrtc.c revision 1.14 1 /* $NetBSD: dsrtc.c,v 1.14 2025/09/07 21:45:11 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1998 Mark Brinicombe.
5 * Copyright (c) 1998 Causality Limited.
6 * All rights reserved.
7 *
8 * Written by Mark Brinicombe, Causality Limited
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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Mark Brinicombe
21 * for the NetBSD Project.
22 * 4. The name of the company nor the name of the author may be used to
23 * endorse or promote products derived from this software without specific
24 * prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY CAUASLITY LIMITED ``AS IS'' AND ANY EXPRESS
27 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: dsrtc.c,v 1.14 2025/09/07 21:45:11 thorpej Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/conf.h>
46 #include <sys/device.h>
47
48 #include <dev/clock_subr.h>
49 #include <arm/footbridge/isa/ds1687reg.h>
50
51 #include <dev/isa/isavar.h>
52
53 #define NRTC_PORTS 2
54
55 struct dsrtc_softc {
56 device_t sc_dev;
57 bus_space_tag_t sc_iot;
58 bus_space_handle_t sc_ioh;
59 struct todr_chip_handle sc_todr;
60 };
61
62 void dsrtcattach(device_t parent, device_t self, void *aux);
63 int dsrtcmatch(device_t parent, cfdata_t cf, void *aux);
64 int ds1687_read(struct dsrtc_softc *sc, int addr);
65 void ds1687_write(struct dsrtc_softc *sc, int addr, int data);
66 #if 0
67 int ds1687_ram_read(struct dsrtc_softc *sc, int addr);
68 void ds1687_ram_write(struct dsrtc_softc *sc, int addr, int data);
69 #endif
70 static void ds1687_bank_select(struct dsrtc_softc *, int);
71 static int dsrtc_write(todr_chip_handle_t, struct clock_ymdhms *);
72 static int dsrtc_read(todr_chip_handle_t, struct clock_ymdhms *);
73
74 int
75 ds1687_read(struct dsrtc_softc *sc, int addr)
76 {
77
78 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr);
79 return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG));
80 }
81
82 void
83 ds1687_write(struct dsrtc_softc *sc, int addr, int data)
84 {
85
86 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr);
87 bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG, data);
88 }
89
90 static void
91 ds1687_bank_select(struct dsrtc_softc *sc, int bank)
92 {
93 int data;
94
95 data = ds1687_read(sc, RTC_REG_A);
96 data &= ~RTC_REG_A_BANK_MASK;
97 if (bank)
98 data |= RTC_REG_A_BANK1;
99 ds1687_write(sc, RTC_REG_A, data);
100 }
101
102 #if 0
103 /* Nothing uses these yet */
104 int
105 ds1687_ram_read(struct dsrtc_softc *sc, int addr)
106 {
107 if (addr < RTC_PC_RAM_SIZE)
108 return(ds1687_read(sc, RTC_PC_RAM_START + addr));
109
110 addr -= RTC_PC_RAM_SIZE;
111 if (addr < RTC_BANK0_RAM_SIZE)
112 return(ds1687_read(sc, RTC_BANK0_RAM_START + addr));
113
114 addr -= RTC_BANK0_RAM_SIZE;
115 if (addr < RTC_EXT_RAM_SIZE) {
116 int data;
117
118 ds1687_bank_select(sc, 1);
119 ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr);
120 data = ds1687_read(sc, RTC_EXT_RAM_DATA);
121 ds1687_bank_select(sc, 0);
122 return(data);
123 }
124 return(-1);
125 }
126
127 void
128 ds1687_ram_write(struct dsrtc_softc *sc, int addr, int val)
129 {
130 if (addr < RTC_PC_RAM_SIZE)
131 return(ds1687_write(sc, RTC_PC_RAM_START + addr, val));
132
133 addr -= RTC_PC_RAM_SIZE;
134 if (addr < RTC_BANK0_RAM_SIZE)
135 return(ds1687_write(sc, RTC_BANK0_RAM_START + addr, val));
136
137 addr -= RTC_BANK0_RAM_SIZE;
138 if (addr < RTC_EXT_RAM_SIZE) {
139 ds1687_bank_select(sc, 1);
140 ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr);
141 ds1687_write(sc, RTC_EXT_RAM_DATA, val);
142 ds1687_bank_select(sc, 0);
143 }
144 }
145 #endif
146
147 static int
148 dsrtc_write(todr_chip_handle_t tc, struct clock_ymdhms *dt)
149 {
150 struct dsrtc_softc *sc = device_private(tc->todr_dev);
151
152 ds1687_write(sc, RTC_SECONDS, dt->dt_sec);
153 ds1687_write(sc, RTC_MINUTES, dt->dt_min);
154 ds1687_write(sc, RTC_HOURS, dt->dt_hour);
155 ds1687_write(sc, RTC_DAYOFMONTH, dt->dt_day);
156 ds1687_write(sc, RTC_MONTH, dt->dt_mon);
157 ds1687_write(sc, RTC_YEAR, dt->dt_year % 100);
158 ds1687_bank_select(sc, 1);
159 ds1687_write(sc, RTC_CENTURY, dt->dt_year / 100);
160 ds1687_bank_select(sc, 0);
161 return(0);
162 }
163
164 static int
165 dsrtc_read(todr_chip_handle_t tc, struct clock_ymdhms *dt)
166 {
167 struct dsrtc_softc *sc = device_private(tc->todr_dev);
168
169 dt->dt_sec = ds1687_read(sc, RTC_SECONDS);
170 dt->dt_min = ds1687_read(sc, RTC_MINUTES);
171 dt->dt_hour = ds1687_read(sc, RTC_HOURS);
172 dt->dt_day = ds1687_read(sc, RTC_DAYOFMONTH);
173 dt->dt_mon = ds1687_read(sc, RTC_MONTH);
174 dt->dt_year = ds1687_read(sc, RTC_YEAR);
175 ds1687_bank_select(sc, 1);
176 dt->dt_year += ds1687_read(sc, RTC_CENTURY) * 100;
177 ds1687_bank_select(sc, 0);
178
179 return(0);
180 }
181
182 /* device and attach structures */
183 CFATTACH_DECL_NEW(ds1687rtc, sizeof(struct dsrtc_softc),
184 dsrtcmatch, dsrtcattach, NULL, NULL);
185
186 /*
187 * dsrtcmatch()
188 *
189 * Validate the IIC address to make sure its an RTC we understand
190 */
191
192 int
193 dsrtcmatch(device_t parent, cfdata_t cf, void *aux)
194 {
195 struct isa_attach_args *ia = aux;
196
197 if (ia->ia_nio < 1 ||
198 ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
199 return (0);
200
201 ia->ia_nio = 1;
202 ia->ia_io[0].ir_size = NRTC_PORTS;
203
204 ia->ia_niomem = 0;
205 ia->ia_nirq = 0;
206 ia->ia_ndrq = 0;
207
208 return(1);
209 }
210
211 /*
212 * dsrtcattach()
213 *
214 * Attach the rtc device
215 */
216
217 void
218 dsrtcattach(device_t parent, device_t self, void *aux)
219 {
220 struct dsrtc_softc *sc = device_private(self);
221 struct isa_attach_args *ia = aux;
222
223 sc->sc_dev = self;
224 sc->sc_iot = ia->ia_iot;
225 if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr,
226 ia->ia_io[0].ir_size, 0, &sc->sc_ioh)) {
227 aprint_error(": cannot map I/O space\n");
228 return;
229 }
230
231 ds1687_write(sc, RTC_REG_A, RTC_REG_A_DV1);
232 ds1687_write(sc, RTC_REG_B, RTC_REG_B_BINARY | RTC_REG_B_24_HOUR);
233
234 if (!(ds1687_read(sc, RTC_REG_D) & RTC_REG_D_VRT))
235 aprint_error(": lithium cell is dead, RTC unreliable");
236 aprint_normal("\n");
237
238 sc->sc_todr.todr_gettime_ymdhms = dsrtc_read;
239 sc->sc_todr.todr_settime_ymdhms = dsrtc_write;
240 sc->sc_todr.todr_dev = self;
241 todr_attach(&sc->sc_todr);
242 }
243
244 /* End of dsrtc.c */
245