blob: 5ca30709cf1977514d8bdfd0fa03fb53d7a6a583 [file] [log] [blame]
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/****************************************************************************/
/*** Include files ***/
/****************************************************************************/
#include "fsl_wtimer.h"
#include "fsl_clock.h"
#include "fsl_device_registers.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.wtimer"
#endif
/****************************************************************************/
/*** Macro Definitions ***/
/****************************************************************************/
//#define WTIMER_TRACE
#ifndef WTIMER_TRACE
#define PRINTF(...)
#else
#include "fsl_debug_console.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.wtimer"
#endif
#endif
/*******************************************************************************
* Variables
******************************************************************************/
typedef struct
{
uint32_t wkt_stat_timeout_mask;
uint32_t wkt_stat_running_mask;
uint32_t wkt_ctrl_clk_ena_mask;
uint32_t wkt_ctrl_ena_mask;
uint32_t wkt_intenclr_timeout_mask;
volatile uint32_t *wkt_load_lsb_reg;
volatile uint32_t *wkt_load_msb_reg;
const volatile uint32_t *wkt_val_lsb_reg;
const volatile uint32_t *wkt_val_msb_reg;
uint8_t wkt_irq_id;
} timer_param_t;
static const timer_param_t timer_param[2] = {
{
.wkt_stat_timeout_mask = SYSCON_WKT_STAT_WKT0_TIMEOUT_MASK,
.wkt_stat_running_mask = SYSCON_WKT_STAT_WKT0_RUNNING_MASK,
.wkt_ctrl_clk_ena_mask = SYSCON_WKT_CTRL_WKT0_CLK_ENA_MASK,
.wkt_ctrl_ena_mask = SYSCON_WKT_CTRL_WKT0_ENA_MASK,
.wkt_intenclr_timeout_mask = SYSCON_WKT_INTENSET_WKT0_TIMEOUT_MASK,
.wkt_load_lsb_reg = &SYSCON->WKT_LOAD_WKT0_LSB,
.wkt_load_msb_reg = &SYSCON->WKT_LOAD_WKT0_MSB,
.wkt_val_lsb_reg = &SYSCON->WKT_VAL_WKT0_LSB,
.wkt_val_msb_reg = NULL,
.wkt_irq_id = WAKE_UP_TIMER0_IRQn,
},
{
.wkt_stat_timeout_mask = SYSCON_WKT_STAT_WKT1_TIMEOUT_MASK,
.wkt_stat_running_mask = SYSCON_WKT_STAT_WKT1_RUNNING_MASK,
.wkt_ctrl_clk_ena_mask = SYSCON_WKT_CTRL_WKT1_CLK_ENA_MASK,
.wkt_ctrl_ena_mask = SYSCON_WKT_CTRL_WKT1_ENA_MASK,
.wkt_intenclr_timeout_mask = SYSCON_WKT_INTENSET_WKT1_TIMEOUT_MASK,
.wkt_load_lsb_reg = &SYSCON->WKT_LOAD_WKT1,
.wkt_load_msb_reg = NULL,
.wkt_val_lsb_reg = &SYSCON->WKT_VAL_WKT1,
.wkt_val_msb_reg = NULL,
.wkt_irq_id = WAKE_UP_TIMER1_IRQn,
},
};
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
/*!
* brief Enable the clocks to the peripheral (functional clock and AHB clock)
*
* note This function does not reset the wake timer peripheral. Wake timer reset is done in PWRM_vColdStart() from the
* PWRM framework module if integrated
* If PWRM framework module is integrated, WTIMER_Init() is called in PWRM_vInit() for power modes with Oscillator ON.
*
*/
void WTIMER_Init(void)
{
/* set clock and divider */
SYSCON->AHBCLKCTRLS[0] |= SYSCON_AHBCLKCTRLSET0_WAKE_UP_TIMERS_CLK_SET_MASK;
SYSCON->WKTCLKSEL = SYSCON_WKTCLKSEL_SEL(0); // & ~SYSCON_WKTCLKSEL_SEL_MASK ;
}
/*!
* brief Disable the clocks to the peripheral (functional clock and AHB clock)
*
* note This function does not reset the wake timer peripheral.
*
*/
void WTIMER_DeInit(void)
{
/* set clock and divider */
SYSCON->AHBCLKCTRLS[0] &= ~SYSCON_AHBCLKCTRLSET0_WAKE_UP_TIMERS_CLK_SET_MASK;
SYSCON->WKTCLKSEL = SYSCON_WKTCLKSEL_SEL(2); // No Clock ;
}
/*!
* brief Gets the Timer status flags.
*
* param timer_id Wtimer Id
*
* return The status flags.
*/
WTIMER_status_t WTIMER_GetStatusFlags(WTIMER_timer_id_t timer_id)
{
const timer_param_t *timer_param_l = &timer_param[timer_id];
WTIMER_status_t status = WTIMER_STATUS_NOT_RUNNING;
uint32_t stat = SYSCON->WKT_STAT;
if (stat & timer_param_l->wkt_stat_timeout_mask)
{
status = WTIMER_STATUS_EXPIRED;
PRINTF("WakeTimerFiredStatus[%d] expired\n", timer_id);
}
else if (stat & timer_param_l->wkt_stat_running_mask)
{
status = WTIMER_STATUS_RUNNING;
PRINTF("WakeTimerFiredStatus[%d] running\n", timer_id);
}
return status;
}
/*!
* brief Enable the selected Timer interrupts.
* The application shall implement the Wake timer ISR
*
* param timer_id Wtimer Id
*/
void WTIMER_EnableInterrupts(WTIMER_timer_id_t timer_id)
{
const timer_param_t *timer_param_l = &timer_param[timer_id];
EnableIRQ((IRQn_Type)timer_param_l->wkt_irq_id);
SYSCON->WKT_INTENSET = timer_param_l->wkt_intenclr_timeout_mask;
}
/*!
* brief Starts the Timer counter.
* The function performs:
* -stop the timer if running, clear the status and interrupt flag if set (WTIMER_ClearStatusFlags())
* -set the counter value
* -start the timer
*
* param timer_id Wtimer Id
* param count number of 32KHz clock periods before expiration
*/
void WTIMER_StartTimer(WTIMER_timer_id_t timer_id, uint32_t count)
{
const timer_param_t *timer_param_l = &timer_param[timer_id];
PRINTF("-->> vAHI_WakeTimerStart[%d] : STAT=%x count=%d WKT_INTSTAT=%x count=%d\n", timer_id, SYSCON->WKT_STAT,
count, SYSCON->WKT_INTSTAT, count);
/* enable the clock */
SYSCON->WKT_CTRL |= timer_param_l->wkt_ctrl_clk_ena_mask;
/* clear timeout flag if set */
SYSCON->WKT_STAT = timer_param_l->wkt_stat_timeout_mask;
/* stop timer if running */
SYSCON->WKT_CTRL &= ~(timer_param_l->wkt_ctrl_ena_mask);
/* make sure the timer is really stopped */
while ((SYSCON->WKT_STAT & (timer_param_l->wkt_stat_running_mask)) == timer_param_l->wkt_stat_running_mask)
{
__asm volatile("nop");
}
*(timer_param_l->wkt_load_lsb_reg) = count;
if (timer_id == WTIMER_TIMER0_ID)
{
*(timer_param_l->wkt_load_msb_reg) = 0;
}
/* enable the timer */
SYSCON->WKT_CTRL |= timer_param_l->wkt_ctrl_ena_mask;
while ((SYSCON->WKT_STAT & (timer_param_l->wkt_stat_running_mask)) == 0)
{
__asm volatile("nop");
}
PRINTF("<<-- vAHI_WakeTimerStart[%d] : STAT=%x WKT_INTSTAT=%x\n", timer_id, SYSCON->WKT_STAT, SYSCON->WKT_INTSTAT);
}
/*!
* brief Read the LSB counter of the wake timer
* API checks the next counter update (next 32KHz clock edge) so the value is uptodate
* Important note : The counter shall be running otherwise, the API gets locked and never return
*
* param timer_id Wtimer Id
* return 32KHz clock frequency (number of 32KHz clock in one sec) - expect to have 32768
*/
uint32_t WTIMER_ReadTimerSafe(WTIMER_timer_id_t timer_id)
{
const timer_param_t *timer_param_l = &timer_param[timer_id];
volatile uint32_t u32CurrentCount_ini = *timer_param_l->wkt_val_lsb_reg;
volatile uint32_t u32CurrentCount = *timer_param_l->wkt_val_lsb_reg;
while (u32CurrentCount == u32CurrentCount_ini)
u32CurrentCount = *timer_param_l->wkt_val_lsb_reg;
return u32CurrentCount;
}
/*!
* brief Read the LSB counter of the wake timer
* This API is unsafe. If the counter has just been started, the counter value may not be
* up to date until the next 32KHz clock edge.
* Use WTIMER_ReadTimerSafe() instead
*
* param timer_id Wtimer Id
* return counter value - number of ticks before expiration if running
*/
uint32_t WTIMER_ReadTimer(WTIMER_timer_id_t timer_id)
{
const timer_param_t *timer_param_l = &timer_param[timer_id];
volatile uint32_t u32CurrentCount = *timer_param_l->wkt_val_lsb_reg;
return u32CurrentCount;
}
/*!
* brief Clears the Timer status flags if expired and clear the pendng interrupt if active
* it needs to be called in ISR
*
* param timer_id Wtimer Id
*/
void WTIMER_ClearStatusFlags(WTIMER_timer_id_t timer_id)
{
const timer_param_t *timer_param_l = &timer_param[timer_id];
/* clear expiration flag */
SYSCON->WKT_STAT = timer_param_l->wkt_stat_timeout_mask;
/* clear interrupt if pending */
NVIC_ClearPendingIRQ((IRQn_Type)timer_param_l->wkt_irq_id);
}
/*!
* brief Stops the Timer counter.
*
* param timer_id Wtimer Id
*/
void WTIMER_StopTimer(WTIMER_timer_id_t timer_id)
{
const timer_param_t *timer_param_l = &timer_param[timer_id];
/* Stop timer */
SYSCON->WKT_CTRL &= ~(timer_param_l->wkt_ctrl_ena_mask);
/* make sure the timer is really stopped */
while ((SYSCON->WKT_STAT & (timer_param_l->wkt_stat_running_mask)) == timer_param_l->wkt_stat_running_mask)
{
__asm volatile("nop");
}
WTIMER_ClearStatusFlags(timer_id);
}