blob: e01f8a0f35c6341679b9a1ded6370cadb5808837 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/******************************************************************************
2 *
3 * (C)Copyright 1998,1999 SysKonnect,
4 * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
5 *
6 * See the file "skfddi.c" for further information.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * The information in this file is provided "AS IS" without warranty.
14 *
15 ******************************************************************************/
16
17/*
18 * Timer Driver for FBI board (timer chip 82C54)
19 */
20
21/*
22 * Modifications:
23 *
24 * 28-Jun-1994 sw Edit v1.6.
25 * MCA: Added support for the SK-NET FDDI-FM2 adapter. The
26 * following functions have been added(+) or modified(*):
27 * hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
28 */
29
30#include "h/types.h"
31#include "h/fddi.h"
32#include "h/smc.h"
33
34#ifndef lint
35static const char ID_sccs[] = "@(#)hwt.c 1.13 97/04/23 (C) SK " ;
36#endif
37
38/*
39 * Prototypes of local functions.
40 */
41/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
42/*static void hwt_restart() ; */
43
44/************************
45 *
46 * hwt_start
47 *
48 * Start hardware timer (clock ticks are 16us).
49 *
50 * void hwt_start(
51 * struct s_smc *smc,
52 * u_long time) ;
53 * In
54 * smc - A pointer to the SMT Context structure.
55 *
56 * time - The time in units of 16us to load the timer with.
57 * Out
58 * Nothing.
59 *
60 ************************/
61#define HWT_MAX (65000)
62
63void hwt_start(struct s_smc *smc, u_long time)
64{
65 u_short cnt ;
66
67 if (time > HWT_MAX)
68 time = HWT_MAX ;
69
70 smc->hw.t_start = time ;
71 smc->hw.t_stop = 0L ;
72
73 cnt = (u_short)time ;
74 /*
75 * if time < 16 us
76 * time = 16 us
77 */
78 if (!cnt)
79 cnt++ ;
80#ifndef PCI
81 /*
82 * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0
83 * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT)
84 */
85 OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
86 OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */
87 OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */
88 /*
89 * start timer by switching counter 0 to mode 3
90 * T0 resolution 16 us (CLK0=0.16us)
91 */
92 OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */
93 OUT_82c54_TIMER(0,100) ; /* LSB */
94 OUT_82c54_TIMER(0,0) ; /* MSB */
95#else /* PCI */
96 outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */
97 outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */
98#endif /* PCI */
99 smc->hw.timer_activ = TRUE ;
100}
101
102/************************
103 *
104 * hwt_stop
105 *
106 * Stop hardware timer.
107 *
108 * void hwt_stop(
109 * struct s_smc *smc) ;
110 * In
111 * smc - A pointer to the SMT Context structure.
112 * Out
113 * Nothing.
114 *
115 ************************/
116void hwt_stop(struct s_smc *smc)
117{
118#ifndef PCI
119 /* stop counter 0 by switching to mode 0 */
120 OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */
121 OUT_82c54_TIMER(0,0) ; /* LSB */
122 OUT_82c54_TIMER(0,0) ; /* MSB */
123#else /* PCI */
124 outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
125 outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
126#endif /* PCI */
127
128 smc->hw.timer_activ = FALSE ;
129}
130
131/************************
132 *
133 * hwt_init
134 *
135 * Initialize hardware timer.
136 *
137 * void hwt_init(
138 * struct s_smc *smc) ;
139 * In
140 * smc - A pointer to the SMT Context structure.
141 * Out
142 * Nothing.
143 *
144 ************************/
145void hwt_init(struct s_smc *smc)
146{
147 smc->hw.t_start = 0 ;
148 smc->hw.t_stop = 0 ;
149 smc->hw.timer_activ = FALSE ;
150
151 hwt_restart(smc) ;
152}
153
154/************************
155 *
156 * hwt_restart
157 *
158 * Clear timer interrupt.
159 *
160 * void hwt_restart(
161 * struct s_smc *smc) ;
162 * In
163 * smc - A pointer to the SMT Context structure.
164 * Out
165 * Nothing.
166 *
167 ************************/
168void hwt_restart(struct s_smc *smc)
169{
170 hwt_stop(smc) ;
171#ifndef PCI
172 OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
173 OUT_82c54_TIMER(1,1 ) ; /* LSB */
174 OUT_82c54_TIMER(1,0 ) ; /* MSB */
175#endif
176}
177
178/************************
179 *
180 * hwt_read
181 *
182 * Stop hardware timer and read time elapsed since last start.
183 *
184 * u_long hwt_read(smc) ;
185 * In
186 * smc - A pointer to the SMT Context structure.
187 * Out
188 * The elapsed time since last start in units of 16us.
189 *
190 ************************/
191u_long hwt_read(struct s_smc *smc)
192{
193 u_short tr ;
194#ifndef PCI
195 u_short is ;
196#else
197 u_long is ;
198#endif
199
200 if (smc->hw.timer_activ) {
201 hwt_stop(smc) ;
202#ifndef PCI
203 OUT_82c54_TIMER(3,1<<6) ; /* latch command */
204 tr = IN_82c54_TIMER(1) & 0xff ;
205 tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
206#else /* PCI */
207 tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
208#endif /* PCI */
209 is = GET_ISR() ;
210 /* Check if timer expired (or wraparound). */
211 if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
212 hwt_restart(smc) ;
213 smc->hw.t_stop = smc->hw.t_start ;
214 }
215 else
216 smc->hw.t_stop = smc->hw.t_start - tr ;
217 }
218 return (smc->hw.t_stop) ;
219}
220
221#ifdef PCI
222/************************
223 *
224 * hwt_quick_read
225 *
226 * Stop hardware timer and read timer value and start the timer again.
227 *
228 * u_long hwt_read(smc) ;
229 * In
230 * smc - A pointer to the SMT Context structure.
231 * Out
232 * current timer value in units of 80ns.
233 *
234 ************************/
235u_long hwt_quick_read(struct s_smc *smc)
236{
237 u_long interval ;
238 u_long time ;
239
240 interval = inpd(ADDR(B2_TI_INI)) ;
241 outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
242 time = inpd(ADDR(B2_TI_VAL)) ;
243 outpd(ADDR(B2_TI_INI),time) ;
244 outpw(ADDR(B2_TI_CRTL), TIM_START) ;
245 outpd(ADDR(B2_TI_INI),interval) ;
246
247 return(time) ;
248}
249
250/************************
251 *
252 * hwt_wait_time(smc,start,duration)
253 *
254 * This function returnes after the amount of time is elapsed
255 * since the start time.
256 *
257 * para start start time
258 * duration time to wait
259 *
260 * NOTE: The fuction will return immediately, if the timer is not
261 * started
262 ************************/
263void hwt_wait_time(struct s_smc *smc, u_long start, long int duration)
264{
265 long diff ;
266 long interval ;
267 int wrapped ;
268
269 /*
270 * check if timer is running
271 */
272 if (smc->hw.timer_activ == FALSE ||
273 hwt_quick_read(smc) == hwt_quick_read(smc)) {
274 return ;
275 }
276
277 interval = inpd(ADDR(B2_TI_INI)) ;
278 if (interval > duration) {
279 do {
280 diff = (long)(start - hwt_quick_read(smc)) ;
281 if (diff < 0) {
282 diff += interval ;
283 }
284 } while (diff <= duration) ;
285 }
286 else {
287 diff = interval ;
288 wrapped = 0 ;
289 do {
290 if (!wrapped) {
291 if (hwt_quick_read(smc) >= start) {
292 diff += interval ;
293 wrapped = 1 ;
294 }
295 }
296 else {
297 if (hwt_quick_read(smc) < start) {
298 wrapped = 0 ;
299 }
300 }
301 } while (diff <= duration) ;
302 }
303}
304#endif
305