ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / net / skfp / hwt.c
1 /******************************************************************************
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
35 static 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
63 void hwt_start(smc, time)
64 struct s_smc *smc ;
65 u_long time ;
66 {
67         u_short cnt ;
68
69         if (time > HWT_MAX)
70                 time = HWT_MAX ;
71
72         smc->hw.t_start = time ;
73         smc->hw.t_stop = 0L ;
74
75         cnt = (u_short)time ;
76         /*
77          * if time < 16 us
78          *      time = 16 us
79          */
80         if (!cnt)
81                 cnt++ ;
82 #ifndef PCI
83         /*
84          * 6.25MHz -> CLK0 : T0 (cnt0 = 16us)   -> OUT0
85          *    OUT0 -> CLK1 : T1 (cnt1)  OUT1    -> ISRA(IS_TIMINT)
86          */
87         OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
88         OUT_82c54_TIMER(1,cnt & 0xff) ;         /* LSB */
89         OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ;    /* MSB */
90         /*
91          * start timer by switching counter 0 to mode 3
92          *      T0 resolution 16 us (CLK0=0.16us)
93          */
94         OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */
95         OUT_82c54_TIMER(0,100) ;                /* LSB */
96         OUT_82c54_TIMER(0,0) ;                  /* MSB */
97 #else   /* PCI */
98         outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;    /* Load timer value. */
99         outpw(ADDR(B2_TI_CRTL), TIM_START) ;            /* Start timer. */
100 #endif  /* PCI */
101         smc->hw.timer_activ = TRUE ;
102 }
103
104 /************************
105  *
106  *      hwt_stop
107  *
108  *      Stop hardware timer.
109  *
110  *      void hwt_stop(
111  *              struct s_smc *smc) ;
112  * In
113  *      smc - A pointer to the SMT Context structure.
114  * Out
115  *      Nothing.
116  *
117  ************************/
118 void hwt_stop(smc)
119 struct s_smc *smc ;
120 {
121 #ifndef PCI
122         /* stop counter 0 by switching to mode 0 */
123         OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */
124         OUT_82c54_TIMER(0,0) ;                  /* LSB */
125         OUT_82c54_TIMER(0,0) ;                  /* MSB */
126 #else   /* PCI */
127         outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
128         outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
129 #endif  /* PCI */
130
131         smc->hw.timer_activ = FALSE ;
132 }
133
134 /************************
135  *
136  *      hwt_init
137  *
138  *      Initialize hardware timer.
139  *
140  *      void hwt_init(
141  *              struct s_smc *smc) ;
142  * In
143  *      smc - A pointer to the SMT Context structure.
144  * Out
145  *      Nothing.
146  *
147  ************************/
148 void hwt_init(smc)
149 struct s_smc *smc ;
150 {
151         smc->hw.t_start = 0 ;
152         smc->hw.t_stop  = 0 ;
153         smc->hw.timer_activ = FALSE ;
154
155         hwt_restart(smc) ;
156 }
157
158 /************************
159  *
160  *      hwt_restart
161  *
162  *      Clear timer interrupt.
163  *
164  *      void hwt_restart(
165  *              struct s_smc *smc) ;
166  * In
167  *      smc - A pointer to the SMT Context structure.
168  * Out
169  *      Nothing.
170  *
171  ************************/
172 void hwt_restart(smc)
173 struct s_smc *smc ;
174 {
175         hwt_stop(smc) ;
176 #ifndef PCI
177         OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
178         OUT_82c54_TIMER(1,1 ) ;                 /* LSB */
179         OUT_82c54_TIMER(1,0 ) ;                 /* MSB */
180 #endif
181 }
182
183 /************************
184  *
185  *      hwt_read
186  *
187  *      Stop hardware timer and read time elapsed since last start.
188  *
189  *      u_long hwt_read(smc) ;
190  * In
191  *      smc - A pointer to the SMT Context structure.
192  * Out
193  *      The elapsed time since last start in units of 16us.
194  *
195  ************************/
196 u_long hwt_read(smc)
197 struct s_smc *smc ;
198 {
199         u_short tr ;
200 #ifndef PCI
201         u_short is ;
202 #else
203         u_long  is ;
204 #endif
205
206         if (smc->hw.timer_activ) {
207                 hwt_stop(smc) ;
208 #ifndef PCI
209                 OUT_82c54_TIMER(3,1<<6) ;       /* latch command */
210                 tr = IN_82c54_TIMER(1) & 0xff ;
211                 tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
212 #else   /* PCI */
213                 tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
214 #endif  /* PCI */
215                 is = GET_ISR() ;
216                 /* Check if timer expired (or wraparound). */
217                 if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
218                         hwt_restart(smc) ;
219                         smc->hw.t_stop = smc->hw.t_start ;
220                 }
221                 else
222                         smc->hw.t_stop = smc->hw.t_start - tr ;
223         }
224         return (smc->hw.t_stop) ;
225 }
226
227 #ifdef  PCI
228 /************************
229  *
230  *      hwt_quick_read
231  *
232  *      Stop hardware timer and read timer value and start the timer again.
233  *
234  *      u_long hwt_read(smc) ;
235  * In
236  *      smc - A pointer to the SMT Context structure.
237  * Out
238  *      current timer value in units of 80ns.
239  *
240  ************************/
241 u_long hwt_quick_read(smc)
242 struct s_smc *smc ;
243 {
244         u_long interval ;
245         u_long time ;
246
247         interval = inpd(ADDR(B2_TI_INI)) ;
248         outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
249         time = inpd(ADDR(B2_TI_VAL)) ;
250         outpd(ADDR(B2_TI_INI),time) ;
251         outpw(ADDR(B2_TI_CRTL), TIM_START) ;
252         outpd(ADDR(B2_TI_INI),interval) ;
253
254         return(time) ;
255 }
256
257 /************************
258  *
259  *      hwt_wait_time(smc,start,duration)
260  *
261  *      This function returnes after the amount of time is elapsed
262  *      since the start time.
263  * 
264  * para start           start time
265  *      duration        time to wait
266  *
267  * NOTE: The fuction will return immediately, if the timer is not 
268  *       started
269  ************************/
270 void hwt_wait_time(smc,start,duration)
271 struct s_smc *smc ;
272 u_long  start ;
273 long    duration ;
274 {
275         long    diff ;
276         long    interval ;
277         int     wrapped ;
278
279         /*
280          * check if timer is running
281          */
282         if (smc->hw.timer_activ == FALSE ||
283                 hwt_quick_read(smc) == hwt_quick_read(smc)) {
284                 return ;
285         }
286
287         interval = inpd(ADDR(B2_TI_INI)) ;
288         if (interval > duration) {
289                 do {
290                         diff = (long)(start - hwt_quick_read(smc)) ;
291                         if (diff < 0) {
292                                 diff += interval ;
293                         }
294                 } while (diff <= duration) ;
295         }
296         else {
297                 diff = interval ;
298                 wrapped = 0 ;
299                 do {
300                         if (!wrapped) {
301                                 if (hwt_quick_read(smc) >= start) {
302                                         diff += interval ;
303                                         wrapped = 1 ;
304                                 }
305                         }
306                         else {
307                                 if (hwt_quick_read(smc) < start) {
308                                         wrapped = 0 ;
309                                 }
310                         }
311                 } while (diff <= duration) ;
312         }
313 }
314 #endif