blob: 6d10b54e7b252f88eed82cdea5355a3e39ddea99 [file] [log] [blame]
/****************************************************************************
* arch/arm/src/tlsr82/tlsr82_timer.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <sys/types.h>
#include <stdbool.h>
#include <assert.h>
#include <debug.h>
#include "tlsr82_timer.h"
#include "hardware/tlsr82_irq.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
struct tlsr82_timer_priv_s
{
struct tlsr82_timer_ops_s *ops;
enum tlsr82_timer_inst_e inst; /* Timer instance */
uint8_t periph; /* Peripheral ID */
int irq; /* Interrupt ID */
bool inuse; /* Flag indicating if the timer is in use */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* TIM operations ***********************************************************/
static void tlsr82_timer_start(struct tlsr82_timer_dev_s *dev);
static void tlsr82_timer_stop(struct tlsr82_timer_dev_s *dev);
static void tlsr82_timer_clear(struct tlsr82_timer_dev_s *dev);
static void tlsr82_timer_setmode(struct tlsr82_timer_dev_s *dev,
enum tlsr82_timer_mode_e mode);
static void tlsr82_timer_getcounter(struct tlsr82_timer_dev_s *dev,
uint32_t *value);
static void tlsr82_timer_setcounter(struct tlsr82_timer_dev_s *dev,
uint32_t value);
static void tlsr82_timer_getcapture(struct tlsr82_timer_dev_s *dev,
uint32_t *value);
static void tlsr82_timer_setcapture(struct tlsr82_timer_dev_s *dev,
uint32_t value);
static void tlsr82_timer_getclock(struct tlsr82_timer_dev_s *dev,
uint32_t *value);
static int tlsr82_timer_setisr(struct tlsr82_timer_dev_s *dev,
xcpt_t handler, void * arg);
static void tlsr82_timer_enableint(struct tlsr82_timer_dev_s *dev);
static void tlsr82_timer_disableint(struct tlsr82_timer_dev_s *dev);
static void tlsr82_timer_ackint(struct tlsr82_timer_dev_s *dev);
static int tlsr82_timer_checkint(struct tlsr82_timer_dev_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
/* TLSR82 TIMER ops */
struct tlsr82_timer_ops_s tlsr82_timer_ops =
{
.start = tlsr82_timer_start,
.stop = tlsr82_timer_stop,
.clear = tlsr82_timer_clear,
.setmode = tlsr82_timer_setmode,
.getcounter = tlsr82_timer_getcounter,
.setcounter = tlsr82_timer_setcounter,
.getcapture = tlsr82_timer_getcapture,
.setcapture = tlsr82_timer_setcapture,
.getclock = tlsr82_timer_getclock,
.setisr = tlsr82_timer_setisr,
.enableint = tlsr82_timer_enableint,
.disableint = tlsr82_timer_disableint,
.ackint = tlsr82_timer_ackint,
.checkint = tlsr82_timer_checkint
};
struct tlsr82_timer_priv_s g_tlsr82_timers_priv[] =
{
#ifdef CONFIG_TLSR82_TIMER1
{
.ops = &tlsr82_timer_ops,
.inst = TLSR82_INST_TIMER1,
.irq = NR_TIMER1_IRQ, /* Interrupt ID */
.inuse = false,
},
#endif
#ifdef CONFIG_TLSR82_TIMER2
{
.ops = &tlsr82_timer_ops,
.inst = TLSR82_INST_TIMER2,
.irq = NR_TIMER2_IRQ, /* Interrupt ID */
.inuse = false,
},
#endif
};
/* TIMER0 is used for os tick */
#ifdef CONFIG_TLSR82_TIMER1
/* TIMER1 */
struct tlsr82_timer_priv_s g_tlsr82_timer1_priv =
{
.ops = &tlsr82_timer_ops,
.inst = TLSR82_INST_TIMER1,
.irq = NR_TIMER1_IRQ, /* Interrupt ID */
.inuse = false,
};
#endif
#ifdef CONFIG_TLSR82_TIMER2
/* TIMER2 */
struct tlsr82_timer_priv_s g_tlsr82_timer2_priv =
{
.ops = &tlsr82_timer_ops,
.inst = TLSR82_INST_TIMER2,
.irq = NR_TIMER2_IRQ, /* Interrupt ID */
.inuse = false,
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: tlsr82_timer_start
*
* Description:
* Release the counter.
*
* Parameters:
* dev - Pointer to the timer driver struct.
*
****************************************************************************/
static void tlsr82_timer_start(struct tlsr82_timer_dev_s *dev)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
BM_SET(TIMER_CTRL_REG, TIMER_CTRL_T1_ENABLE);
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
BM_SET(TIMER_CTRL_REG, TIMER_CTRL_T2_ENABLE);
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_stop
*
* Description:
* Halt the counter.
*
* Parameters:
* dev - Pointer to the timer driver struct.
*
****************************************************************************/
static void tlsr82_timer_stop(struct tlsr82_timer_dev_s *dev)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
BM_CLR(TIMER_CTRL_REG, TIMER_CTRL_T1_ENABLE);
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
BM_CLR(TIMER_CTRL_REG, TIMER_CTRL_T2_ENABLE);
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_clear
*
* Description:
* Set the counter to zero instantly.
*
* Parameters:
* dev - Pointer to the timer driver struct.
*
****************************************************************************/
static void tlsr82_timer_clear(struct tlsr82_timer_dev_s *dev)
{
DEBUGASSERT(dev);
tlsr82_timer_setcounter(dev, 0);
}
/****************************************************************************
* Name: tlsr82_timer_setmode
*
* Description:
* Set counter mode.
*
* Parameters:
* dev - Pointer to the timer driver struct.
* mode - Variable indicating the counting direction (up/down).
*
****************************************************************************/
static void tlsr82_timer_setmode(struct tlsr82_timer_dev_s *dev,
enum tlsr82_timer_mode_e mode)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
if (mode >= TLSR82_TIMER_MODE_NUM)
{
tmrerr("Timer mode error, mode: %d\n", (int)mode);
return;
}
if (priv->inst == TLSR82_INST_TIMER1)
{
BM_CLR(TIMER_CTRL_REG, TIMER_CTRL_T1_MODE);
BM_SET(TIMER_CTRL_REG, ((uint32_t)mode << TIMER_CTRL_T1_MODE_SHIFT));
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
BM_CLR(TIMER_CTRL_REG, TIMER_CTRL_T2_MODE);
BM_SET(TIMER_CTRL_REG, ((uint32_t)mode << TIMER_CTRL_T2_MODE_SHIFT));
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_getcounter
*
* Description:
* Get the current counter value.
*
* Parameters:
* dev - Pointer to the timer driver struct.
* value - A pointer to a variable to store the current read
* value from counter.
*
****************************************************************************/
static void tlsr82_timer_getcounter(struct tlsr82_timer_dev_s *dev,
uint32_t *value)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
DEBUGASSERT(value);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
*value = TIMER_TICK1_REG;
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
*value = TIMER_TICK2_REG;
}
else
{
*value = 0;
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_setcounter
*
* Description:
* Set the value to be loaded to the counter.
* If you want the counter to be loaded at an alarm, enable the alarm and
* the auto-reload before.
* If you want the counter to be loaded instantly, call
* tlsr82_timer_reload_now() after this function.
*
* Parameters:
* dev - Pointer to the timer driver struct.
* value - The value to be loaded the counter.
*
****************************************************************************/
static void tlsr82_timer_setcounter(struct tlsr82_timer_dev_s *dev,
uint32_t value)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
TIMER_TICK1_REG = value;
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
TIMER_TICK2_REG = value;
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_getcapture
*
* Description:
* Get the alarm value.
*
* Parameters:
* dev - Pointer to the timer driver struct.
* value - Pointer to retrieve the current configured alarm value.
*
****************************************************************************/
static void tlsr82_timer_getcapture(struct tlsr82_timer_dev_s *dev,
uint32_t *value)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
DEBUGASSERT(value);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
*value = TIMER_CAPT1_REG;
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
*value = TIMER_CAPT2_REG;
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_setcapture
*
* Description:
* Set the value that will trigger an alarm when the
* counter value matches this value.
*
* Parameters:
* dev - Pointer to the timer driver struct.
* value - The alarm value.
*
****************************************************************************/
static void tlsr82_timer_setcapture(struct tlsr82_timer_dev_s *dev,
uint32_t value)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
TIMER_CAPT1_REG = value;
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
TIMER_CAPT2_REG = value;
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_getclock
*
* Description:
* Get the timer clock.
*
* Parameters:
* dev - Pointer to the timer driver struct.
* value - Pointer to clock value (MHz).
*
****************************************************************************/
static void tlsr82_timer_getclock(struct tlsr82_timer_dev_s *dev,
uint32_t *value)
{
DEBUGASSERT(dev);
DEBUGASSERT(value);
/* Timer clock always using the system clock */
*value = CONFIG_TLSR82_CPU_CLK_MHZ;
}
/****************************************************************************
* Name: tlsr82_timer_setisr
*
* Description:
* Allocate a CPU Interrupt, connect the peripheral source to this
* Interrupt, register the callback and enable CPU the Interruption.
* In case a NULL handler is provided, deallocate the interrupt and
* unregister the previously provided handler.
*
* Parameters:
* dev - Pointer to the driver state structure.
* handler - Callback to be invoked on timer interrupt.
* arg - Argument to be passed to the handler callback.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
static int tlsr82_timer_setisr(struct tlsr82_timer_dev_s *dev,
xcpt_t handler, void *arg)
{
struct tlsr82_timer_priv_s *priv = NULL;
int ret = OK;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
/* Disable interrupt when callback is removed. */
if (handler == NULL)
{
if (priv->irq < NR_IRQS)
{
/* Disable cpu interrupt */
up_disable_irq(priv->irq);
/* Dissociate the IRQ from the ISR */
irq_detach(priv->irq);
}
}
/* Otherwise set callback and enable interrupt */
else
{
if (priv->irq < NR_IRQS)
{
/* Disable the provided CPU interrupt to configure it. */
up_disable_irq(priv->irq);
/* Associate an IRQ Number (from the timer) to an ISR */
ret = irq_attach(priv->irq, handler, arg);
if (ret != OK)
{
tmrerr("ERROR: Failed to associate an IRQ Number to and ISR");
goto errout;
}
/* Enable the CPU Interrupt that is linked to the timer */
up_enable_irq(priv->irq);
}
else
{
tmrerr("Timer isr can't attach, irq number=%d is invalid\n",
priv->irq);
}
}
errout:
return ret;
}
/****************************************************************************
* Name: tlsr82_timer_enableint
*
* Description:
* Enable a level Interrupt at the alarm if it is set.
*
* Parameters:
* dev - Pointer to the timer driver struct.
*
****************************************************************************/
static void tlsr82_timer_enableint(struct tlsr82_timer_dev_s *dev)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
up_enable_irq(NR_TIMER1_IRQ);
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
up_enable_irq(NR_TIMER2_IRQ);
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_disableint
*
* Description:
* Disable a level Interrupt at the alarm if it is set.
*
* Parameters:
* dev - Pointer to the timer driver struct.
*
****************************************************************************/
static void tlsr82_timer_disableint(struct tlsr82_timer_dev_s *dev)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
up_disable_irq(NR_TIMER1_IRQ);
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
up_disable_irq(NR_TIMER2_IRQ);
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_ackint
*
* Description:
* Acknowledge an interrupt, that means, clear the interrupt.
*
* Parameters:
* dev - Pointer to the timer driver struct.
*
****************************************************************************/
static void tlsr82_timer_ackint(struct tlsr82_timer_dev_s *dev)
{
struct tlsr82_timer_priv_s *priv;
DEBUGASSERT(dev);
priv = (struct tlsr82_timer_priv_s *)dev;
if (priv->inst == TLSR82_INST_TIMER1)
{
BM_SET(TIMER_STATUS_REG, TIMER_STATUS_T1_CLR);
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
BM_SET(TIMER_STATUS_REG, TIMER_STATUS_T2_CLR);
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
}
/****************************************************************************
* Name: tlsr82_timer_checkint
*
* Description:
* Check the interrupt status bit.
*
* Parameters:
* dev - Pointer to the timer driver struct.
*
* Returned Values:
* Return 1 in case of an interrupt is triggered, otherwise 0.
*
****************************************************************************/
static int tlsr82_timer_checkint(struct tlsr82_timer_dev_s *dev)
{
struct tlsr82_timer_priv_s *priv = (struct tlsr82_timer_priv_s *)dev;
int ret = 0;
DEBUGASSERT(dev != NULL);
if (priv->inst == TLSR82_INST_TIMER1)
{
if (BM_IS_SET(IRQ_SRC_REG, 1 << NR_TIMER1_IRQ))
{
ret = 1;
}
}
else if (priv->inst == TLSR82_INST_TIMER2)
{
if (BM_IS_SET(IRQ_SRC_REG, 1 << NR_TIMER2_IRQ))
{
ret = 1;
}
}
else
{
tmrerr("Timer instance %d is not existed.\n", (int)priv->inst);
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: tlsr82_timer_init
*
* Description:
* Initialize TIMER device.
*
* Parameters:
* timer - Timer instance to be initialized.
* Valid values: 1 or 2.
*
* Returned Values:
* If the initialization is successful, return a pointer to the timer
* driver struct associated to that timer instance.
* In case it fails, return NULL.
*
****************************************************************************/
struct tlsr82_timer_dev_s *tlsr82_timer_init(int timer)
{
struct tlsr82_timer_priv_s *tim = NULL;
/* First, take the data structure associated with the timer instance */
switch (timer)
{
#ifdef CONFIG_TLSR82_TIMER1
case 1:
{
tim = &g_tlsr82_timer1_priv;
break;
}
#endif
#ifdef CONFIG_TLSR82_TIMER2
case 2:
{
tim = &g_tlsr82_timer2_priv;
break;
}
#endif
default:
{
tmrerr("ERROR: unsupported TIMER %d\n", timer);
goto errout;
}
}
/* Verify if it is in use */
if (tim->inuse == false)
{
tim->inuse = true; /* If it was not, now it is */
}
else
{
tmrerr("ERROR: TIMER %d is already in use\n", timer);
tim = NULL;
}
errout:
return (struct tlsr82_timer_dev_s *)tim;
}
/****************************************************************************
* Name: tlsr82_timer_deinit
*
* Description:
* Deinit TIMER device.
*
* Parameters:
* dev - Pointer to the timer driver struct.
*
****************************************************************************/
void tlsr82_timer_deinit(struct tlsr82_timer_dev_s *dev)
{
struct tlsr82_timer_priv_s *tim = NULL;
DEBUGASSERT(dev);
tim = (struct tlsr82_timer_priv_s *)dev;
tim->inuse = false;
}