Tiva Timer: First cut at timer driver lower half (still incomplete)

This commit is contained in:
Gregory Nutt
2015-01-12 15:52:48 -06:00
parent c93b205eea
commit bbfc5cf747
4 changed files with 958 additions and 34 deletions
+3
View File
@@ -98,6 +98,9 @@ endif
ifeq ($(CONFIG_TIVA_TIMER),y)
CHIP_CSRCS += tiva_timer.c
ifeq ($(CONFIG_TIMER),y)
CHIP_CSRCS += tiva_timerlow.c
endif
endif
ifeq ($(CONFIG_NET),y)
+300 -6
View File
@@ -820,10 +820,11 @@ static int tiva_oneshot_periodic_mode32(struct tiva_gptmstate_s *priv,
#warning Missing Logic
/* Enable one-shot/periodic interrupts? Enable interrupts only if an
* interrupt handler was provided.
* non-NULL interrupt handler and non-zero timeout interval were
* provided.
*/
if (timer->handler)
if (timer->handler && timer->u.periodic.interval > 0)
{
/* Select the interrupt mask that will enable the timer interrupt.
* Any non-zero value of imr indicates that interrupts are expected.
@@ -1527,8 +1528,8 @@ static int tiva_timer16_configure(struct tiva_gptmstate_s *priv,
TIMER_HANDLE tiva_gptm_configure(const struct tiva_gptmconfig_s *config)
{
static const struct tiva_gptmattr_s *attr;
static struct tiva_gptmstate_s *priv;
const struct tiva_gptmattr_s *attr;
struct tiva_gptmstate_s *priv;
uint32_t regval;
int ret;
@@ -1542,7 +1543,7 @@ TIMER_HANDLE tiva_gptm_configure(const struct tiva_gptmconfig_s *config)
case 0:
/* Enable GPTM0 clocking and power */
attr = &g_gptm0_attr;
priv = &g_gptm0_state;
break;
@@ -1632,7 +1633,7 @@ TIMER_HANDLE tiva_gptm_configure(const struct tiva_gptmconfig_s *config)
while (!tiva_gpio_periphrdy(config->gptm));
/* Reset the time to be certain that it is in the disabled state */
/* Reset the timer to be certain that it is in the disabled state */
regval = tiva_getreg(priv, TIVA_SYSCON_SRTIMER);
regval |= SYSCON_SRTIMER(config->gptm);
@@ -1744,6 +1745,64 @@ TIMER_HANDLE tiva_gptm_configure(const struct tiva_gptmconfig_s *config)
return ret < 0 ? (TIMER_HANDLE)NULL : (TIMER_HANDLE)priv;
}
/****************************************************************************
* Name: tiva_gptm_release
*
* Description:
* Release resources held by the timer instance. After this function is
* called, the timer handle is invalid and must not be used further.
*
* Input Parameters:
* handle - The handle value returned by tiva_gptm_configure()
*
* Returned Value:
* None.
*
****************************************************************************/
void tiva_gptm_release(TIMER_HANDLE handle)
{
struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle;
const struct tiva_gptmconfig_s *config;
const struct tiva_gptmattr_s *attr;
uint32_t regval;
DEBUGASSERT(priv && priv->attr && priv->config);
config = priv->config;
attr = priv->attr;
/* Disable and detach interrupt handlers */
up_disable_irq(attr->irq[TIMER16A]);
up_disable_irq(attr->irq[TIMER16B]);
(void)irq_detach(attr->irq[TIMER16A]);
(void)irq_detach(attr->irq[TIMER16B]);
/* Reset the time to be certain that it is in the disabled state */
regval = tiva_getreg(priv, TIVA_SYSCON_SRTIMER);
regval |= SYSCON_SRTIMER(config->gptm);
tiva_putreg(priv, TIVA_SYSCON_SRTIMER, regval);
regval &= ~SYSCON_SRTIMER(config->gptm);
tiva_putreg(priv, TIVA_SYSCON_SRTIMER, regval);
/* Wait for the reset to complete */
while (!tiva_emac_periphrdy());
up_udelay(250);
/* Disable power and clocking to the GPTM module */
tiva_gptm_disableclk(config->gptm);
tiva_gptm_disablepwr(config->gptm);
/* Un-initialize the state structure */
memset(priv, 0, sizeof(struct tiva_gptmstate_s));
}
/****************************************************************************
* Name: tiva_gptm_putreg
*
@@ -2083,6 +2142,241 @@ uint32_t tiva_timer16_counter(TIMER_HANDLE handle, int tmndx)
return counter;
}
/****************************************************************************
* Name: tiva_timer32_setinterval
*
* Description:
* This function may be called at any time to change the timer interval
* load value of a 32-bit timer.
*
* Input Parameters:
* handle - The handle value returned by tiva_gptm_configure()
* interval - The value to write to the timer interval load register
*
* Returned Value:
* None.
*
****************************************************************************/
void tiva_timer32_setinterval(TIMER_HANDLE handle, uint32_t interval)
{
struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle;
const struct tiva_gptm32config_s *config;
const struct tiva_timer32config_s *timer;
irqstate_t flags;
uintptr_t base;
uintptr_t moder;
uintptr_t loadr;
uintptr_t icrr;
uintptr_t imrr;
uint32_t modev1;
uint32_t modev2;
bool toints;
DEBUGASSERT(priv && priv->attr && priv->config &&
priv->config->mode != TIMER16_MODE);
config = (const struct tiva_gptm32config_s *)priv->config;
timer = &config->config;
/* Do we need to control timeout interrupts? */
base = priv->attr->base;
if (timer->handler && interval > 0 &&
(config->cmn.mode == TIMER32_MODE_ONESHOT ||
config->cmn.mode == TIMER32_MODE_PERIODIC))
{
priv->imr |= TIMER_INT_TATO;
toints = true;
}
else
{
priv->imr &= ~TIMER_INT_TATO;
toints = false;
}
loadr = base + TIVA_TIMER_TAILR_OFFSET;
moder = base + TIVA_TIMER_TAMR_OFFSET;
icrr = base + TIVA_TIMER_ICR_OFFSET;
imrr = base + TIVA_TIMER_IMR_OFFSET;
/* Make the following atomic */
flags = irqsave();
/* Set the new timeout interval */
putreg32(interval, loadr);
/* Enable/disable timeout interrupts */
if (toints)
{
/* Clearing the TACINTD bit allows the time-out interrupt to be
* generated as normal
*/
modev1 = tiva_getreg(priv, moder);
modev2 = modev1 & ~TIMER_TnMR_TnCINTD;
putreg32(modev2, moder);
}
else
{
/* Setting the TACINTD bit prevents the time-out interrupt */
modev1 = tiva_getreg(priv, moder);
modev2 = modev1 | TIMER_TnMR_TnCINTD;
putreg32(modev2, moder);
/* Clear any pending timeout interrupts */
putreg32(TIMER_INT_TATO, icrr);
}
/* Set the new interrupt mask */
putreg32(priv->imr, imrr);
irqrestore(flags);
#ifdef CONFIG_TIVA_TIMER_REGDEBUG
/* Generate low-level debug output outside of the critical section */
lldbg("%08x<-%08x\n", loadr, interval);
lldbg("%08x->%08x\n", moder, modev1);
lldbg("%08x<-%08x\n", moder, modev2);
if (!toints)
{
lldbg("%08x->%08x\n", icrr, TIMER_INT_TATO);
}
lldbg("%08x<-%08x\n", imrr, priv->imr);
#endif
}
/****************************************************************************
* Name: tiva_timer16_setinterval
*
* Description:
* This function may be called at any time to change the timer interval
* load value of a 16-bit timer.
*
* Input Parameters:
* handle - The handle value returned by tiva_gptm_configure()
* interval - The value to write to the timer interval load register
* tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer
*
* Returned Value:
* None.
*
****************************************************************************/
void tiva_timer16_setinterval(TIMER_HANDLE handle, uint16_t interval, int tmndx)
{
struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle;
const struct tiva_gptm16config_s *config;
const struct tiva_timer16config_s *timer;
irqstate_t flags;
uintptr_t base;
uintptr_t moder;
uintptr_t loadr;
uintptr_t icrr;
uintptr_t imrr;
uint32_t intbit;
uint32_t modev1;
uint32_t modev2;
bool toints;
DEBUGASSERT(priv && priv->attr && priv->config &&
priv->config->mode != TIMER16_MODE);
config = (const struct tiva_gptm16config_s *)priv->config;
timer = &config->config[tmndx];
/* Pre-calculate as much as possible outside of the critical section */
base = priv->attr->base;
if (tmndx)
{
intbit = TIMER_INT_TBTO;
loadr = base + TIVA_TIMER_TBILR_OFFSET;
moder = base + TIVA_TIMER_TBMR_OFFSET;
}
else
{
intbit = TIMER_INT_TATO;
loadr = base + TIVA_TIMER_TAILR_OFFSET;
moder = base + TIVA_TIMER_TAMR_OFFSET;
}
icrr = base + TIVA_TIMER_ICR_OFFSET;
imrr = base + TIVA_TIMER_IMR_OFFSET;
/* Do we need to control timeout interrupts? */
if (timer->handler && interval > 0 &&
(config->cmn.mode == TIMER16_MODE_ONESHOT ||
config->cmn.mode == TIMER16_MODE_PERIODIC))
{
priv->imr |= intbit;
toints = true;
}
else
{
priv->imr &= ~intbit;
toints = false;
}
/* Make the following atomic */
flags = irqsave();
/* Set the new timeout interval */
putreg32(interval, loadr);
/* Enable/disable timeout interrupts */
if (toints)
{
/* Clearing the TACINTD bit allows the time-out interrupt to be
* generated as normal
*/
modev1 = tiva_getreg(priv, moder);
modev2 = modev1 & ~TIMER_TnMR_TnCINTD;
putreg32(modev2, moder);
}
else
{
/* Setting the TACINTD bit prevents the time-out interrupt */
modev1 = tiva_getreg(priv, moder);
modev2 = modev1 | TIMER_TnMR_TnCINTD;
putreg32(modev2, moder);
/* Clear any pending timeout interrupts */
putreg32(intbit, icrr);
}
/* Set the new interrupt mask */
putreg32(priv->imr, imrr);
irqrestore(flags);
#ifdef CONFIG_TIVA_TIMER_REGDEBUG
/* Generate low-level debug output outside of the critical section */
lldbg("%08x<-%08x\n", loadr, interval);
lldbg("%08x->%08x\n", moder, modev1);
lldbg("%08x<-%08x\n", moder, modev2);
if (!toints)
{
lldbg("%08x->%08x\n", icrr, intbit);
}
lldbg("%08x<-%08x\n", imrr, priv->imr);
#endif
}
/****************************************************************************
* Name: tiva_rtc_setalarm
*
+72 -28
View File
@@ -47,6 +47,8 @@
#include <arch/tiva/chip.h>
#include "up_arch.h"
#include "chip.h"
#include "chip/tiva_timer.h"
/****************************************************************************
@@ -125,6 +127,20 @@
#define TIMER_ISDMARTCM(c) ((((c)->flags) & TIMER_FLAG_DMARTCM) != 0)
#define TIMER_ISDMAMATCH(c) ((((c)->flags) & TIMER_FLAG_DMAMATCH) != 0)
/* Debug ********************************************************************/
/* Non-standard debug that may be enabled just for testing the timer
* driver. NOTE: that only lldbg types are used so that the output is
* immediately available.
*/
#ifdef CONFIG_DEBUG_TIMER
# define timdbg lldbg
# define timvdbg llvdbg
#else
# define timdbg(x...)
# define timvdbg(x...)
#endif
/****************************************************************************
* Public Types
****************************************************************************/
@@ -320,6 +336,23 @@ struct tiva_gptm16config_s
TIMER_HANDLE tiva_gptm_configure(const struct tiva_gptmconfig_s *gptm);
/****************************************************************************
* Name: tiva_gptm_release
*
* Description:
* Release resources held by the timer instance. After this function is
* called, the timer handle is invalid and must not be used further.
*
* Input Parameters:
* handle - The handle value returned by tiva_gptm_configure()
*
* Returned Value:
* None.
*
****************************************************************************/
void tiva_gptm_release(TIMER_HANDLE handle);
/****************************************************************************
* Name: tiva_gptm_putreg
*
@@ -504,61 +537,44 @@ static inline uint32_t tiva_timer32_counter(TIMER_HANDLE handle)
uint32_t tiva_timer16_counter(TIMER_HANDLE handle, int tmndx);
/****************************************************************************
* Name: tiva_timer32_setload
* Name: tiva_timer32_setinterval
*
* Description:
* This function may be called at any time to change the timer interval
* load value of a 32-bit timer.
*
* Input Parameters:
* handle - The handle value returned by tiva_gptm_configure()
* load - The value to write to the timer interval load register
* handle - The handle value returned by tiva_gptm_configure()
* interval - The value to write to the timer interval load register
*
* Returned Value:
* None.
*
****************************************************************************/
static inline void tiva_timer32_setload(TIMER_HANDLE handle, uint32_t load)
{
tiva_gptm_putreg(handle, TIVA_TIMER_TAILR_OFFSET, load);
}
void tiva_timer32_setinterval(TIMER_HANDLE handle, uint32_t interval);
/****************************************************************************
* Name: tiva_timer16_setload
* Name: tiva_timer16_setinterval
*
* Description:
* This function may be called at any time to change the timer interval
* load value of a 16-bit timer.
*
* Input Parameters:
* handle - The handle value returned by tiva_gptm_configure()
* load - The value to write to the timer interval load register
* tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer
* handle - The handle value returned by tiva_gptm_configure()
* interval - The value to write to the timer interval load register
* tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer
*
* Returned Value:
* None.
*
****************************************************************************/
static inline void tiva_timer16_setload(TIMER_HANDLE handle, uint16_t load,
int tmndx)
{
unsigned int regoffset =
tmndx ? TIVA_TIMER_TBILR_OFFSET : TIVA_TIMER_TAILR_OFFSET;
void tiva_timer16_setinterval(TIMER_HANDLE handle, uint16_t interval, int tmndx);
tiva_gptm_putreg(handle, regoffset, load);
}
static inline void tiva_timer16a_setload(TIMER_HANDLE handle, uint16_t load)
{
tiva_gptm_putreg(handle, TIVA_TIMER_TAILR_OFFSET, load);
}
static inline void tiva_timer16b_setload(TIMER_HANDLE handle, uint16_t load)
{
tiva_gptm_putreg(handle, TIVA_TIMER_TBILR_OFFSET, load);
}
#define tiva_timer16a_setinterval(h,l) tiva_timer16_setinterval(h,l,TIMER16A)
#define tiva_timer16b_setinterval(h,l) tiva_timer16_setinterval(h,l,TIMER16B)
/****************************************************************************
* Name: tiva_timer32_absmatch
@@ -768,4 +784,32 @@ static inline void tiva_gptm0_synchronize(uint32_t sync)
putreg32(sync, TIVA_TIMER0_SYNC);
}
/****************************************************************************
* Name: tiva_timer_register
*
* Description:
* Bind the configuration timer to a timer lower half instance and
* register the timer drivers at 'devpath'
*
* NOTE: Only 32-bit periodic timers are supported.
*
* Input Parameters:
* devpath - The full path to the timer device. This should be of the form
* /dev/timer0
* gptm - General purpose timer number
* timeout - Timeout interval in milliseconds. Set to a non-zero value
* to enable timeout interrupts
* altlck - True: Use alternate clock source.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
#ifdef CONFIG_TIMER
int tiva_timer_register(FAR const char *devpath, int gptm, uint32_t timeout,
bool altclk);
#endif
#endif /* __ARCH_ARM_SRC_TIVA_TIVA_TIMER_H */
File diff suppressed because it is too large Load Diff