nuttx/arch/arm/src/efm32/efm32_timer.c

235 lines
8.1 KiB
C

/****************************************************************************
* arch/arm/src/efm32/efm32_timer.c
*
* Copyright (C) 2014 Pierre-Noel Bouteville. All rights reserved.
* Author: Pierre-Noel Bouteville <pnb990@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <arch/board/board.h>
#include "up_arch.h"
#include "up_internal.h"
#include "chip/efm32_timer.h"
#include "efm32_config.h"
#include "efm32_gpio.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Debug ********************************************************************/
#ifdef CONFIG_DEBUG_TIMER_INFO
# define efm32_timer_dumpgpio(p,m) efm32_dumpgpio(p,m)
#else
# define efm32_timer_dumpgpio(p,m)
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: efm32_timer_dumpregs
*
* Description:
* Dump all timer registers.
*
* Input parameters:
* base - A base address of timer
*
* Returned Value:
* None
*
****************************************************************************/
void efm32_timer_dumpregs(uintptr_t base, FAR const char *msg)
{
#ifdef CONFIG_DEBUG_TIMER_INFO
int i;
tmrinfo("%s:\n", msg);
tmrinfo(" CTRL: %04x STATUS: %04x IEN: %04x IF: %04x\n",
getreg32(base + EFM32_TIMER_CTRL_OFFSET ),
getreg32(base + EFM32_TIMER_STATUS_OFFSET ),
getreg32(base + EFM32_TIMER_IEN_OFFSET ),
getreg32(base + EFM32_TIMER_IF_OFFSET ));
tmrinfo(" TOP: %04x TOPB: %04x CNT: %04x ROUTE: %04x\n",
getreg32(base + EFM32_TIMER_TOP_OFFSET ),
getreg32(base + EFM32_TIMER_TOPB_OFFSET ),
getreg32(base + EFM32_TIMER_CNT_OFFSET ),
getreg32(base + EFM32_TIMER_ROUTE_OFFSET ));
for (i = 0; i < EFM32_TIMER_NCC; i++)
{
uintptr_t base_cc = base + EFM32_TIMER_CC_OFFSET(i);
tmrinfo("CC%d => CTRL: %04x CCV: %04x CCVP: %04x CCVB: %04x\n",
i
getreg32(base_cc + EFM32_TIMER_CC_CTRL_OFFSET ),
getreg32(base_cc + EFM32_TIMER_CC_CCV_OFFSET ),
getreg32(base_cc + EFM32_TIMER_CC_CCVP_OFFSET ),
getreg32(base_cc + EFM32_TIMER_CC_CCVB_OFFSET ));
}
tmrinfo("DTCTRL: %04x DTTIME: %04x DTFC: %04x DTOGEN: %04x\n",
getreg32(base + EFM32_TIMER_CTRL_OFFSET ),
getreg32(base + EFM32_TIMER_STATUS_OFFSET ),
getreg32(base + EFM32_TIMER_IEN_OFFSET ),
getreg32(base + EFM32_TIMER_IF_OFFSET ));
tmrinfo("DTFAULT: %04x DTFAULTC: %04x DTLOCK: %04x \n",
getreg32(base + EFM32_TIMER_CTRL_OFFSET ),
getreg32(base + EFM32_TIMER_STATUS_OFFSET ),
getreg32(base + EFM32_TIMER_IEN_OFFSET ),
#endif
}
/****************************************************************************
* Name: efm32_timer_reset
*
* Description:
* reset timer into reset state
*
* Input parameters:
* base - A base address of timer
*
* Returned Value:
* None
*
****************************************************************************/
void efm32_timer_reset(uintptr_t base)
{
int i;
/* Make sure disabled first, before resetting other registers */
putreg32(TIMER_CMD_STOP, base + EFM32_TIMER_CMD_OFFSET);
/* Reset timer register */
putreg32(_TIMER_CTRL_RESETVALUE, base + EFM32_TIMER_CTRL_OFFSET );
putreg32(_TIMER_IEN_RESETVALUE, base + EFM32_TIMER_STATUS_OFFSET );
putreg32(_TIMER_IFC_MASK, base + EFM32_TIMER_IEN_OFFSET );
putreg32(_TIMER_TOP_RESETVALUE, base + EFM32_TIMER_IF_OFFSET );
putreg32(_TIMER_TOPB_RESETVALUE, base + EFM32_TIMER_CTRL_OFFSET );
putreg32(_TIMER_CNT_RESETVALUE, base + EFM32_TIMER_CMD_OFFSET );
/* Do not reset route register, setting should be done independently
* (Note: ROUTE register may be locked by DTLOCK register.)
*/
//putreg32(_TIMER_ROUTE_RESETVALUE, base + EFM32_TIMER_ROUTE_OFFSET );
for (i = 0; i < EFM32_TIMER_NCC; i++)
{
uintptr_t base_cc = base + EFM32_TIMER_CC_OFFSET(i);
putreg32(_TIMER_CC_CTRL_RESETVALUE, base_cc+EFM32_TIMER_CC_CTRL_OFFSET);
putreg32(_TIMER_CC_CCV_RESETVALUE, base_cc+EFM32_TIMER_CC_CCV_OFFSET );
putreg32(_TIMER_CC_CCVB_RESETVALUE, base_cc+EFM32_TIMER_CC_CCVB_OFFSET);
}
/* Reset dead time insertion module, no effect on timers without DTI */
#ifdef TIMER_DTLOCK_LOCKKEY_UNLOCK
/* Unlock DTI registers first in case locked */
putreg32(TIMER_DTLOCK_LOCKKEY_UNLOCK, base + EFM32_TIMER_DTLOCK_OFFSET);
putreg32(_TIMER_DTCTRL_RESETVALUE, base + EFM32_TIMER_DTCTRL_OFFSET);
putreg32(_TIMER_DTTIME_RESETVALUE, base + EFM32_TIMER_DTTIME_OFFSET);
putreg32(_TIMER_DTFC_RESETVALUE, base + EFM32_TIMER_DTFC_OFFSET);
putreg32(_TIMER_DTOGEN_RESETVALUE,base + EFM32_TIMER_DTOGEN_OFFSET);
putreg32(_TIMER_DTFAULTC_MASK, base + EFM32_TIMER_DTFAULTC_OFFSET);
#endif
}
/****************************************************************************
* Name: efm32_timer_set_freq
*
* Description:
* set prescaler and top timer with best value to have "freq"
*
* Input parameters:
* base - A base address of timer
* clk_freq - Clock soure of timer.
* freq - Wanted freqency.
*
* Returned Value:
* prescaler setted, -1 in case of error.
*
****************************************************************************/
int efm32_timer_set_freq(uintptr_t base, uint32_t clk_freq, uint32_t freq)
{
int prescaler = 0;
int cnt_freq = clk_freq >> 16;
int reload;
while (cnt_freq > freq)
{
prescaler++;
cnt_freq >>= 1;
if (prescaler > (_TIMER_CTRL_PRESC_MASK >> _TIMER_CTRL_PRESC_SHIFT))
{
return -1;
}
}
modifyreg32(base + EFM32_TIMER_CTRL_OFFSET,
_TIMER_CTRL_PRESC_MASK,
prescaler << _TIMER_CTRL_PRESC_SHIFT);
prescaler = 1 << prescaler;
reload = (clk_freq / prescaler / freq);
tmrinfo("Source: %4xHz Div: %4x Reload: %4x \n", clk_freq, prescaler, reload);
putreg32(reload, base + EFM32_TIMER_TOP_OFFSET);
return prescaler;
}