Files
2025-08-27 09:51:58 +01:00

793 lines
25 KiB
C

/**
* @file hgtimer_v6.c
* @author bxd
* @brief super timer
* @version
* TXW80X
* @date 2023-08-02
*
* @copyright Copyright (c) 2023
*
*/
#include "typesdef.h"
#include "list.h"
#include "errno.h"
#include "dev.h"
#include "osal/irq.h"
#include "osal/string.h"
#include "hal/timer_device.h"
#include "hal/pwm.h"
#include "dev/pwm/hgpwm_v0.h"
#include "dev/timer/hgtimer_v6.h"
#include "hgtimer_v6_hw.h"
/**********************************************************************************/
/* COMM FUNCTION */
/**********************************************************************************/
#define HGTIMER_V6_HW_SUPTMRCON0_BIT (\
LL_STRM_CON0_SUPTMR01_SYNC_MD_SEL(0x3) | \
LL_STRM_CON0_SUPTMR23_SYNC_MD_SEL(0x3) | \
LL_STRM_CON0_SUPTMR45_SYNC_MD_SEL(0x3) | \
LL_SUPTMR_CON0_SUPTMR_GP0_EN | \
LL_SUPTMR_CON0_SUPTMR_GP1_EN | \
LL_SUPTMR_CON0_CPMC_SEL(0x1) | \
LL_SUPTMR_CON0_LOAD_SEL(0x1) | \
LL_SUPTMR_CON0_SUPTMR0_CNT_TYPE_SEL(0x1) | \
LL_SUPTMR_CON0_SUPTMR1_CNT_TYPE_SEL(0x1) | \
LL_SUPTMR_CON0_SUPTMR2_CNT_TYPE_SEL(0x1) | \
LL_SUPTMR_CON0_SUPTMR3_CNT_TYPE_SEL(0x1) | \
LL_SUPTMR_CON0_SUPTMR4_CNT_TYPE_SEL(0x1) | \
LL_SUPTMR_CON0_SUPTMR5_CNT_TYPE_SEL(0x1) \
)
static int32 hgtimer_v6_switch_suptmr_index(struct hgtimer_v6 *dev)
{
switch ((uint32)(dev->hw_suptmrx)) {
case ((uint32)HG_SUPTMR0_BASE):
return 0;
break;
case ((uint32)HG_SUPTMR1_BASE):
return 1;
break;
case ((uint32)HG_SUPTMR2_BASE):
return 2;
break;
case ((uint32)HG_SUPTMR3_BASE):
return 3;
break;
case ((uint32)HG_SUPTMR4_BASE):
return 4;
break;
case ((uint32)HG_SUPTMR5_BASE):
return 5;
break;
default:
return -1;
break;
}
}
/**********************************************************************************/
/* PWM FUNCTION START */
/**********************************************************************************/
static int32 hgtimer_v6_pwm_switch_func_cmd(enum hgpwm_v0_func_cmd param)
{
switch (param) {
case (HGPWM_V0_FUNC_CMD_INIT):
return HGTIMER_V6_PWM_FUNC_CMD_INIT;
break;
case (HGPWM_V0_FUNC_CMD_DEINIT):
return HGTIMER_V6_PWM_FUNC_CMD_DEINIT;
break;
case (HGPWM_V0_FUNC_CMD_START):
return HGTIMER_V6_PWM_FUNC_CMD_START;
break;
case (HGPWM_V0_FUNC_CMD_STOP):
return HGTIMER_V6_PWM_FUNC_CMD_STOP;
break;
case (HGPWM_V0_FUNC_CMD_IOCTL_SET_PERIOD_DUTY):
return HGTIMER_V6_PWM_FUNC_CMD_IOCTL_SET_PERIOD_DUTY;
break;
case (HGPWM_V0_FUNC_CMD_REQUEST_IRQ_COMPARE):
return HGTIMER_V6_PWM_FUNC_CMD_REQUEST_IRQ_COMPARE;
break;
case (HGPWM_V0_FUNC_CMD_REQUEST_IRQ_PERIOD):
return HGTIMER_V6_PWM_FUNC_CMD_REQUEST_IRQ_PERIOD;
break;
case (HGPWM_V0_FUNC_CMD_RELEASE_IRQ):
return HGTIMER_V6_PWM_FUNC_CMD_RELEASE_IRQ;
break;
case (HGPWM_V0_FUNC_CMD_IOCTL_SET_PRESCALER):
return HGTIMER_V6_PWM_FUNC_CMD_IOCTL_SET_PRESCALER;
break;
case (HGPWM_V0_FUNC_CMD_IOCTL_SET_PERIOD_DUTY_IMMEDIATELY):
return HGTIMER_V6_PWM_FUNC_CMD_IOCTL_SET_PERIOD_DUTY_IMMEDIATELY;
break;
default:
return -1;
break;
}
}
static inline int32 hgtimer_v6_pwm_func_init(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if (dev->opened) {
return -EBUSY;
}
if (pin_func(dev->dev.dev.dev_id, 1) != RET_OK) {
return RET_ERR;
}
if ((p_config->duty < 0) || ((p_config->duty) > (p_config->period))) {
return RET_ERR;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
/* config regs */
switch ((uint32)(dev->hw_suptmrx)) {
case ((uint32)HG_SUPTMR0_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR0_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR1_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR1_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR2_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR2_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR3_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR3_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR4_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR4_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR5_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR5_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
default:
return RET_ERR;
break;
}
/* config PWMCON: PWMVA; PWMEN */
hw_comm->SUPTMR_PWMCON &= ~(((1) << (6 + index)) | ((0) << (0 + index)));
/* config period */
hw_suptmrx->PR = p_config->period;
/* config compare */
hw_suptmrx->CMP = p_config->duty;
/* clear current cnt */
hw_suptmrx->CNT = 0;
dev->opened = 1;
dev->pwm_en = 1;
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_deinit(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if ((!dev->opened) || (!dev->pwm_en)) {
return RET_OK;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
irq_disable(dev->irq_num);
pin_func(dev->dev.dev.dev_id, 0);
/* comm reg CON1: CNTEN; */
hw_comm->SUPTMR_CON1 &= ~((1) << (0 + index));
/* comm reg PWMCON: PWMEN; */
hw_comm->SUPTMR_PWMCON &= ~((1) << (0 + index));
hw_suptmrx->CON = 0;
/* clear current cnt */
hw_suptmrx->CNT = 0;
dev->opened = 0;
dev->pwm_en = 0;
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_start(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if (!dev->pwm_en) {
return RET_ERR;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
/* comm reg PWMCON: PWMEN*/
hw_comm->SUPTMR_PWMCON |= (1) << (0 + index);
/* comm reg CON1: CNTEN */
hw_comm->SUPTMR_CON1 |= (1) << (0 + index);
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_stop(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if (!dev->pwm_en) {
return RET_ERR;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
/* comm reg PWMCON: PWMEN*/
hw_comm->SUPTMR_PWMCON &= ~((1) << (0 + index));
/* comm reg CON1: CNTEN */
hw_comm->SUPTMR_CON1 &= ~((1) << (0 + index));
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_ioctl_set_period_duty(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if (!dev->pwm_en) {
return RET_ERR;
}
if ((p_config->duty < 0) || ((p_config->duty) > (p_config->period))) {
return RET_ERR;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
/* config period */
hw_suptmrx->PR = p_config->period;
/* config compare */
hw_suptmrx->CMP = p_config->duty;
/* clear current cnt */
hw_suptmrx->CNT = 0;
/* comm reg CON1: LOADEN */
hw_comm->SUPTMR_CON1 |= (1) << (8 + index);
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_cmd_ioctl_set_prescaler(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
if (!dev->pwm_en) {
return RET_ERR;
}
hw_suptmrx->CON = (hw_suptmrx->CON &~ (LL_SUPTMRx_CON_PSC(0x3FF))) | (LL_SUPTMRx_CON_PSC(p_config->param1));
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_cmd_ioctl_set_period_duty_immediately(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if (!dev->pwm_en) {
return RET_ERR;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
/* comm reg PWMCON: PWMEN*/
hw_comm->SUPTMR_PWMCON &= ~((1) << (0 + index));
/* comm reg CON1: CNTEN */
hw_comm->SUPTMR_CON1 &= ~((1) << (0 + index));
hw_suptmrx->CNT = 0;
hw_suptmrx->PR = p_config->period;
hw_suptmrx->CMP = p_config->duty;
/* comm reg PWMCON: PWMEN*/
hw_comm->SUPTMR_PWMCON |= (1) << (0 + index);
/* comm reg CON1: CNTEN */
hw_comm->SUPTMR_CON1 |= (1) << (0 + index);
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_request_irq_compare(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
if (!dev->pwm_en) {
return RET_ERR;
}
dev->_pwm_irq_hdl = p_config->irq_hdl;
dev->irq_data = p_config->irq_data;
hw_suptmrx->CON |= LL_SUPTMRx_CON_CMPA_IE;
irq_enable(dev->irq_num);
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_request_irq_period(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
if (!dev->pwm_en) {
return RET_ERR;
}
dev->_pwm_irq_hdl = p_config->irq_hdl;
dev->irq_data = p_config->irq_data;
hw_suptmrx->CON |= LL_SUPTMRx_CON_UD_IE;
irq_enable(dev->irq_num);
return RET_OK;
}
static inline int32 hgtimer_v6_pwm_func_release_irq(struct hgtimer_v6 *dev, struct hgpwm_v0_config *p_config)
{
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
if (!dev->pwm_en) {
return RET_ERR;
}
irq_disable(dev->irq_num);
dev->_pwm_irq_hdl = NULL;
dev->irq_data = 0;
hw_suptmrx->CON &= ~(LL_SUPTMRx_CON_UD_IE | LL_SUPTMRx_CON_UD_IE);
return RET_OK;
}
static int32 hgtimer_v6_pwm_config(struct hgtimer_v6 *dev, uint32 config, uint32 param)
{
struct hgpwm_v0_config *p_config;
int32 hgtimer_v6_pwm_func_cmd = 0;
int32 ret_val = RET_OK;
/* Make sure the config struct pointer */
if (!config) {
return -EINVAL;
}
p_config = (struct hgpwm_v0_config *)config;
hgtimer_v6_pwm_func_cmd = hgtimer_v6_pwm_switch_func_cmd(p_config->func_cmd);
if ((-1) == hgtimer_v6_pwm_func_cmd) {
return -EINVAL;
}
switch (hgtimer_v6_pwm_func_cmd) {
case (HGTIMER_V6_PWM_FUNC_CMD_INIT):
ret_val = hgtimer_v6_pwm_func_init(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_DEINIT):
ret_val = hgtimer_v6_pwm_func_deinit(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_START):
ret_val = hgtimer_v6_pwm_func_start(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_STOP):
ret_val = hgtimer_v6_pwm_func_stop(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_IOCTL_SET_PERIOD_DUTY):
ret_val = hgtimer_v6_pwm_func_ioctl_set_period_duty(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_REQUEST_IRQ_COMPARE):
ret_val = hgtimer_v6_pwm_func_request_irq_compare(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_REQUEST_IRQ_PERIOD):
ret_val = hgtimer_v6_pwm_func_request_irq_period(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_RELEASE_IRQ):
ret_val = hgtimer_v6_pwm_func_release_irq(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_IOCTL_SET_PRESCALER):
ret_val = hgtimer_v6_pwm_func_cmd_ioctl_set_prescaler(dev, p_config);
break;
case (HGTIMER_V6_PWM_FUNC_CMD_IOCTL_SET_PERIOD_DUTY_IMMEDIATELY):
ret_val = hgtimer_v6_pwm_func_cmd_ioctl_set_period_duty_immediately(dev, p_config);
break;
default:
ret_val = -ENOTSUPP;
break;
}
return ret_val;
}
/**********************************************************************************/
/* PWM FUNCTION END */
/**********************************************************************************/
/**********************************************************************************/
/* COUNTER FUNCTION START */
/**********************************************************************************/
static int32 hgtimer_v6_counter_switch_hal_type(struct hgtimer_v6 *dev, enum timer_type param)
{
switch (param) {
case (TIMER_TYPE_ONCE):
dev->type = HGTIMER_V6_TYPE_ONCE;
return 0;
break;
case (TIMER_TYPE_PERIODIC):
dev->type = HGTIMER_V6_TYPE_PERIODIC;
return 1;
break;
default:
return -1;
break;
}
}
static int32 hgtimer_v6_counter_set_psc(struct hgtimer_v6 *timer, uint32 psc)
{
struct hgtimer_v6 *dev = (struct hgtimer_v6 *)timer;
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
if (!dev->counter_en) {
return RET_ERR;
}
hw_suptmrx->CON = (hw_suptmrx->CON & ~ LL_SUPTMRx_CON_PSC(0x3FF)) | LL_SUPTMRx_CON_PSC(psc);
return RET_OK;
}
static int32 hgtimer_v6_counter_func_open(struct timer_device *timer, enum timer_type type, uint32 flags)
{
struct hgtimer_v6 *dev = (struct hgtimer_v6 *)timer;
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
if (dev->opened) {
return -EBUSY;
}
if ((-1) == hgtimer_v6_counter_switch_hal_type(dev, type)) {
return RET_ERR;
}
irq_enable(dev->irq_num);
switch (dev->type) {
/* TIMER_TYPE_ONCE */
case (HGTIMER_V6_TYPE_ONCE):
/* TIMER_TYPE_PERIODIC */
case (HGTIMER_V6_TYPE_PERIODIC):
/* TIMER_TYPE_COUNTER */
case (HGTIMER_V6_TYPE_COUNTER):
/* config regs */
switch ((uint32)(dev->hw_suptmrx)) {
case ((uint32)HG_SUPTMR0_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR0_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR1_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR1_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR2_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR2_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR3_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR3_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR4_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR4_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
case ((uint32)HG_SUPTMR5_BASE):
hw_comm->SUPTMR_CON0 = (hw_comm->SUPTMR_CON0 & ~(HGTIMER_V6_HW_SUPTMRCON0_BIT)) | LL_SUPTMR_CON0_SUPTMR5_CNT_MOD_SEL(1);
hw_suptmrx->CON = LL_SUPTMRx_CON_PSC(0); /* default psc: 1 */
break;
default:
return RET_ERR;
break;
}
break;
default:
return RET_ERR;
break;
}
/* clear current cnt */
hw_suptmrx->CNT = 0;
dev->opened = 1;
dev->counter_en = 1;
return RET_OK;
}
static int32 hgtimer_v6_counter_func_close(struct timer_device *timer)
{
struct hgtimer_v6 *dev = (struct hgtimer_v6 *)timer;
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if ((!dev->opened) || (!dev->counter_en)) {
return RET_OK;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
irq_disable(dev->irq_num);
/* config regs */
hw_comm->SUPTMR_CON1 &= ~(1) << (0 + index);
hw_suptmrx->CON = 0;
dev->opened = 0;
dev->counter_en = 0;
return RET_OK;
}
static int32 hgtimer_v6_counter_func_start(struct timer_device *timer, uint32 period_sysclkpd_cnt, timer_cb_hdl cb, uint32 cb_data)
{
struct hgtimer_v6 *dev = (struct hgtimer_v6 *)timer;
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if (!dev->counter_en) {
return RET_ERR;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
switch (dev->type) {
/* TIMER_TYPE_ONCE */
case (HGTIMER_V6_TYPE_ONCE):
dev->counter_once_en = 1;
/* config period */
hw_suptmrx->PR = period_sysclkpd_cnt;
/* clear current cnt */
hw_suptmrx->CNT = 0;
if (cb) {
dev->_counter_irq_hdl = cb;
dev->irq_data = cb_data;
hw_suptmrx->CON |= LL_SUPTMRx_CON_OV_IE;
}
hw_comm->SUPTMR_CON1 |= (1) << (0 + index);
break;
/* TIMER_TYPE_PERIODIC */
case (HGTIMER_V6_TYPE_PERIODIC):
/* TIMER_TYPE_COUNTER */
case (HGTIMER_V6_TYPE_COUNTER):
dev->counter_period_en = 1;
/* config period */
hw_suptmrx->PR = period_sysclkpd_cnt;
/* clear current cnt */
hw_suptmrx->CNT = 0;
if (cb) {
dev->_counter_irq_hdl = cb;
dev->irq_data = cb_data;
hw_suptmrx->CON |= LL_SUPTMRx_CON_UD_IE;
}
hw_comm->SUPTMR_CON1 |= (1) << (0 + index);
break;
default:
return RET_ERR;
break;
}
return RET_OK;
}
static int32 hgtimer_v6_counter_func_stop(struct timer_device *timer)
{
struct hgtimer_v6 *dev = (struct hgtimer_v6 *)timer;
struct hgtimer_v6_hw_comm *hw_comm = (struct hgtimer_v6_hw_comm *)dev->hw_comm;
int32 index = 0;
if (!dev->counter_en) {
return RET_ERR;
}
/* confirm which suptmr */
index = hgtimer_v6_switch_suptmr_index(dev);
if ((-1) == index) {
return RET_ERR;
}
hw_comm->SUPTMR_CON1 &= ~(1) << (0 + index);
return RET_OK;
}
static int32 hgtimer_v6_counter_func_ioctl(struct timer_device *timer, uint32 cmd, uint32 param1, uint32 param2)
{
int32 ret_val = RET_OK;
struct hgtimer_v6 *dev = (struct hgtimer_v6 *)timer;
switch (cmd) {
case (HGPWM_V0_FUNC_CMD_MASK):
ret_val = hgtimer_v6_pwm_config(dev, param1, 0);
break;
case (TIMER_SET_CLK_PSC):
ret_val = hgtimer_v6_counter_set_psc(dev, param1);
break;
default:
ret_val = RET_ERR;
break;
}
return ret_val;
}
/**********************************************************************************/
/* COUNTER FUNCTION END */
/**********************************************************************************/
static void hgtimer_v6_irq_handler(void *data)
{
struct hgtimer_v6 *dev = (struct hgtimer_v6 *)data;
struct hgtimer_v6_hw_suptmrx *hw_suptmrx = (struct hgtimer_v6_hw_suptmrx *)dev->hw_suptmrx;
if ((hw_suptmrx->CON & LL_SUPTMRx_CON_UD_IF) &&
(hw_suptmrx->CON & LL_SUPTMRx_CON_UD_IE)) {
/* clear the pending */
hw_suptmrx->CON |= LL_SUPTMRx_CON_UD_IF_CLR;
/* pwm mode irq */
if (dev->opened && dev->pwm_en && dev->_pwm_irq_hdl) {
dev->_pwm_irq_hdl(PWM_IRQ_FLAG_PERIOD, dev->irq_data);
}
/* counter mode irq */
if (dev->opened && dev->counter_en) {
if (dev->counter_once_en) {
dev->counter_once_en = 0;
/* close timer & interrupt */
hw_suptmrx->CON &= ~ LL_SUPTMRx_CON_UD_IE;
}
if (dev->_counter_irq_hdl) {
dev->_counter_irq_hdl(dev->irq_data, TIMER_INTR_PERIOD);
}
}
}
if ((hw_suptmrx->CON & LL_SUPTMRx_CON_CMPA_IF) &&
(hw_suptmrx->CON & LL_SUPTMRx_CON_CMPA_IE)) {
/* clear the pending */
hw_suptmrx->CON |= LL_SUPTMRx_CON_CMPA_IF_CLR;
/* pwm mode irq */
if (dev->opened && dev->pwm_en && dev->_pwm_irq_hdl) {
dev->_pwm_irq_hdl(PWM_IRQ_FLAG_PERIOD, dev->irq_data);
}
}
}
static const struct timer_hal_ops timer_v6_ops = {
.open = hgtimer_v6_counter_func_open,
.close = hgtimer_v6_counter_func_close,
.start = hgtimer_v6_counter_func_start,
.stop = hgtimer_v6_counter_func_stop,
.ioctl = hgtimer_v6_counter_func_ioctl,
};
int32 hgtimer_v6_attach(uint32 dev_id, struct hgtimer_v6 *timer)
{
timer->opened = 0;
timer->_counter_irq_hdl = NULL;
timer->_pwm_irq_hdl = NULL;
timer->irq_data = 0;
timer->dev.dev.ops = (const struct devobj_ops *)&timer_v6_ops;
request_irq(timer->irq_num, hgtimer_v6_irq_handler, timer);
dev_register(dev_id, (struct dev_obj *)timer);
return RET_OK;
}