diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-14 17:48:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-14 17:48:14 -0700 |
commit | 2ca7d674d7ab2220707b2ada0b690c0e7c95e7ac (patch) | |
tree | 9c0927ed1d540e5fd704c1f82689870786514655 /arch/arm/mach-bcmring/csp/tmr/tmrHw.c | |
parent | 2195d2818c37bdf263865f1e9effccdd9fc5f9d4 (diff) | |
parent | 87d721ad7a37b7650dd710c88dd5c6a5bf9fe996 (diff) | |
download | op-kernel-dev-2ca7d674d7ab2220707b2ada0b690c0e7c95e7ac.zip op-kernel-dev-2ca7d674d7ab2220707b2ada0b690c0e7c95e7ac.tar.gz |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (257 commits)
[ARM] Update mach-types
ARM: 5636/1: Move vendor enum to AMBA include
ARM: Fix pfn_valid() for sparse memory
[ARM] orion5x: Add LaCie NAS 2Big Network support
[ARM] pxa/sharpsl_pm: zaurus c3000 aka spitz: fix resume
ARM: 5686/1: at91: Correct AC97 reset line in at91sam9263ek board
ARM: 5640/1: This patch modifies the support of AC97 on the at91sam9263 ek board
ARM: 5689/1: Update default config of HP Jornada 700-series machines
ARM: 5691/1: fix cache aliasing issues between kmap() and kmap_atomic() with highmem
ARM: 5688/1: ks8695_serial: disable_irq() lockup
ARM: 5687/1: fix an oops with highmem
ARM: 5684/1: Add nuc960 platform to w90x900
ARM: 5683/1: Add nuc950 platform to w90x900
ARM: 5682/1: Add cpu.c and dev.c and modify some files of w90p910 platform
ARM: 5626/1: add suspend/resume functions to amba-pl011 serial driver
ARM: 5625/1: fix hard coded 4K resource size in amba bus detection
MMC: MMCI: convert realview MMC to use gpiolib
ARM: 5685/1: Make MMCI driver compile without gpiolib
ARM: implement highpte
ARM: Show FIQ in /proc/interrupts on CONFIG_FIQ
...
Fix up trivial conflict in arch/arm/kernel/signal.c.
It was due to the TIF_NOTIFY_RESUME addition in commit d0420c83f ("KEYS:
Extend TIF_NOTIFY_RESUME to (almost) all architectures") and follow-ups.
Diffstat (limited to 'arch/arm/mach-bcmring/csp/tmr/tmrHw.c')
-rw-r--r-- | arch/arm/mach-bcmring/csp/tmr/tmrHw.c | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/arch/arm/mach-bcmring/csp/tmr/tmrHw.c b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c new file mode 100644 index 0000000..5c1c9a0 --- /dev/null +++ b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c @@ -0,0 +1,576 @@ +/***************************************************************************** +* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved. +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2, available at +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). +* +* Notwithstanding the above, under no circumstances may you combine this +* software in any way with any other Broadcom software provided under a +* license other than the GPL, without Broadcom's express prior written +* consent. +*****************************************************************************/ + +/****************************************************************************/ +/** +* @file tmrHw.c +* +* @brief Low level Timer driver routines +* +* @note +* +* These routines provide basic timer functionality only. +*/ +/****************************************************************************/ + +/* ---- Include Files ---------------------------------------------------- */ + +#include <csp/errno.h> +#include <csp/stdint.h> + +#include <csp/tmrHw.h> +#include <mach/csp/tmrHw_reg.h> + +#define tmrHw_ASSERT(a) if (!(a)) *(char *)0 = 0 +#define tmrHw_MILLISEC_PER_SEC (1000) + +#define tmrHw_LOW_1_RESOLUTION_COUNT (tmrHw_LOW_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC) +#define tmrHw_LOW_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_1_RESOLUTION_COUNT) +#define tmrHw_LOW_16_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 16) +#define tmrHw_LOW_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_16_RESOLUTION_COUNT) +#define tmrHw_LOW_256_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 256) +#define tmrHw_LOW_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_256_RESOLUTION_COUNT) + +#define tmrHw_HIGH_1_RESOLUTION_COUNT (tmrHw_HIGH_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC) +#define tmrHw_HIGH_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_1_RESOLUTION_COUNT) +#define tmrHw_HIGH_16_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 16) +#define tmrHw_HIGH_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_16_RESOLUTION_COUNT) +#define tmrHw_HIGH_256_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 256) +#define tmrHw_HIGH_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_256_RESOLUTION_COUNT) + +static void ResetTimer(tmrHw_ID_t timerId) + __attribute__ ((section(".aramtext"))); +static int tmrHw_divide(int num, int denom) + __attribute__ ((section(".aramtext"))); + +/****************************************************************************/ +/** +* @brief Get timer capability +* +* This function returns various capabilities/attributes of a timer +* +* @return Capability +* +*/ +/****************************************************************************/ +uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ + tmrHw_CAPABILITY_e capability /* [ IN ] Timer capability */ +) { + switch (capability) { + case tmrHw_CAPABILITY_CLOCK: + return (timerId <= + 1) ? tmrHw_LOW_RESOLUTION_CLOCK : + tmrHw_HIGH_RESOLUTION_CLOCK; + case tmrHw_CAPABILITY_RESOLUTION: + return 32; + default: + return 0; + } + return 0; +} + +/****************************************************************************/ +/** +* @brief Resets a timer +* +* This function initializes timer +* +* @return void +* +*/ +/****************************************************************************/ +static void ResetTimer(tmrHw_ID_t timerId /* [ IN ] Timer Id */ +) { + /* Reset timer */ + pTmrHw[timerId].LoadValue = 0; + pTmrHw[timerId].CurrentValue = 0xFFFFFFFF; + pTmrHw[timerId].Control = 0; + pTmrHw[timerId].BackgroundLoad = 0; + /* Always configure as a 32 bit timer */ + pTmrHw[timerId].Control |= tmrHw_CONTROL_32BIT; + /* Clear interrupt only if raw status interrupt is set */ + if (pTmrHw[timerId].RawInterruptStatus) { + pTmrHw[timerId].InterruptClear = 0xFFFFFFFF; + } +} + +/****************************************************************************/ +/** +* @brief Sets counter value for an interval in ms +* +* @return On success: Effective counter value set +* On failure: 0 +* +*/ +/****************************************************************************/ +static tmrHw_INTERVAL_t SetTimerPeriod(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ + tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */ +) { + uint32_t scale = 0; + uint32_t count = 0; + + if (timerId == 0 || timerId == 1) { + if (msec <= tmrHw_LOW_1_MAX_MILLISEC) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1; + scale = tmrHw_LOW_1_RESOLUTION_COUNT; + } else if (msec <= tmrHw_LOW_16_MAX_MILLISEC) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16; + scale = tmrHw_LOW_16_RESOLUTION_COUNT; + } else if (msec <= tmrHw_LOW_256_MAX_MILLISEC) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256; + scale = tmrHw_LOW_256_RESOLUTION_COUNT; + } else { + return 0; + } + + count = msec * scale; + /* Set counter value */ + pTmrHw[timerId].LoadValue = count; + pTmrHw[timerId].BackgroundLoad = count; + + } else if (timerId == 2 || timerId == 3) { + if (msec <= tmrHw_HIGH_1_MAX_MILLISEC) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1; + scale = tmrHw_HIGH_1_RESOLUTION_COUNT; + } else if (msec <= tmrHw_HIGH_16_MAX_MILLISEC) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16; + scale = tmrHw_HIGH_16_RESOLUTION_COUNT; + } else if (msec <= tmrHw_HIGH_256_MAX_MILLISEC) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256; + scale = tmrHw_HIGH_256_RESOLUTION_COUNT; + } else { + return 0; + } + + count = msec * scale; + /* Set counter value */ + pTmrHw[timerId].LoadValue = count; + pTmrHw[timerId].BackgroundLoad = count; + } + return count / scale; +} + +/****************************************************************************/ +/** +* @brief Configures a periodic timer in terms of timer interrupt rate +* +* This function initializes a periodic timer to generate specific number of +* timer interrupt per second +* +* @return On success: Effective timer frequency +* On failure: 0 +* +*/ +/****************************************************************************/ +tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ + tmrHw_RATE_t rate /* [ IN ] Number of timer interrupt per second */ +) { + uint32_t resolution = 0; + uint32_t count = 0; + ResetTimer(timerId); + + /* Set timer mode periodic */ + pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC; + pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT; + /* Set timer in highest resolution */ + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1; + + if (rate && (timerId == 0 || timerId == 1)) { + if (rate > tmrHw_LOW_RESOLUTION_CLOCK) { + return 0; + } + resolution = tmrHw_LOW_RESOLUTION_CLOCK; + } else if (rate && (timerId == 2 || timerId == 3)) { + if (rate > tmrHw_HIGH_RESOLUTION_CLOCK) { + return 0; + } else { + resolution = tmrHw_HIGH_RESOLUTION_CLOCK; + } + } else { + return 0; + } + /* Find the counter value */ + count = resolution / rate; + /* Set counter value */ + pTmrHw[timerId].LoadValue = count; + pTmrHw[timerId].BackgroundLoad = count; + + return resolution / count; +} + +/****************************************************************************/ +/** +* @brief Configures a periodic timer to generate timer interrupt after +* certain time interval +* +* This function initializes a periodic timer to generate timer interrupt +* after every time interval in millisecond +* +* @return On success: Effective interval set in milli-second +* On failure: 0 +* +*/ +/****************************************************************************/ +tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ + tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */ +) { + ResetTimer(timerId); + + /* Set timer mode periodic */ + pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC; + pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT; + + return SetTimerPeriod(timerId, msec); +} + +/****************************************************************************/ +/** +* @brief Configures a periodic timer to generate timer interrupt just once +* after certain time interval +* +* This function initializes a periodic timer to generate a single ticks after +* certain time interval in millisecond +* +* @return On success: Effective interval set in milli-second +* On failure: 0 +* +*/ +/****************************************************************************/ +tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ + tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */ +) { + ResetTimer(timerId); + + /* Set timer mode oneshot */ + pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC; + pTmrHw[timerId].Control |= tmrHw_CONTROL_ONESHOT; + + return SetTimerPeriod(timerId, msec); +} + +/****************************************************************************/ +/** +* @brief Configures a timer to run as a free running timer +* +* This function initializes a timer to run as a free running timer +* +* @return Timer resolution (count / sec) +* +*/ +/****************************************************************************/ +tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ + uint32_t divider /* [ IN ] Dividing the clock frequency */ +) { + uint32_t scale = 0; + + ResetTimer(timerId); + /* Set timer as free running mode */ + pTmrHw[timerId].Control &= ~tmrHw_CONTROL_PERIODIC; + pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT; + + if (divider >= 64) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256; + scale = 256; + } else if (divider >= 8) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16; + scale = 16; + } else { + pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1; + scale = 1; + } + + if (timerId == 0 || timerId == 1) { + return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, scale); + } else if (timerId == 2 || timerId == 3) { + return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, scale); + } + + return 0; +} + +/****************************************************************************/ +/** +* @brief Starts a timer +* +* This function starts a preconfigured timer +* +* @return -1 - On Failure +* 0 - On Success +* +*/ +/****************************************************************************/ +int tmrHw_startTimer(tmrHw_ID_t timerId /* [ IN ] Timer id */ +) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_TIMER_ENABLE; + return 0; +} + +/****************************************************************************/ +/** +* @brief Stops a timer +* +* This function stops a running timer +* +* @return -1 - On Failure +* 0 - On Success +* +*/ +/****************************************************************************/ +int tmrHw_stopTimer(tmrHw_ID_t timerId /* [ IN ] Timer id */ +) { + pTmrHw[timerId].Control &= ~tmrHw_CONTROL_TIMER_ENABLE; + return 0; +} + +/****************************************************************************/ +/** +* @brief Gets current timer count +* +* This function returns the current timer value +* +* @return Current downcounting timer value +* +*/ +/****************************************************************************/ +uint32_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId /* [ IN ] Timer id */ +) { + /* return 32 bit timer value */ + switch (pTmrHw[timerId].Control & tmrHw_CONTROL_MODE_MASK) { + case tmrHw_CONTROL_FREE_RUNNING: + if (pTmrHw[timerId].CurrentValue) { + return tmrHw_MAX_COUNT - pTmrHw[timerId].CurrentValue; + } + break; + case tmrHw_CONTROL_PERIODIC: + case tmrHw_CONTROL_ONESHOT: + return pTmrHw[timerId].BackgroundLoad - + pTmrHw[timerId].CurrentValue; + } + return 0; +} + +/****************************************************************************/ +/** +* @brief Gets timer count rate +* +* This function returns the number of counts per second +* +* @return Count rate +* +*/ +/****************************************************************************/ +tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId /* [ IN ] Timer id */ +) { + uint32_t divider = 0; + + switch (pTmrHw[timerId].Control & tmrHw_CONTROL_PRESCALE_MASK) { + case tmrHw_CONTROL_PRESCALE_1: + divider = 1; + break; + case tmrHw_CONTROL_PRESCALE_16: + divider = 16; + break; + case tmrHw_CONTROL_PRESCALE_256: + divider = 256; + break; + default: + tmrHw_ASSERT(0); + } + + if (timerId == 0 || timerId == 1) { + return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, divider); + } else { + return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, divider); + } + return 0; +} + +/****************************************************************************/ +/** +* @brief Enables timer interrupt +* +* This function enables the timer interrupt +* +* @return N/A +* +*/ +/****************************************************************************/ +void tmrHw_enableInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */ +) { + pTmrHw[timerId].Control |= tmrHw_CONTROL_INTERRUPT_ENABLE; +} + +/****************************************************************************/ +/** +* @brief Disables timer interrupt +* +* This function disable the timer interrupt +* +* @return N/A +* +*/ +/****************************************************************************/ +void tmrHw_disableInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */ +) { + pTmrHw[timerId].Control &= ~tmrHw_CONTROL_INTERRUPT_ENABLE; +} + +/****************************************************************************/ +/** +* @brief Clears the interrupt +* +* This function clears the timer interrupt +* +* @return N/A +* +* @note +* Must be called under the context of ISR +*/ +/****************************************************************************/ +void tmrHw_clearInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */ +) { + pTmrHw[timerId].InterruptClear = 0x1; +} + +/****************************************************************************/ +/** +* @brief Gets the interrupt status +* +* This function returns timer interrupt status +* +* @return Interrupt status +*/ +/****************************************************************************/ +tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId /* [ IN ] Timer id */ +) { + if (pTmrHw[timerId].InterruptStatus) { + return tmrHw_INTERRUPT_STATUS_SET; + } else { + return tmrHw_INTERRUPT_STATUS_UNSET; + } +} + +/****************************************************************************/ +/** +* @brief Indentifies a timer causing interrupt +* +* This functions returns a timer causing interrupt +* +* @return 0xFFFFFFFF : No timer causing an interrupt +* ! 0xFFFFFFFF : timer causing an interrupt +* @note +* tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function +*/ +/****************************************************************************/ +tmrHw_ID_t tmrHw_getInterruptSource(void /* void */ +) { + int i; + + for (i = 0; i < tmrHw_TIMER_NUM_COUNT; i++) { + if (pTmrHw[i].InterruptStatus) { + return i; + } + } + + return 0xFFFFFFFF; +} + +/****************************************************************************/ +/** +* @brief Displays specific timer registers +* +* +* @return void +* +*/ +/****************************************************************************/ +void tmrHw_printDebugInfo(tmrHw_ID_t timerId, /* [ IN ] Timer id */ + int (*fpPrint) (const char *, ...) /* [ IN ] Print callback function */ +) { + (*fpPrint) ("Displaying register contents \n\n"); + (*fpPrint) ("Timer %d: Load value 0x%X\n", timerId, + pTmrHw[timerId].LoadValue); + (*fpPrint) ("Timer %d: Background load value 0x%X\n", timerId, + pTmrHw[timerId].BackgroundLoad); + (*fpPrint) ("Timer %d: Control 0x%X\n", timerId, + pTmrHw[timerId].Control); + (*fpPrint) ("Timer %d: Interrupt clear 0x%X\n", timerId, + pTmrHw[timerId].InterruptClear); + (*fpPrint) ("Timer %d: Interrupt raw interrupt 0x%X\n", timerId, + pTmrHw[timerId].RawInterruptStatus); + (*fpPrint) ("Timer %d: Interrupt status 0x%X\n", timerId, + pTmrHw[timerId].InterruptStatus); +} + +/****************************************************************************/ +/** +* @brief Use a timer to perform a busy wait delay for a number of usecs. +* +* @return N/A +*/ +/****************************************************************************/ +void tmrHw_udelay(tmrHw_ID_t timerId, /* [ IN ] Timer id */ + unsigned long usecs /* [ IN ] usec to delay */ +) { + tmrHw_RATE_t usec_tick_rate; + tmrHw_COUNT_t start_time; + tmrHw_COUNT_t delta_time; + + start_time = tmrHw_GetCurrentCount(timerId); + usec_tick_rate = tmrHw_divide(tmrHw_getCountRate(timerId), 1000000); + delta_time = usecs * usec_tick_rate; + + /* Busy wait */ + while (delta_time > (tmrHw_GetCurrentCount(timerId) - start_time)) + ; +} + +/****************************************************************************/ +/** +* @brief Local Divide function +* +* This function does the divide +* +* @return divide value +* +*/ +/****************************************************************************/ +static int tmrHw_divide(int num, int denom) +{ + int r; + int t = 1; + + /* Shift denom and t up to the largest value to optimize algorithm */ + /* t contains the units of each divide */ + while ((denom & 0x40000000) == 0) { /* fails if denom=0 */ + denom = denom << 1; + t = t << 1; + } + + /* Intialize the result */ + r = 0; + + do { + /* Determine if there exists a positive remainder */ + if ((num - denom) >= 0) { + /* Accumlate t to the result and calculate a new remainder */ + num = num - denom; + r = r + t; + } + /* Continue to shift denom and shift t down to 0 */ + denom = denom >> 1; + t = t >> 1; + } while (t != 0); + return r; +} |