linux/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
<<
>>
Prefs
   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