Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6.git] / arch / arm / mach-bcmring / csp / tmr / tmrHw.c
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
52 static void ResetTimer(tmrHw_ID_t timerId)
53     __attribute__ ((section(".aramtext")));
54 static 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 /****************************************************************************/
67 uint32_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 /****************************************************************************/
93 static 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 /****************************************************************************/
117 static 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 /****************************************************************************/
176 tmrHw_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 /****************************************************************************/
225 tmrHw_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 /****************************************************************************/
250 tmrHw_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 /****************************************************************************/
272 tmrHw_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 /****************************************************************************/
313 int 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 /****************************************************************************/
330 int 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 /****************************************************************************/
346 uint32_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 /****************************************************************************/
373 tmrHw_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 /****************************************************************************/
409 void 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 /****************************************************************************/
424 void 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 /****************************************************************************/
441 void 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 /****************************************************************************/
455 tmrHw_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 /****************************************************************************/
476 tmrHw_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 /****************************************************************************/
498 void 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 /****************************************************************************/
523 void 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 /****************************************************************************/
549 static 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 }