• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/mach-bcmring/csp/tmr/
1/*****************************************************************************
2* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
3*
4* Unless you and Broadcom execute a separate written software license
5* agreement governing use of this software, this software is licensed to you
6* under the terms of the GNU General Public License version 2, available at
7* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
8*
9* Notwithstanding the above, under no circumstances may you combine this
10* software in any way with any other Broadcom software provided under a
11* license other than the GPL, without Broadcom's express prior written
12* consent.
13*****************************************************************************/
14
15/****************************************************************************/
16/**
17*  @file    tmrHw.c
18*
19*  @brief   Low level Timer driver routines
20*
21*  @note
22*
23*   These routines provide basic timer functionality only.
24*/
25/****************************************************************************/
26
27/* ---- Include Files ---------------------------------------------------- */
28
29#include <csp/errno.h>
30#include <csp/stdint.h>
31
32#include <csp/tmrHw.h>
33#include <mach/csp/tmrHw_reg.h>
34
35#define tmrHw_ASSERT(a)                     if (!(a)) *(char *)0 = 0
36#define tmrHw_MILLISEC_PER_SEC              (1000)
37
38#define tmrHw_LOW_1_RESOLUTION_COUNT        (tmrHw_LOW_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
39#define tmrHw_LOW_1_MAX_MILLISEC            (0xFFFFFFFF / tmrHw_LOW_1_RESOLUTION_COUNT)
40#define tmrHw_LOW_16_RESOLUTION_COUNT       (tmrHw_LOW_1_RESOLUTION_COUNT / 16)
41#define tmrHw_LOW_16_MAX_MILLISEC           (0xFFFFFFFF / tmrHw_LOW_16_RESOLUTION_COUNT)
42#define tmrHw_LOW_256_RESOLUTION_COUNT      (tmrHw_LOW_1_RESOLUTION_COUNT / 256)
43#define tmrHw_LOW_256_MAX_MILLISEC          (0xFFFFFFFF / tmrHw_LOW_256_RESOLUTION_COUNT)
44
45#define tmrHw_HIGH_1_RESOLUTION_COUNT       (tmrHw_HIGH_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
46#define tmrHw_HIGH_1_MAX_MILLISEC           (0xFFFFFFFF / tmrHw_HIGH_1_RESOLUTION_COUNT)
47#define tmrHw_HIGH_16_RESOLUTION_COUNT      (tmrHw_HIGH_1_RESOLUTION_COUNT / 16)
48#define tmrHw_HIGH_16_MAX_MILLISEC          (0xFFFFFFFF / tmrHw_HIGH_16_RESOLUTION_COUNT)
49#define tmrHw_HIGH_256_RESOLUTION_COUNT     (tmrHw_HIGH_1_RESOLUTION_COUNT / 256)
50#define tmrHw_HIGH_256_MAX_MILLISEC         (0xFFFFFFFF / tmrHw_HIGH_256_RESOLUTION_COUNT)
51
52static void ResetTimer(tmrHw_ID_t timerId)
53    __attribute__ ((section(".aramtext")));
54static int tmrHw_divide(int num, int denom)
55    __attribute__ ((section(".aramtext")));
56
57/****************************************************************************/
58/**
59*  @brief   Get timer capability
60*
61*  This function returns various capabilities/attributes of a timer
62*
63*  @return  Capability
64*
65*/
66/****************************************************************************/
67uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
68				  tmrHw_CAPABILITY_e capability	/*  [ IN ] Timer capability */
69) {
70	switch (capability) {
71	case tmrHw_CAPABILITY_CLOCK:
72		return (timerId <=
73			1) ? tmrHw_LOW_RESOLUTION_CLOCK :
74		    tmrHw_HIGH_RESOLUTION_CLOCK;
75	case tmrHw_CAPABILITY_RESOLUTION:
76		return 32;
77	default:
78		return 0;
79	}
80	return 0;
81}
82
83/****************************************************************************/
84/**
85*  @brief   Resets a timer
86*
87*  This function initializes  timer
88*
89*  @return  void
90*
91*/
92/****************************************************************************/
93static void ResetTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer Id */
94) {
95	/* Reset timer */
96	pTmrHw[timerId].LoadValue = 0;
97	pTmrHw[timerId].CurrentValue = 0xFFFFFFFF;
98	pTmrHw[timerId].Control = 0;
99	pTmrHw[timerId].BackgroundLoad = 0;
100	/* Always configure as a 32 bit timer */
101	pTmrHw[timerId].Control |= tmrHw_CONTROL_32BIT;
102	/* Clear interrupt only if raw status interrupt is set */
103	if (pTmrHw[timerId].RawInterruptStatus) {
104		pTmrHw[timerId].InterruptClear = 0xFFFFFFFF;
105	}
106}
107
108/****************************************************************************/
109/**
110*  @brief   Sets counter value for an interval in ms
111*
112*  @return   On success: Effective counter value set
113*            On failure: 0
114*
115*/
116/****************************************************************************/
117static tmrHw_INTERVAL_t SetTimerPeriod(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
118				       tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in milli-second */
119) {
120	uint32_t scale = 0;
121	uint32_t count = 0;
122
123	if (timerId == 0 || timerId == 1) {
124		if (msec <= tmrHw_LOW_1_MAX_MILLISEC) {
125			pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
126			scale = tmrHw_LOW_1_RESOLUTION_COUNT;
127		} else if (msec <= tmrHw_LOW_16_MAX_MILLISEC) {
128			pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
129			scale = tmrHw_LOW_16_RESOLUTION_COUNT;
130		} else if (msec <= tmrHw_LOW_256_MAX_MILLISEC) {
131			pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
132			scale = tmrHw_LOW_256_RESOLUTION_COUNT;
133		} else {
134			return 0;
135		}
136
137		count = msec * scale;
138		/* Set counter value */
139		pTmrHw[timerId].LoadValue = count;
140		pTmrHw[timerId].BackgroundLoad = count;
141
142	} else if (timerId == 2 || timerId == 3) {
143		if (msec <= tmrHw_HIGH_1_MAX_MILLISEC) {
144			pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
145			scale = tmrHw_HIGH_1_RESOLUTION_COUNT;
146		} else if (msec <= tmrHw_HIGH_16_MAX_MILLISEC) {
147			pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
148			scale = tmrHw_HIGH_16_RESOLUTION_COUNT;
149		} else if (msec <= tmrHw_HIGH_256_MAX_MILLISEC) {
150			pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
151			scale = tmrHw_HIGH_256_RESOLUTION_COUNT;
152		} else {
153			return 0;
154		}
155
156		count = msec * scale;
157		/* Set counter value */
158		pTmrHw[timerId].LoadValue = count;
159		pTmrHw[timerId].BackgroundLoad = count;
160	}
161	return count / scale;
162}
163
164/****************************************************************************/
165/**
166*  @brief   Configures a periodic timer in terms of timer interrupt rate
167*
168*  This function initializes a periodic timer to generate specific number of
169*  timer interrupt per second
170*
171*  @return   On success: Effective timer frequency
172*            On failure: 0
173*
174*/
175/****************************************************************************/
176tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
177					tmrHw_RATE_t rate	/*  [ IN ] Number of timer interrupt per second */
178) {
179	uint32_t resolution = 0;
180	uint32_t count = 0;
181	ResetTimer(timerId);
182
183	/* Set timer mode periodic */
184	pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
185	pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
186	/* Set timer in highest resolution */
187	pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
188
189	if (rate && (timerId == 0 || timerId == 1)) {
190		if (rate > tmrHw_LOW_RESOLUTION_CLOCK) {
191			return 0;
192		}
193		resolution = tmrHw_LOW_RESOLUTION_CLOCK;
194	} else if (rate && (timerId == 2 || timerId == 3)) {
195		if (rate > tmrHw_HIGH_RESOLUTION_CLOCK) {
196			return 0;
197		} else {
198			resolution = tmrHw_HIGH_RESOLUTION_CLOCK;
199		}
200	} else {
201		return 0;
202	}
203	/* Find the counter value */
204	count = resolution / rate;
205	/* Set counter value */
206	pTmrHw[timerId].LoadValue = count;
207	pTmrHw[timerId].BackgroundLoad = count;
208
209	return resolution / count;
210}
211
212/****************************************************************************/
213/**
214*  @brief   Configures a periodic timer to generate timer interrupt after
215*           certain time interval
216*
217*  This function initializes a periodic timer to generate timer interrupt
218*  after every time interval in millisecond
219*
220*  @return   On success: Effective interval set in milli-second
221*            On failure: 0
222*
223*/
224/****************************************************************************/
225tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
226						tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in milli-second */
227) {
228	ResetTimer(timerId);
229
230	/* Set timer mode periodic */
231	pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
232	pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
233
234	return SetTimerPeriod(timerId, msec);
235}
236
237/****************************************************************************/
238/**
239*  @brief   Configures a periodic timer to generate timer interrupt just once
240*           after certain time interval
241*
242*  This function initializes a periodic timer to generate a single ticks after
243*  certain time interval in millisecond
244*
245*  @return   On success: Effective interval set in milli-second
246*            On failure: 0
247*
248*/
249/****************************************************************************/
250tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
251					       tmrHw_INTERVAL_t msec	/*  [ IN ] Interval in milli-second */
252) {
253	ResetTimer(timerId);
254
255	/* Set timer mode oneshot */
256	pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
257	pTmrHw[timerId].Control |= tmrHw_CONTROL_ONESHOT;
258
259	return SetTimerPeriod(timerId, msec);
260}
261
262/****************************************************************************/
263/**
264*  @brief   Configures a timer to run as a free running timer
265*
266*  This function initializes a timer to run as a free running timer
267*
268*  @return   Timer resolution (count / sec)
269*
270*/
271/****************************************************************************/
272tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId,	/*  [ IN ] Timer Id */
273				       uint32_t divider	/*  [ IN ] Dividing the clock frequency */
274) {
275	uint32_t scale = 0;
276
277	ResetTimer(timerId);
278	/* Set timer as free running mode */
279	pTmrHw[timerId].Control &= ~tmrHw_CONTROL_PERIODIC;
280	pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
281
282	if (divider >= 64) {
283		pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
284		scale = 256;
285	} else if (divider >= 8) {
286		pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
287		scale = 16;
288	} else {
289		pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
290		scale = 1;
291	}
292
293	if (timerId == 0 || timerId == 1) {
294		return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, scale);
295	} else if (timerId == 2 || timerId == 3) {
296		return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, scale);
297	}
298
299	return 0;
300}
301
302/****************************************************************************/
303/**
304*  @brief   Starts a timer
305*
306*  This function starts a preconfigured timer
307*
308*  @return  -1     - On Failure
309*            0     - On Success
310*
311*/
312/****************************************************************************/
313int tmrHw_startTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
314) {
315	pTmrHw[timerId].Control |= tmrHw_CONTROL_TIMER_ENABLE;
316	return 0;
317}
318
319/****************************************************************************/
320/**
321*  @brief   Stops a timer
322*
323*  This function stops a running timer
324*
325*  @return  -1     - On Failure
326*            0     - On Success
327*
328*/
329/****************************************************************************/
330int tmrHw_stopTimer(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
331) {
332	pTmrHw[timerId].Control &= ~tmrHw_CONTROL_TIMER_ENABLE;
333	return 0;
334}
335
336/****************************************************************************/
337/**
338*  @brief   Gets current timer count
339*
340*  This function returns the current timer value
341*
342*  @return  Current downcounting timer value
343*
344*/
345/****************************************************************************/
346uint32_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
347) {
348	/* return 32 bit timer value */
349	switch (pTmrHw[timerId].Control & tmrHw_CONTROL_MODE_MASK) {
350	case tmrHw_CONTROL_FREE_RUNNING:
351		if (pTmrHw[timerId].CurrentValue) {
352			return tmrHw_MAX_COUNT - pTmrHw[timerId].CurrentValue;
353		}
354		break;
355	case tmrHw_CONTROL_PERIODIC:
356	case tmrHw_CONTROL_ONESHOT:
357		return pTmrHw[timerId].BackgroundLoad -
358		    pTmrHw[timerId].CurrentValue;
359	}
360	return 0;
361}
362
363/****************************************************************************/
364/**
365*  @brief   Gets timer count rate
366*
367*  This function returns the number of counts per second
368*
369*  @return  Count rate
370*
371*/
372/****************************************************************************/
373tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
374) {
375	uint32_t divider = 0;
376
377	switch (pTmrHw[timerId].Control & tmrHw_CONTROL_PRESCALE_MASK) {
378	case tmrHw_CONTROL_PRESCALE_1:
379		divider = 1;
380		break;
381	case tmrHw_CONTROL_PRESCALE_16:
382		divider = 16;
383		break;
384	case tmrHw_CONTROL_PRESCALE_256:
385		divider = 256;
386		break;
387	default:
388		tmrHw_ASSERT(0);
389	}
390
391	if (timerId == 0 || timerId == 1) {
392		return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, divider);
393	} else {
394		return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, divider);
395	}
396	return 0;
397}
398
399/****************************************************************************/
400/**
401*  @brief   Enables timer interrupt
402*
403*  This function enables the timer interrupt
404*
405*  @return   N/A
406*
407*/
408/****************************************************************************/
409void tmrHw_enableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
410) {
411	pTmrHw[timerId].Control |= tmrHw_CONTROL_INTERRUPT_ENABLE;
412}
413
414/****************************************************************************/
415/**
416*  @brief   Disables timer interrupt
417*
418*  This function disable the timer interrupt
419*
420*  @return   N/A
421*
422*/
423/****************************************************************************/
424void tmrHw_disableInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
425) {
426	pTmrHw[timerId].Control &= ~tmrHw_CONTROL_INTERRUPT_ENABLE;
427}
428
429/****************************************************************************/
430/**
431*  @brief   Clears the interrupt
432*
433*  This function clears the timer interrupt
434*
435*  @return   N/A
436*
437*  @note
438*     Must be called under the context of ISR
439*/
440/****************************************************************************/
441void tmrHw_clearInterrupt(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
442) {
443	pTmrHw[timerId].InterruptClear = 0x1;
444}
445
446/****************************************************************************/
447/**
448*  @brief   Gets the interrupt status
449*
450*  This function returns timer interrupt status
451*
452*  @return   Interrupt status
453*/
454/****************************************************************************/
455tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId	/*  [ IN ] Timer id */
456) {
457	if (pTmrHw[timerId].InterruptStatus) {
458		return tmrHw_INTERRUPT_STATUS_SET;
459	} else {
460		return tmrHw_INTERRUPT_STATUS_UNSET;
461	}
462}
463
464/****************************************************************************/
465/**
466*  @brief   Indentifies a timer causing interrupt
467*
468*  This functions returns a timer causing interrupt
469*
470*  @return  0xFFFFFFFF   : No timer causing an interrupt
471*           ! 0xFFFFFFFF : timer causing an interrupt
472*  @note
473*     tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
474*/
475/****************************************************************************/
476tmrHw_ID_t tmrHw_getInterruptSource(void	/*  void */
477) {
478	int i;
479
480	for (i = 0; i < tmrHw_TIMER_NUM_COUNT; i++) {
481		if (pTmrHw[i].InterruptStatus) {
482			return i;
483		}
484	}
485
486	return 0xFFFFFFFF;
487}
488
489/****************************************************************************/
490/**
491*  @brief   Displays specific timer registers
492*
493*
494*  @return  void
495*
496*/
497/****************************************************************************/
498void tmrHw_printDebugInfo(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
499			  int (*fpPrint) (const char *, ...)	/*  [ IN ] Print callback function */
500) {
501	(*fpPrint) ("Displaying register contents \n\n");
502	(*fpPrint) ("Timer %d: Load value              0x%X\n", timerId,
503		    pTmrHw[timerId].LoadValue);
504	(*fpPrint) ("Timer %d: Background load value   0x%X\n", timerId,
505		    pTmrHw[timerId].BackgroundLoad);
506	(*fpPrint) ("Timer %d: Control                 0x%X\n", timerId,
507		    pTmrHw[timerId].Control);
508	(*fpPrint) ("Timer %d: Interrupt clear         0x%X\n", timerId,
509		    pTmrHw[timerId].InterruptClear);
510	(*fpPrint) ("Timer %d: Interrupt raw interrupt 0x%X\n", timerId,
511		    pTmrHw[timerId].RawInterruptStatus);
512	(*fpPrint) ("Timer %d: Interrupt status        0x%X\n", timerId,
513		    pTmrHw[timerId].InterruptStatus);
514}
515
516/****************************************************************************/
517/**
518*  @brief   Use a timer to perform a busy wait delay for a number of usecs.
519*
520*  @return   N/A
521*/
522/****************************************************************************/
523void tmrHw_udelay(tmrHw_ID_t timerId,	/*  [ IN ] Timer id */
524		  unsigned long usecs /*  [ IN ] usec to delay */
525) {
526	tmrHw_RATE_t usec_tick_rate;
527	tmrHw_COUNT_t start_time;
528	tmrHw_COUNT_t delta_time;
529
530	start_time = tmrHw_GetCurrentCount(timerId);
531	usec_tick_rate = tmrHw_divide(tmrHw_getCountRate(timerId), 1000000);
532	delta_time = usecs * usec_tick_rate;
533
534	/* Busy wait */
535	while (delta_time > (tmrHw_GetCurrentCount(timerId) - start_time))
536		;
537}
538
539/****************************************************************************/
540/**
541*  @brief   Local Divide function
542*
543*  This function does the divide
544*
545*  @return divide value
546*
547*/
548/****************************************************************************/
549static int tmrHw_divide(int num, int denom)
550{
551	int r;
552	int t = 1;
553
554	/* Shift denom and t up to the largest value to optimize algorithm */
555	/* t contains the units of each divide */
556	while ((denom & 0x40000000) == 0) {	/* fails if denom=0 */
557		denom = denom << 1;
558		t = t << 1;
559	}
560
561	/* Intialize the result */
562	r = 0;
563
564	do {
565		/* Determine if there exists a positive remainder */
566		if ((num - denom) >= 0) {
567			/* Accumlate t to the result and calculate a new remainder */
568			num = num - denom;
569			r = r + t;
570		}
571		/* Continue to shift denom and shift t down to 0 */
572		denom = denom >> 1;
573		t = t >> 1;
574	} while (t != 0);
575	return r;
576}
577