xref: /kernel/linux/linux-6.6/drivers/net/fddi/skfp/hwt.c (revision 62306a36)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/******************************************************************************
3 *
4 *	(C)Copyright 1998,1999 SysKonnect,
5 *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
6 *
7 *	See the file "skfddi.c" for further information.
8 *
9 *	The information in this file is provided "AS IS" without warranty.
10 *
11 ******************************************************************************/
12
13/*
14 * Timer Driver for FBI board (timer chip 82C54)
15 */
16
17/*
18 * Modifications:
19 *
20 *	28-Jun-1994 sw	Edit v1.6.
21 *			MCA: Added support for the SK-NET FDDI-FM2 adapter. The
22 *			 following functions have been added(+) or modified(*):
23 *			 hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
24 */
25
26#include "h/types.h"
27#include "h/fddi.h"
28#include "h/smc.h"
29
30/*
31 * Prototypes of local functions.
32 */
33/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
34/*static void hwt_restart() ; */
35
36/************************
37 *
38 *	hwt_start
39 *
40 *	Start hardware timer (clock ticks are 16us).
41 *
42 *	void hwt_start(
43 *		struct s_smc *smc,
44 *		u_long time) ;
45 * In
46 *	smc - A pointer to the SMT Context structure.
47 *
48 *	time - The time in units of 16us to load the timer with.
49 * Out
50 *	Nothing.
51 *
52 ************************/
53#define	HWT_MAX	(65000)
54
55void hwt_start(struct s_smc *smc, u_long time)
56{
57	u_short	cnt ;
58
59	if (time > HWT_MAX)
60		time = HWT_MAX ;
61
62	smc->hw.t_start = time ;
63	smc->hw.t_stop = 0L ;
64
65	cnt = (u_short)time ;
66	/*
67	 * if time < 16 us
68	 *	time = 16 us
69	 */
70	if (!cnt)
71		cnt++ ;
72
73	outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;	/* Load timer value. */
74	outpw(ADDR(B2_TI_CRTL), TIM_START) ;		/* Start timer. */
75
76	smc->hw.timer_activ = TRUE ;
77}
78
79/************************
80 *
81 *	hwt_stop
82 *
83 *	Stop hardware timer.
84 *
85 *	void hwt_stop(
86 *		struct s_smc *smc) ;
87 * In
88 *	smc - A pointer to the SMT Context structure.
89 * Out
90 *	Nothing.
91 *
92 ************************/
93void hwt_stop(struct s_smc *smc)
94{
95	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
96	outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
97
98	smc->hw.timer_activ = FALSE ;
99}
100
101/************************
102 *
103 *	hwt_init
104 *
105 *	Initialize hardware timer.
106 *
107 *	void hwt_init(
108 *		struct s_smc *smc) ;
109 * In
110 *	smc - A pointer to the SMT Context structure.
111 * Out
112 *	Nothing.
113 *
114 ************************/
115void hwt_init(struct s_smc *smc)
116{
117	smc->hw.t_start = 0 ;
118	smc->hw.t_stop	= 0 ;
119	smc->hw.timer_activ = FALSE ;
120
121	hwt_restart(smc) ;
122}
123
124/************************
125 *
126 *	hwt_restart
127 *
128 *	Clear timer interrupt.
129 *
130 *	void hwt_restart(
131 *		struct s_smc *smc) ;
132 * In
133 *	smc - A pointer to the SMT Context structure.
134 * Out
135 *	Nothing.
136 *
137 ************************/
138void hwt_restart(struct s_smc *smc)
139{
140	hwt_stop(smc) ;
141}
142
143/************************
144 *
145 *	hwt_read
146 *
147 *	Stop hardware timer and read time elapsed since last start.
148 *
149 *	u_long hwt_read(smc) ;
150 * In
151 *	smc - A pointer to the SMT Context structure.
152 * Out
153 *	The elapsed time since last start in units of 16us.
154 *
155 ************************/
156u_long hwt_read(struct s_smc *smc)
157{
158	u_short	tr ;
159	u_long	is ;
160
161	if (smc->hw.timer_activ) {
162		hwt_stop(smc) ;
163		tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
164
165		is = GET_ISR() ;
166		/* Check if timer expired (or wraparound). */
167		if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
168			hwt_restart(smc) ;
169			smc->hw.t_stop = smc->hw.t_start ;
170		}
171		else
172			smc->hw.t_stop = smc->hw.t_start - tr ;
173	}
174	return smc->hw.t_stop;
175}
176
177#ifdef	PCI
178/************************
179 *
180 *	hwt_quick_read
181 *
182 *	Stop hardware timer and read timer value and start the timer again.
183 *
184 *	u_long hwt_read(smc) ;
185 * In
186 *	smc - A pointer to the SMT Context structure.
187 * Out
188 *	current timer value in units of 80ns.
189 *
190 ************************/
191u_long hwt_quick_read(struct s_smc *smc)
192{
193	u_long interval ;
194	u_long time ;
195
196	interval = inpd(ADDR(B2_TI_INI)) ;
197	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
198	time = inpd(ADDR(B2_TI_VAL)) ;
199	outpd(ADDR(B2_TI_INI),time) ;
200	outpw(ADDR(B2_TI_CRTL), TIM_START) ;
201	outpd(ADDR(B2_TI_INI),interval) ;
202
203	return time;
204}
205
206/************************
207 *
208 *	hwt_wait_time(smc,start,duration)
209 *
210 *	This function returnes after the amount of time is elapsed
211 *	since the start time.
212 *
213 * para	start		start time
214 *	duration	time to wait
215 *
216 * NOTE: The function will return immediately, if the timer is not
217 *	 started
218 ************************/
219void hwt_wait_time(struct s_smc *smc, u_long start, long int duration)
220{
221	long	diff ;
222	long	interval ;
223	int	wrapped ;
224
225	/*
226	 * check if timer is running
227	 */
228	if (smc->hw.timer_activ == FALSE ||
229		hwt_quick_read(smc) == hwt_quick_read(smc)) {
230		return ;
231	}
232
233	interval = inpd(ADDR(B2_TI_INI)) ;
234	if (interval > duration) {
235		do {
236			diff = (long)(start - hwt_quick_read(smc)) ;
237			if (diff < 0) {
238				diff += interval ;
239			}
240		} while (diff <= duration) ;
241	}
242	else {
243		diff = interval ;
244		wrapped = 0 ;
245		do {
246			if (!wrapped) {
247				if (hwt_quick_read(smc) >= start) {
248					diff += interval ;
249					wrapped = 1 ;
250				}
251			}
252			else {
253				if (hwt_quick_read(smc) < start) {
254					wrapped = 0 ;
255				}
256			}
257		} while (diff <= duration) ;
258	}
259}
260#endif
261
262