xref: /netbsd/sys/dev/ic/intersil7170.c (revision bf9ec67e)
1 /*	$NetBSD: intersil7170.c,v 1.2 2001/11/13 13:14:38 lukem Exp $ */
2 /*-
3  * Copyright (c) 2000 The NetBSD Foundation, Inc.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to The NetBSD Foundation
7  * by Paul Kranenburg.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *        This product includes software developed by the NetBSD
20  *        Foundation, Inc. and its contributors.
21  * 4. Neither the name of The NetBSD Foundation nor the names of its
22  *    contributors may be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Intersil 7170 time-of-day chip subroutines.
40  */
41 
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: intersil7170.c,v 1.2 2001/11/13 13:14:38 lukem Exp $");
44 
45 #include <sys/param.h>
46 #include <sys/malloc.h>
47 #include <sys/systm.h>
48 #include <sys/errno.h>
49 
50 #include <machine/bus.h>
51 #include <dev/clock_subr.h>
52 #include <dev/ic/intersil7170.h>
53 
54 #define intersil_command(run, interrupt) \
55 	(run | interrupt | INTERSIL_CMD_FREQ_32K | INTERSIL_CMD_24HR_MODE | \
56 	 INTERSIL_CMD_NORMAL_MODE)
57 
58 struct intersil7170_softc {
59 	bus_space_tag_t		sil_bt;
60 	bus_space_handle_t	sil_bh;
61 	int			sil_year0;
62 };
63 
64 int intersil7170_gettime(todr_chip_handle_t, struct timeval *);
65 int intersil7170_settime(todr_chip_handle_t, struct timeval *);
66 int intersil7170_getcal(todr_chip_handle_t, int *);
67 int intersil7170_setcal(todr_chip_handle_t, int);
68 
69 int intersil7170_auto_century_adjust = 1;
70 
71 todr_chip_handle_t
72 intersil7170_attach(bt, bh, year0)
73 	bus_space_tag_t bt;
74 	bus_space_handle_t bh;
75 	int year0;
76 {
77 	todr_chip_handle_t handle;
78 	struct intersil7170_softc *sil;
79 	int sz;
80 
81 	printf(": intersil7170");
82 
83 	sz = ALIGN(sizeof(struct todr_chip_handle)) + sizeof(struct intersil7170);
84 	handle = malloc(sz, M_DEVBUF, M_NOWAIT);
85 	sil = (struct intersil7170_softc *)((u_long)handle +
86 					ALIGN(sizeof(struct todr_chip_handle)));
87 	handle->cookie = sil;
88 	handle->todr_gettime = intersil7170_gettime;
89 	handle->todr_settime = intersil7170_settime;
90 	handle->todr_getcal = intersil7170_getcal;
91 	handle->todr_setcal = intersil7170_setcal;
92 	sil->sil_bt = bt;
93 	sil->sil_bh = bh;
94 	sil->sil_year0 = year0;
95 
96 	return (handle);
97 }
98 
99 /*
100  * Set up the system's time, given a `reasonable' time value.
101  */
102 int
103 intersil7170_gettime(handle, tv)
104 	todr_chip_handle_t handle;
105 	struct timeval *tv;
106 {
107 	struct intersil7170_softc *sil = handle->cookie;
108 	bus_space_tag_t bt = sil->sil_bt;
109 	bus_space_handle_t bh = sil->sil_bh;
110 	struct clock_ymdhms dt;
111 	u_int8_t cmd;
112 	int year;
113 	int s;
114 
115 	/* No interrupts while we're fiddling with the chip */
116 	s = splhigh();
117 
118 	/* Enable read (stop time) */
119 	cmd = intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
120 	bus_space_write_1(bt, bh, INTERSIL_ICMD, cmd);
121 
122 	/* The order of reading out the clock elements is important */
123 	bus_space_read_1(bt, bh, INTERSIL_ICSEC);	/* not used */
124 	dt.dt_hour = bus_space_read_1(bt, bh, INTERSIL_IHOUR);
125 	dt.dt_min = bus_space_read_1(bt, bh, INTERSIL_IMIN);
126 	dt.dt_sec = bus_space_read_1(bt, bh, INTERSIL_ISEC);
127 	dt.dt_mon = bus_space_read_1(bt, bh, INTERSIL_IMON);
128 	dt.dt_day = bus_space_read_1(bt, bh, INTERSIL_IDAY);
129 	year = bus_space_read_1(bt, bh, INTERSIL_IYEAR);
130 	dt.dt_wday = bus_space_read_1(bt, bh, INTERSIL_IDOW);
131 
132 	/* Done writing (time wears on) */
133 	cmd = intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
134 	bus_space_write_1(bt, bh, INTERSIL_ICMD, cmd);
135 	splx(s);
136 
137 	year += sil->sil_year0;
138 	if (year < 1970 && intersil7170_auto_century_adjust != 0)
139 		year += 100;
140 
141 	dt.dt_year = year;
142 
143 	tv->tv_sec = clock_ymdhms_to_secs(&dt);
144 	tv->tv_usec = 0;
145 	return (0);
146 }
147 
148 /*
149  * Reset the clock based on the current time.
150  */
151 int
152 intersil7170_settime(handle, tv)
153 	todr_chip_handle_t handle;
154 	struct timeval *tv;
155 {
156 	struct intersil7170_softc *sil = handle->cookie;
157 	bus_space_tag_t bt = sil->sil_bt;
158 	bus_space_handle_t bh = sil->sil_bh;
159 	struct clock_ymdhms dt;
160 	u_int8_t cmd;
161 	int year;
162 	int s;
163 
164 	clock_secs_to_ymdhms(tv->tv_sec, &dt);
165 
166 	year = dt.dt_year - sil->sil_year0;
167 	if (year > 99 && intersil7170_auto_century_adjust != 0)
168 		year -= 100;
169 
170 	/* No interrupts while we're fiddling with the chip */
171 	s = splhigh();
172 
173 	/* Enable write (stop time) */
174 	cmd = intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
175 	bus_space_write_1(bt, bh, INTERSIL_ICMD, cmd);
176 
177 	/* The order of reading writing the clock elements is important */
178 	bus_space_write_1(bt, bh, INTERSIL_ICSEC, 0);
179 	bus_space_write_1(bt, bh, INTERSIL_IHOUR, dt.dt_hour);
180 	bus_space_write_1(bt, bh, INTERSIL_IMIN, dt.dt_min);
181 	bus_space_write_1(bt, bh, INTERSIL_ISEC, dt.dt_sec);
182 	bus_space_write_1(bt, bh, INTERSIL_IMON, dt.dt_mon);
183 	bus_space_write_1(bt, bh, INTERSIL_IDAY, dt.dt_day);
184 	bus_space_write_1(bt, bh, INTERSIL_IYEAR, year);
185 	bus_space_write_1(bt, bh, INTERSIL_IDOW, dt.dt_wday);
186 
187 	/* Done writing (time wears on) */
188 	cmd = intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
189 	bus_space_write_1(bt, bh, INTERSIL_ICMD, cmd);
190 	splx(s);
191 
192 	return (0);
193 }
194 
195 int
196 intersil7170_getcal(handle, vp)
197 	todr_chip_handle_t handle;
198 	int *vp;
199 {
200 	return (EOPNOTSUPP);
201 }
202 
203 int
204 intersil7170_setcal(handle, v)
205 	todr_chip_handle_t handle;
206 	int v;
207 {
208 	return (EOPNOTSUPP);
209 }
210