1*77e75c28Sskrll /* $NetBSD: dsrtc.c,v 1.13 2021/08/13 11:40:43 skrll Exp $ */
2a73dabb4Schris
3a73dabb4Schris /*
4a73dabb4Schris * Copyright (c) 1998 Mark Brinicombe.
5a73dabb4Schris * Copyright (c) 1998 Causality Limited.
6a73dabb4Schris * All rights reserved.
7a73dabb4Schris *
8a73dabb4Schris * Written by Mark Brinicombe, Causality Limited
9a73dabb4Schris *
10a73dabb4Schris * Redistribution and use in source and binary forms, with or without
11a73dabb4Schris * modification, are permitted provided that the following conditions
12a73dabb4Schris * are met:
13a73dabb4Schris * 1. Redistributions of source code must retain the above copyright
14a73dabb4Schris * notice, this list of conditions and the following disclaimer.
15a73dabb4Schris * 2. Redistributions in binary form must reproduce the above copyright
16a73dabb4Schris * notice, this list of conditions and the following disclaimer in the
17a73dabb4Schris * documentation and/or other materials provided with the distribution.
18a73dabb4Schris * 3. All advertising materials mentioning features or use of this software
19a73dabb4Schris * must display the following acknowledgement:
20a73dabb4Schris * This product includes software developed by Mark Brinicombe
21a73dabb4Schris * for the NetBSD Project.
22a73dabb4Schris * 4. The name of the company nor the name of the author may be used to
23a73dabb4Schris * endorse or promote products derived from this software without specific
24a73dabb4Schris * prior written permission.
25a73dabb4Schris *
26a73dabb4Schris * THIS SOFTWARE IS PROVIDED BY CAUASLITY LIMITED ``AS IS'' AND ANY EXPRESS
27a73dabb4Schris * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28a73dabb4Schris * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29a73dabb4Schris * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED OR CONTRIBUTORS BE LIABLE
30a73dabb4Schris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31a73dabb4Schris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32a73dabb4Schris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33a73dabb4Schris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34a73dabb4Schris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35a73dabb4Schris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36a73dabb4Schris * SUCH DAMAGE.
37a73dabb4Schris */
38a73dabb4Schris
399fd86b68Schris #include <sys/cdefs.h>
40*77e75c28Sskrll __KERNEL_RCSID(0, "$NetBSD: dsrtc.c,v 1.13 2021/08/13 11:40:43 skrll Exp $");
419fd86b68Schris
42a73dabb4Schris #include <sys/param.h>
43a73dabb4Schris #include <sys/systm.h>
44a73dabb4Schris #include <sys/kernel.h>
45a73dabb4Schris #include <sys/conf.h>
46a73dabb4Schris #include <sys/device.h>
47a73dabb4Schris
48467eaaa9Schristos #include <dev/clock_subr.h>
49a73dabb4Schris #include <arm/footbridge/isa/ds1687reg.h>
50a73dabb4Schris
51a73dabb4Schris #include <dev/isa/isavar.h>
52a73dabb4Schris
53a73dabb4Schris #define NRTC_PORTS 2
54a73dabb4Schris
55a73dabb4Schris struct dsrtc_softc {
56a73dabb4Schris bus_space_tag_t sc_iot;
57a73dabb4Schris bus_space_handle_t sc_ioh;
58467eaaa9Schristos struct todr_chip_handle sc_todr;
59a73dabb4Schris };
60a73dabb4Schris
61f037af89Sskrll void dsrtcattach(device_t parent, device_t self, void *aux);
62f037af89Sskrll int dsrtcmatch(device_t parent, cfdata_t cf, void *aux);
63f475d69bSgdamore int ds1687_read(struct dsrtc_softc *sc, int addr);
64f475d69bSgdamore void ds1687_write(struct dsrtc_softc *sc, int addr, int data);
65f475d69bSgdamore #if 0
66f475d69bSgdamore int ds1687_ram_read(struct dsrtc_softc *sc, int addr);
67f475d69bSgdamore void ds1687_ram_write(struct dsrtc_softc *sc, int addr, int data);
68f475d69bSgdamore #endif
69f475d69bSgdamore static void ds1687_bank_select(struct dsrtc_softc *, int);
70467eaaa9Schristos static int dsrtc_write(todr_chip_handle_t, struct clock_ymdhms *);
71467eaaa9Schristos static int dsrtc_read(todr_chip_handle_t, struct clock_ymdhms *);
72a73dabb4Schris
73a73dabb4Schris int
ds1687_read(struct dsrtc_softc * sc,int addr)74f475d69bSgdamore ds1687_read(struct dsrtc_softc *sc, int addr)
75a73dabb4Schris {
76a73dabb4Schris
77a73dabb4Schris bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr);
78a73dabb4Schris return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG));
79a73dabb4Schris }
80a73dabb4Schris
81a73dabb4Schris void
ds1687_write(struct dsrtc_softc * sc,int addr,int data)82f475d69bSgdamore ds1687_write(struct dsrtc_softc *sc, int addr, int data)
83a73dabb4Schris {
84a73dabb4Schris
85a73dabb4Schris bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr);
86a73dabb4Schris bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG, data);
87a73dabb4Schris }
88a73dabb4Schris
89a73dabb4Schris static void
ds1687_bank_select(struct dsrtc_softc * sc,int bank)90f475d69bSgdamore ds1687_bank_select(struct dsrtc_softc *sc, int bank)
91a73dabb4Schris {
92a73dabb4Schris int data;
93a73dabb4Schris
94a73dabb4Schris data = ds1687_read(sc, RTC_REG_A);
95a73dabb4Schris data &= ~RTC_REG_A_BANK_MASK;
96a73dabb4Schris if (bank)
97a73dabb4Schris data |= RTC_REG_A_BANK1;
98a73dabb4Schris ds1687_write(sc, RTC_REG_A, data);
99a73dabb4Schris }
100a73dabb4Schris
101a73dabb4Schris #if 0
102a73dabb4Schris /* Nothing uses these yet */
103a73dabb4Schris int
104f475d69bSgdamore ds1687_ram_read(struct dsrtc_softc *sc, int addr)
105a73dabb4Schris {
106a73dabb4Schris if (addr < RTC_PC_RAM_SIZE)
107a73dabb4Schris return(ds1687_read(sc, RTC_PC_RAM_START + addr));
108a73dabb4Schris
109a73dabb4Schris addr -= RTC_PC_RAM_SIZE;
110a73dabb4Schris if (addr < RTC_BANK0_RAM_SIZE)
111a73dabb4Schris return(ds1687_read(sc, RTC_BANK0_RAM_START + addr));
112a73dabb4Schris
113a73dabb4Schris addr -= RTC_BANK0_RAM_SIZE;
114a73dabb4Schris if (addr < RTC_EXT_RAM_SIZE) {
115a73dabb4Schris int data;
116a73dabb4Schris
117a73dabb4Schris ds1687_bank_select(sc, 1);
118a73dabb4Schris ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr);
119a73dabb4Schris data = ds1687_read(sc, RTC_EXT_RAM_DATA);
120a73dabb4Schris ds1687_bank_select(sc, 0);
121a73dabb4Schris return(data);
122a73dabb4Schris }
123a73dabb4Schris return(-1);
124a73dabb4Schris }
125a73dabb4Schris
126a73dabb4Schris void
127f475d69bSgdamore ds1687_ram_write(struct dsrtc_softc *sc, int addr, int val)
128a73dabb4Schris {
129a73dabb4Schris if (addr < RTC_PC_RAM_SIZE)
130a73dabb4Schris return(ds1687_write(sc, RTC_PC_RAM_START + addr, val));
131a73dabb4Schris
132a73dabb4Schris addr -= RTC_PC_RAM_SIZE;
133a73dabb4Schris if (addr < RTC_BANK0_RAM_SIZE)
134a73dabb4Schris return(ds1687_write(sc, RTC_BANK0_RAM_START + addr, val));
135a73dabb4Schris
136a73dabb4Schris addr -= RTC_BANK0_RAM_SIZE;
137a73dabb4Schris if (addr < RTC_EXT_RAM_SIZE) {
138a73dabb4Schris ds1687_bank_select(sc, 1);
139a73dabb4Schris ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr);
140a73dabb4Schris ds1687_write(sc, RTC_EXT_RAM_DATA, val);
141a73dabb4Schris ds1687_bank_select(sc, 0);
142a73dabb4Schris }
143a73dabb4Schris }
144a73dabb4Schris #endif
145a73dabb4Schris
146a73dabb4Schris static int
dsrtc_write(todr_chip_handle_t tc,struct clock_ymdhms * dt)147467eaaa9Schristos dsrtc_write(todr_chip_handle_t tc, struct clock_ymdhms *dt)
148a73dabb4Schris {
149467eaaa9Schristos struct dsrtc_softc *sc = tc->cookie;
150a73dabb4Schris
151467eaaa9Schristos ds1687_write(sc, RTC_SECONDS, dt->dt_sec);
152467eaaa9Schristos ds1687_write(sc, RTC_MINUTES, dt->dt_min);
153467eaaa9Schristos ds1687_write(sc, RTC_HOURS, dt->dt_hour);
154467eaaa9Schristos ds1687_write(sc, RTC_DAYOFMONTH, dt->dt_day);
155467eaaa9Schristos ds1687_write(sc, RTC_MONTH, dt->dt_mon);
156467eaaa9Schristos ds1687_write(sc, RTC_YEAR, dt->dt_year % 100);
157a73dabb4Schris ds1687_bank_select(sc, 1);
158467eaaa9Schristos ds1687_write(sc, RTC_CENTURY, dt->dt_year / 100);
159a73dabb4Schris ds1687_bank_select(sc, 0);
160467eaaa9Schristos return(0);
161a73dabb4Schris }
162a73dabb4Schris
163a73dabb4Schris static int
dsrtc_read(todr_chip_handle_t tc,struct clock_ymdhms * dt)164467eaaa9Schristos dsrtc_read(todr_chip_handle_t tc, struct clock_ymdhms *dt)
165a73dabb4Schris {
166467eaaa9Schristos struct dsrtc_softc *sc = tc->cookie;
167a73dabb4Schris
168467eaaa9Schristos dt->dt_sec = ds1687_read(sc, RTC_SECONDS);
169467eaaa9Schristos dt->dt_min = ds1687_read(sc, RTC_MINUTES);
170467eaaa9Schristos dt->dt_hour = ds1687_read(sc, RTC_HOURS);
171467eaaa9Schristos dt->dt_day = ds1687_read(sc, RTC_DAYOFMONTH);
172467eaaa9Schristos dt->dt_mon = ds1687_read(sc, RTC_MONTH);
173467eaaa9Schristos dt->dt_year = ds1687_read(sc, RTC_YEAR);
174a73dabb4Schris ds1687_bank_select(sc, 1);
175467eaaa9Schristos dt->dt_year += ds1687_read(sc, RTC_CENTURY) * 100;
176a73dabb4Schris ds1687_bank_select(sc, 0);
177a73dabb4Schris
178467eaaa9Schristos return(0);
179a73dabb4Schris }
180a73dabb4Schris
181a73dabb4Schris /* device and attach structures */
1829cbe4c86Sskrll CFATTACH_DECL_NEW(ds1687rtc, sizeof(struct dsrtc_softc),
183bd5bb465Sthorpej dsrtcmatch, dsrtcattach, NULL, NULL);
184a73dabb4Schris
185a73dabb4Schris /*
186a73dabb4Schris * dsrtcmatch()
187a73dabb4Schris *
188a73dabb4Schris * Validate the IIC address to make sure its an RTC we understand
189a73dabb4Schris */
190a73dabb4Schris
191a73dabb4Schris int
dsrtcmatch(device_t parent,cfdata_t cf,void * aux)1929cbe4c86Sskrll dsrtcmatch(device_t parent, cfdata_t cf, void *aux)
193a73dabb4Schris {
194a73dabb4Schris struct isa_attach_args *ia = aux;
195a73dabb4Schris
196a73dabb4Schris if (ia->ia_nio < 1 ||
197ea827e51Sdrochner ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
198a73dabb4Schris return (0);
199a73dabb4Schris
200a73dabb4Schris ia->ia_nio = 1;
201a73dabb4Schris ia->ia_io[0].ir_size = NRTC_PORTS;
202a73dabb4Schris
203a73dabb4Schris ia->ia_niomem = 0;
204a73dabb4Schris ia->ia_nirq = 0;
205a73dabb4Schris ia->ia_ndrq = 0;
206a73dabb4Schris
207a73dabb4Schris return(1);
208a73dabb4Schris }
209a73dabb4Schris
210a73dabb4Schris /*
211a73dabb4Schris * dsrtcattach()
212a73dabb4Schris *
213a73dabb4Schris * Attach the rtc device
214a73dabb4Schris */
215a73dabb4Schris
216a73dabb4Schris void
dsrtcattach(device_t parent,device_t self,void * aux)2179cbe4c86Sskrll dsrtcattach(device_t parent, device_t self, void *aux)
218a73dabb4Schris {
2199cbe4c86Sskrll struct dsrtc_softc *sc = device_private(self);
220a73dabb4Schris struct isa_attach_args *ia = aux;
221a73dabb4Schris
222a73dabb4Schris sc->sc_iot = ia->ia_iot;
223a73dabb4Schris if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr,
224a73dabb4Schris ia->ia_io[0].ir_size, 0, &sc->sc_ioh)) {
2259cbe4c86Sskrll aprint_error(": cannot map I/O space\n");
226a73dabb4Schris return;
227a73dabb4Schris }
228a73dabb4Schris
229a73dabb4Schris ds1687_write(sc, RTC_REG_A, RTC_REG_A_DV1);
230a73dabb4Schris ds1687_write(sc, RTC_REG_B, RTC_REG_B_BINARY | RTC_REG_B_24_HOUR);
231a73dabb4Schris
232a73dabb4Schris if (!(ds1687_read(sc, RTC_REG_D) & RTC_REG_D_VRT))
2339cbe4c86Sskrll aprint_error(": lithium cell is dead, RTC unreliable");
2349cbe4c86Sskrll aprint_normal("\n");
235a73dabb4Schris
236467eaaa9Schristos sc->sc_todr.todr_gettime_ymdhms = dsrtc_read;
237467eaaa9Schristos sc->sc_todr.todr_settime_ymdhms = dsrtc_write;
238467eaaa9Schristos sc->sc_todr.cookie = sc;
239467eaaa9Schristos todr_attach(&sc->sc_todr);
240a73dabb4Schris }
241a73dabb4Schris
242a73dabb4Schris /* End of dsrtc.c */
243