541 lines
13 KiB
C
541 lines
13 KiB
C
/**
|
|
* @file sdrv_btm.c
|
|
*
|
|
* Copyright (c) 2021 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*
|
|
* Description: Semidrive basic timer module driver.
|
|
*
|
|
* Revision History:
|
|
* -----------------
|
|
*/
|
|
|
|
#include <types.h>
|
|
#include <string.h>
|
|
#include "sdrv_btm.h"
|
|
#include "irq.h"
|
|
#include "bits.h"
|
|
#include "debug.h"
|
|
#include "regs_base.h"
|
|
#include "sdrv_ckgen.h"
|
|
#include "clock_ip.h"
|
|
|
|
|
|
#define SDRV_BTM_MODULE_NUM 6
|
|
sdrv_btm_controller_module_t btm_controller[SDRV_BTM_MODULE_NUM] = {0};
|
|
|
|
#define EXTRA_FMT "sdrv_btm:"
|
|
#define SDRV_BTM_ERR(format, ...) \
|
|
ssdk_printf(SSDK_ERR, EXTRA_FMT format, ##__VA_ARGS__)
|
|
#define SDRV_BTM_WARN(format, ...) \
|
|
ssdk_printf(SSDK_WARNING, EXTRA_FMT format, ##__VA_ARGS__)
|
|
#define SDRV_BTM_INFO(format, ...) \
|
|
ssdk_printf(SSDK_INFO, EXTRA_FMT format, ##__VA_ARGS__)
|
|
|
|
|
|
/**
|
|
* @brief sdrv btm irq handle function
|
|
*
|
|
* @param[in] irq :irq id
|
|
* @param[in] arg :irq arg
|
|
*/
|
|
static int sdrv_btm_irq_handle(uint32_t irq, void *arg)
|
|
{
|
|
sdrv_btm_controller_module_t *pstbtm_controller = arg;
|
|
sdrv_btm_t *sdrv_btm_g0 = pstbtm_controller->btm_bank[SDRV_BTM_G0];
|
|
sdrv_btm_t *sdrv_btm_g1 = pstbtm_controller->btm_bank[SDRV_BTM_G1];
|
|
volatile uint32_t int_sta = 0;
|
|
|
|
if (sdrv_btm_g0 != NULL) {
|
|
int_sta = sdrv_btm_hw_get_int_sta(sdrv_btm_g0->config->base);
|
|
}
|
|
else {
|
|
int_sta = sdrv_btm_hw_get_int_sta(sdrv_btm_g1->config->base);
|
|
}
|
|
|
|
uint32_t clr_int_sta;
|
|
|
|
if (int_sta & BTM_BM_INT_STAT_OE_G0) {
|
|
clr_int_sta = int_sta & BTM_BM_INT_STAT_OE_G0;
|
|
sdrv_btm_hw_set_int_sta(sdrv_btm_g0->config->base, clr_int_sta);
|
|
|
|
if (sdrv_btm_g0 != NULL) {
|
|
if (sdrv_btm_g0->callback) {
|
|
sdrv_btm_g0->callback(sdrv_btm_g0->arg);
|
|
}
|
|
|
|
/*update timer status*/
|
|
if (sdrv_btm_g0->type == BTM_TYPE_ONESHOT) {
|
|
sdrv_btm_g0->status = BTM_STATUS_IDLE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (int_sta & BTM_BM_INT_STAT_OE_G1) {
|
|
clr_int_sta = int_sta & BTM_BM_INT_STAT_OE_G1;
|
|
sdrv_btm_hw_set_int_sta(sdrv_btm_g1->config->base, clr_int_sta);
|
|
|
|
if (sdrv_btm_g1 != NULL) {
|
|
if (sdrv_btm_g1->callback) {
|
|
sdrv_btm_g1->callback(sdrv_btm_g1->arg);
|
|
}
|
|
|
|
/*update timer status*/
|
|
if (sdrv_btm_g1->type == BTM_TYPE_ONESHOT) {
|
|
sdrv_btm_g1->status = BTM_STATUS_IDLE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief get btm module id
|
|
*
|
|
* @param[in] base: module address
|
|
* @param[out] id : module id
|
|
*/
|
|
status_t sdrv_btm_get_module_id(uint32_t base, uint8_t *id)
|
|
{
|
|
status_t ret = SDRV_STATUS_FAIL;
|
|
|
|
switch (base) {
|
|
#if APB_BTM1_BASE
|
|
|
|
case APB_BTM1_BASE:
|
|
*id = 0;
|
|
ret = SDRV_STATUS_OK;
|
|
break;
|
|
#endif
|
|
|
|
#if APB_BTM2_BASE
|
|
|
|
case APB_BTM2_BASE:
|
|
*id = 1;
|
|
ret = SDRV_STATUS_OK;
|
|
break;
|
|
#endif
|
|
|
|
#if APB_BTM3_BASE
|
|
|
|
case APB_BTM3_BASE:
|
|
*id = 2;
|
|
ret = SDRV_STATUS_OK;
|
|
break;
|
|
#endif
|
|
|
|
#if APB_BTM4_BASE
|
|
|
|
case APB_BTM4_BASE:
|
|
*id = 3;
|
|
ret = SDRV_STATUS_OK;
|
|
break;
|
|
#endif
|
|
|
|
#if APB_BTM5_BASE
|
|
|
|
case APB_BTM5_BASE:
|
|
*id = 4;
|
|
ret = SDRV_STATUS_OK;
|
|
break;
|
|
#endif
|
|
|
|
#if APB_BTM6_BASE
|
|
|
|
case APB_BTM6_BASE:
|
|
*id = 5;
|
|
ret = SDRV_STATUS_OK;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
*id = 0;
|
|
ret = SDRV_STATUS_FAIL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief btm init
|
|
*
|
|
* Initial btm module instance.
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @param[in] cfg: btm config
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_init(sdrv_btm_t *ctrl, sdrv_btm_cfg_t *cfg)
|
|
{
|
|
uint8_t btm_id = 0u;
|
|
uint32_t apb_clock = 0u;
|
|
status_t status = 0;
|
|
ASSERT(ctrl != NULL);
|
|
ASSERT(cfg != NULL);
|
|
|
|
ctrl->config = cfg;
|
|
|
|
if (cfg->tmr_id == SDRV_BTM_G0) {
|
|
apb_clock = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_cr5_sf), CKGEN_BUS_CLK_OUT_P);
|
|
apb_clock = apb_clock / 1000;
|
|
ctrl->cnt_per_ms = (apb_clock * (cfg->tmr_cfg.inc_val)) / ((cfg->tmr_cfg.si_val) + 1);
|
|
}
|
|
else if (cfg->tmr_id == SDRV_BTM_G1) {
|
|
/* btm_g1 fre: 24M Hz */
|
|
ctrl->cnt_per_ms = (24000 * (cfg->tmr_cfg.inc_val)) / ((cfg->tmr_cfg.si_val) + 1);
|
|
}
|
|
else {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
|
|
status = sdrv_btm_get_module_id(cfg->base, &btm_id);
|
|
|
|
if (status == SDRV_STATUS_FAIL)
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
|
|
sdrv_btm_hw_init(cfg->base, cfg->tmr_id, &(cfg->tmr_cfg));
|
|
|
|
ctrl->status = BTM_STATUS_IDLE;
|
|
ctrl->type = (btm_type_t)cfg->tmr_cfg.cnt_mode; /*oneshot or continous*/
|
|
ctrl->time_type = BTM_TIME_US;
|
|
ctrl->time_out = 0;
|
|
ctrl->callback = NULL;
|
|
|
|
btm_controller[btm_id].btm_bank[cfg->tmr_id] = ctrl;
|
|
|
|
if (cfg->irq > 0) {
|
|
irq_attach(cfg->irq, sdrv_btm_irq_handle, &btm_controller[btm_id]);
|
|
irq_enable(cfg->irq);
|
|
}
|
|
else {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief btm deinit
|
|
*
|
|
* Deinitial btm module instance.
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_deinit(sdrv_btm_t *ctrl)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
sdrv_btm_hw_timer_stop(ctrl->config->base, ctrl->config->tmr_id);
|
|
ctrl->status = BTM_STATUS_NULL;
|
|
ctrl->type = BTM_TYPE_ONESHOT;
|
|
ctrl->time_type = BTM_TIME_US;
|
|
ctrl->time_out = 0;
|
|
ctrl->callback = NULL;
|
|
ctrl->cnt_per_ms = 0;
|
|
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief btm start
|
|
*
|
|
* In one-short mode, btm will auto stop while reaches overflow value.
|
|
* In continuous mode, btm will reset to 0 and restart once reaches overflow value.
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @param[in] btm_type: timer type
|
|
* @param[in] time_type: timeout time unit
|
|
* @param[in] time_out: timeout
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_start(sdrv_btm_t *ctrl, btm_type_t btm_type, btm_time_type_t time_type,
|
|
uint32_t time_out)
|
|
{
|
|
uint32_t count = 0u;
|
|
ASSERT(ctrl != NULL);
|
|
|
|
if (BTM_STATUS_BUSY == ctrl->status) {
|
|
return SDRV_STATUS_BUSY;
|
|
}
|
|
|
|
ctrl->time_type = time_type;
|
|
ctrl->time_out = time_out;
|
|
|
|
switch (time_type) {
|
|
case BTM_TIME_MS: {
|
|
count = time_out * ctrl->cnt_per_ms;
|
|
}
|
|
break;
|
|
|
|
case BTM_TIME_US: {
|
|
count = (uint32_t)((uint64_t)time_out * ctrl->cnt_per_ms / 1000);
|
|
}
|
|
break;
|
|
|
|
case BTM_TIME_NS: {
|
|
count = (uint32_t)((uint64_t)time_out * ctrl->cnt_per_ms / 1000000);
|
|
}
|
|
break;
|
|
|
|
default: {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
}
|
|
|
|
if (ctrl->type != btm_type) {
|
|
ctrl->type = btm_type;
|
|
ctrl->config->tmr_cfg.cnt_mode = (sdrv_btm_cnt_mode_e)btm_type;
|
|
sdrv_btm_hw_init(ctrl->config->base, ctrl->config->tmr_id, &(ctrl->config->tmr_cfg));
|
|
}
|
|
|
|
sdrv_btm_hw_timer_start(ctrl->config->base, ctrl->config->tmr_id, count - 1);
|
|
sdrv_btm_hw_compare_int_en(ctrl->config->base, ctrl->config->tmr_id, false);
|
|
ctrl->status = BTM_STATUS_BUSY;
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief btm stop
|
|
*
|
|
* BTM stop to count.
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_stop(sdrv_btm_t *ctrl)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
sdrv_btm_hw_timer_stop(ctrl->config->base, ctrl->config->tmr_id);
|
|
ctrl->status = BTM_STATUS_IDLE;
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief btm setup callback funciton
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @param[in] callback: user callback function
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_set_callback(sdrv_btm_t *ctrl, btm_callback callback, void *arg)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
ctrl->callback = callback;
|
|
ctrl->arg = arg;
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief get btm Elapsed time (us)
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return btm Elapsed time (us)
|
|
*/
|
|
uint32_t sdrv_btm_get_current_time(sdrv_btm_t *ctrl)
|
|
{
|
|
uint32_t current = 0;
|
|
ASSERT(ctrl != NULL);
|
|
|
|
current = sdrv_btm_hw_get_cnt_val(ctrl->config->base, ctrl->config->tmr_id);
|
|
|
|
if (ctrl->cnt_per_ms == 0) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return (uint32_t)((uint64_t)current * 1000 / ctrl->cnt_per_ms);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief get btm Elapsed time (extend)
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @param[in] time_type: time type
|
|
* @return btm Elapsed time (us)
|
|
*/
|
|
uint32_t sdrv_btm_get_current_time_ex(sdrv_btm_t *ctrl, btm_time_type_t time_type)
|
|
{
|
|
uint32_t current = 0;
|
|
ASSERT(ctrl != NULL);
|
|
|
|
current = sdrv_btm_hw_get_cnt_val(ctrl->config->base, ctrl->config->tmr_id);
|
|
|
|
switch (time_type) {
|
|
case BTM_TIME_MS: {
|
|
if (ctrl->cnt_per_ms == 0) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return (uint32_t)(current / ctrl->cnt_per_ms);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BTM_TIME_US: {
|
|
if (ctrl->cnt_per_ms == 0) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return (uint32_t)((uint64_t)current * 1000 / ctrl->cnt_per_ms);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BTM_TIME_NS: {
|
|
if (ctrl->cnt_per_ms == 0) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return (uint32_t)((uint64_t)current * 1000000 / ctrl->cnt_per_ms);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default: {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief btm pause
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_pause(sdrv_btm_t *ctrl)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
sdrv_btm_hw_cnt_stop(ctrl->config->base, ctrl->config->tmr_id, true);
|
|
ctrl->status = BTM_STATUS_IDLE;
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief btm continue
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_continue(sdrv_btm_t *ctrl)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
sdrv_btm_hw_cnt_stop(ctrl->config->base, ctrl->config->tmr_id, false);
|
|
ctrl->status = BTM_STATUS_BUSY;
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief btm continue
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return btm ctrl instance status
|
|
*/
|
|
btm_status_t sdrv_btm_get_status(sdrv_btm_t *ctrl)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
return ctrl->status;
|
|
}
|
|
|
|
/**
|
|
* @brief get btm counter value
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return btm counter value
|
|
*/
|
|
uint32_t sdrv_btm_get_counter(sdrv_btm_t *ctrl)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
return sdrv_btm_hw_get_cnt_val(ctrl->config->base, ctrl->config->tmr_id);
|
|
}
|
|
|
|
/**
|
|
* @brief set btm overflow value
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @param[in] val: btm overflow value
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_set_overflow(sdrv_btm_t *ctrl, uint32_t val)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
sdrv_btm_hw_set_ovf_cnt(ctrl->config->base, ctrl->config->tmr_id, val);
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief btm force reset counter value
|
|
*
|
|
* Btm force reset counter value to 0.
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_force_reload(sdrv_btm_t *ctrl)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
sdrv_btm_hw_frc_rld(ctrl->config->base, ctrl->config->tmr_id);
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief is btm overflow.
|
|
*
|
|
* Check btm overflow status.
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return true:overflow fail:not overflow
|
|
*/
|
|
bool sdrv_btm_is_overflowed(sdrv_btm_t *ctrl)
|
|
{
|
|
uint32_t int_sta = 0u;
|
|
ASSERT(ctrl != NULL);
|
|
|
|
int_sta = sdrv_btm_hw_get_int_sta(ctrl->config->base);
|
|
|
|
if (ctrl->config->tmr_id == SDRV_BTM_G1) {
|
|
return (int_sta & BTM_BM_INT_STAT_OE_G1) ? true : false;
|
|
}
|
|
else {
|
|
return (int_sta & BTM_BM_INT_STAT_OE_G0) ? true : false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief btm clear interupt status
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @return succeed:0 fail:other
|
|
*/
|
|
status_t sdrv_btm_clear_intr(sdrv_btm_t *ctrl)
|
|
{
|
|
uint32_t int_sta = 0u;
|
|
ASSERT(ctrl != NULL);
|
|
|
|
int_sta = sdrv_btm_hw_get_int_sta(ctrl->config->base);
|
|
sdrv_btm_hw_set_int_sta(ctrl->config->base, int_sta);
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief btm convert count to time in us
|
|
*
|
|
* @param[in] ctrl: btm ctrl instance
|
|
* @param[in] cnt: btm count value
|
|
* @return time in microseconds.
|
|
*/
|
|
uint32_t sdrv_btm_count_to_us(sdrv_btm_t *ctrl, uint32_t cnt)
|
|
{
|
|
ASSERT(ctrl != NULL);
|
|
return (ctrl->cnt_per_ms) ? (uint32_t)((uint64_t)cnt * 1000 / ctrl->cnt_per_ms) : 0;
|
|
}
|