1/*	$NetBSD: dsrtc.c,v 1.13 2021/08/13 11:40:43 skrll 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.13 2021/08/13 11:40:43 skrll 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
55struct dsrtc_softc {
56	bus_space_tag_t	sc_iot;
57	bus_space_handle_t sc_ioh;
58	struct todr_chip_handle sc_todr;
59};
60
61void dsrtcattach(device_t parent, device_t self, void *aux);
62int dsrtcmatch(device_t parent, cfdata_t cf, void *aux);
63int ds1687_read(struct dsrtc_softc *sc, int addr);
64void ds1687_write(struct dsrtc_softc *sc, int addr, int data);
65#if 0
66int ds1687_ram_read(struct dsrtc_softc *sc, int addr);
67void ds1687_ram_write(struct dsrtc_softc *sc, int addr, int data);
68#endif
69static void ds1687_bank_select(struct dsrtc_softc *, int);
70static int dsrtc_write(todr_chip_handle_t, struct clock_ymdhms *);
71static int dsrtc_read(todr_chip_handle_t, struct clock_ymdhms *);
72
73int
74ds1687_read(struct dsrtc_softc *sc, int addr)
75{
76
77	bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr);
78	return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG));
79}
80
81void
82ds1687_write(struct dsrtc_softc *sc, int addr, int data)
83{
84
85	bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr);
86	bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG, data);
87}
88
89static void
90ds1687_bank_select(struct dsrtc_softc *sc, int bank)
91{
92	int data;
93
94	data = ds1687_read(sc, RTC_REG_A);
95	data &= ~RTC_REG_A_BANK_MASK;
96	if (bank)
97		data |= RTC_REG_A_BANK1;
98	ds1687_write(sc, RTC_REG_A, data);
99}
100
101#if 0
102/* Nothing uses these yet */
103int
104ds1687_ram_read(struct dsrtc_softc *sc, int addr)
105{
106	if (addr < RTC_PC_RAM_SIZE)
107		return(ds1687_read(sc, RTC_PC_RAM_START + addr));
108
109	addr -= RTC_PC_RAM_SIZE;
110	if (addr < RTC_BANK0_RAM_SIZE)
111		return(ds1687_read(sc, RTC_BANK0_RAM_START + addr));
112
113	addr -= RTC_BANK0_RAM_SIZE;
114	if (addr < RTC_EXT_RAM_SIZE) {
115		int data;
116
117		ds1687_bank_select(sc, 1);
118		ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr);
119		data = ds1687_read(sc, RTC_EXT_RAM_DATA);
120		ds1687_bank_select(sc, 0);
121		return(data);
122	}
123	return(-1);
124}
125
126void
127ds1687_ram_write(struct dsrtc_softc *sc, int addr, int val)
128{
129	if (addr < RTC_PC_RAM_SIZE)
130		return(ds1687_write(sc, RTC_PC_RAM_START + addr, val));
131
132	addr -= RTC_PC_RAM_SIZE;
133	if (addr < RTC_BANK0_RAM_SIZE)
134		return(ds1687_write(sc, RTC_BANK0_RAM_START + addr, val));
135
136	addr -= RTC_BANK0_RAM_SIZE;
137	if (addr < RTC_EXT_RAM_SIZE) {
138		ds1687_bank_select(sc, 1);
139		ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr);
140		ds1687_write(sc, RTC_EXT_RAM_DATA, val);
141		ds1687_bank_select(sc, 0);
142	}
143}
144#endif
145
146static int
147dsrtc_write(todr_chip_handle_t tc, struct clock_ymdhms *dt)
148{
149	struct dsrtc_softc *sc = tc->cookie;
150
151	ds1687_write(sc, RTC_SECONDS, dt->dt_sec);
152	ds1687_write(sc, RTC_MINUTES, dt->dt_min);
153	ds1687_write(sc, RTC_HOURS, dt->dt_hour);
154	ds1687_write(sc, RTC_DAYOFMONTH, dt->dt_day);
155	ds1687_write(sc, RTC_MONTH, dt->dt_mon);
156	ds1687_write(sc, RTC_YEAR, dt->dt_year % 100);
157	ds1687_bank_select(sc, 1);
158	ds1687_write(sc, RTC_CENTURY, dt->dt_year / 100);
159	ds1687_bank_select(sc, 0);
160	return(0);
161}
162
163static int
164dsrtc_read(todr_chip_handle_t tc, struct clock_ymdhms *dt)
165{
166	struct dsrtc_softc *sc = tc->cookie;
167
168	dt->dt_sec   = ds1687_read(sc, RTC_SECONDS);
169	dt->dt_min   = ds1687_read(sc, RTC_MINUTES);
170	dt->dt_hour  = ds1687_read(sc, RTC_HOURS);
171	dt->dt_day   = ds1687_read(sc, RTC_DAYOFMONTH);
172	dt->dt_mon   = ds1687_read(sc, RTC_MONTH);
173	dt->dt_year  = ds1687_read(sc, RTC_YEAR);
174	ds1687_bank_select(sc, 1);
175	dt->dt_year  += ds1687_read(sc, RTC_CENTURY) * 100;
176	ds1687_bank_select(sc, 0);
177
178	return(0);
179}
180
181/* device and attach structures */
182CFATTACH_DECL_NEW(ds1687rtc, sizeof(struct dsrtc_softc),
183    dsrtcmatch, dsrtcattach, NULL, NULL);
184
185/*
186 * dsrtcmatch()
187 *
188 * Validate the IIC address to make sure its an RTC we understand
189 */
190
191int
192dsrtcmatch(device_t parent, cfdata_t cf, void *aux)
193{
194	struct isa_attach_args *ia = aux;
195
196	if (ia->ia_nio < 1 ||
197	    ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
198		return (0);
199
200	ia->ia_nio = 1;
201	ia->ia_io[0].ir_size = NRTC_PORTS;
202
203	ia->ia_niomem = 0;
204	ia->ia_nirq = 0;
205	ia->ia_ndrq = 0;
206
207	return(1);
208}
209
210/*
211 * dsrtcattach()
212 *
213 * Attach the rtc device
214 */
215
216void
217dsrtcattach(device_t parent, device_t self, void *aux)
218{
219	struct dsrtc_softc *sc = device_private(self);
220	struct isa_attach_args *ia = aux;
221
222	sc->sc_iot = ia->ia_iot;
223	if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr,
224	    ia->ia_io[0].ir_size, 0, &sc->sc_ioh)) {
225		aprint_error(": cannot map I/O space\n");
226		return;
227	}
228
229	ds1687_write(sc, RTC_REG_A, RTC_REG_A_DV1);
230	ds1687_write(sc, RTC_REG_B, RTC_REG_B_BINARY | RTC_REG_B_24_HOUR);
231
232	if (!(ds1687_read(sc, RTC_REG_D) & RTC_REG_D_VRT))
233		aprint_error(": lithium cell is dead, RTC unreliable");
234	aprint_normal("\n");
235
236	sc->sc_todr.todr_gettime_ymdhms = dsrtc_read;
237	sc->sc_todr.todr_settime_ymdhms = dsrtc_write;
238	sc->sc_todr.cookie = sc;
239	todr_attach(&sc->sc_todr);
240}
241
242/* End of dsrtc.c */
243