pure sdk for main
This commit is contained in:
@@ -0,0 +1,797 @@
|
||||
/**
|
||||
* @file hgtimer_v5.c
|
||||
* @author bxd
|
||||
* @brief low power led 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_v5.h"
|
||||
#include "hgtimer_v5_hw.h"
|
||||
|
||||
|
||||
/**********************************************************************************/
|
||||
/* LOW LAYER FUNCTION */
|
||||
/**********************************************************************************/
|
||||
|
||||
#define LL_LED_TIMER_CHECK_COUNT_OV_INTERRUPT_ENABLE(p_timer) (LED_TIMER0_BASE == (uint32)p_timer) ? (SYSCTRL->SYS_CON15 & (1 << 8)) : \
|
||||
((LED_TIMER1_BASE == (uint32)p_timer) ? (SYSCTRL->SYS_CON15 & (1 << 9)) : \
|
||||
((LED_TIMER2_BASE == (uint32)p_timer) ? (SYSCTRL->SYS_CON15 & (1 << 10)) : \
|
||||
((LED_TIMER3_BASE == (uint32)p_timer) ? (SYSCTRL->SYS_CON15 & (1 << 11)) : 0)))
|
||||
|
||||
|
||||
static inline void hgtimer_v5_irq_config(struct hgtimer_v5 *dev, uint32 enable) {
|
||||
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 pos = 0;
|
||||
uint32 addr = (uint32)(&hw->LED_TMR_CON0);
|
||||
|
||||
//Confirm which led_timer will be enable interrupt
|
||||
if (LED_TIMER0_BASE == addr) {
|
||||
pos = 8;
|
||||
} else if (LED_TIMER1_BASE == addr) {
|
||||
pos = 9;
|
||||
} else if (LED_TIMER2_BASE == addr) {
|
||||
pos = 10;
|
||||
} else if (LED_TIMER3_BASE == addr){
|
||||
pos = 11;
|
||||
}
|
||||
|
||||
sysctrl_unlock();
|
||||
if (enable) {
|
||||
SYSCTRL->SYS_CON15 |= (1 << pos);
|
||||
} else {
|
||||
SYSCTRL->SYS_CON15 &= ~(1 << pos);
|
||||
}
|
||||
sysctrl_lock();
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************/
|
||||
/* PWM FUNCTION START */
|
||||
/**********************************************************************************/
|
||||
static int32 hgtimer_v5_pwm_switch_func_cmd(enum hgpwm_v0_func_cmd param) {
|
||||
|
||||
switch (param) {
|
||||
case (HGPWM_V0_FUNC_CMD_INIT):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_INIT;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_DEINIT):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_DEINIT;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_START):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_START;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_STOP):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_STOP;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_IOCTL_SET_PERIOD_DUTY):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_PERIOD_DUTY;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_IOCTL_SET_SINGLE_INCREAM):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_SINGLE_INCREAM;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_IOCTL_SET_INCREAM_DECREASE):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_INCREAM_DECREASE;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_REQUEST_IRQ_PERIOD):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_REQUEST_IRQ_PERIOD;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_RELEASE_IRQ):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_RELEASE_IRQ;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_IOCTL_SET_PRESCALER):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_PRESCALER;
|
||||
break;
|
||||
case (HGPWM_V0_FUNC_CMD_IOCTL_SET_PERIOD_DUTY_IMMEDIATELY):
|
||||
return HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_PERIOD_DUTY_IMMEDIATELY;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_pwm_switch_period_duty(uint32 period, uint32 duty, uint32 *p_period, uint32 *p_duty) {
|
||||
|
||||
uint32 pmu_con0_tmp = 0;
|
||||
uint32 period_us_to_reg = 0;
|
||||
uint32 duty_us_to_reg = 0;
|
||||
|
||||
pmu_con0_tmp = PMU->PMUCON0;
|
||||
|
||||
/* make sure the period */
|
||||
switch ((pmu_con0_tmp & (0x3 << 25)) >> 25) {
|
||||
/* rc128k_pre */
|
||||
case (0):
|
||||
period_us_to_reg = ((128000*period) / 1000000);
|
||||
duty_us_to_reg = ((128000*duty ) / 1000000);
|
||||
|
||||
if (period_us_to_reg && duty_us_to_reg) {
|
||||
*p_period = period_us_to_reg;
|
||||
*p_duty = duty_us_to_reg;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
/* x32m_div_clk */
|
||||
case (1):
|
||||
period_us_to_reg = ((32000000*period) / 1000000);
|
||||
duty_us_to_reg = ((32000000*duty ) / 1000000);
|
||||
|
||||
if (period_us_to_reg && duty_us_to_reg) {
|
||||
*p_period = period_us_to_reg;
|
||||
*p_duty = duty_us_to_reg;
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
/* rc10m_clk */
|
||||
case (2):
|
||||
period_us_to_reg = ((10000000*period) / 1000000);
|
||||
duty_us_to_reg = ((10000000*duty ) / 1000000);
|
||||
|
||||
if (period_us_to_reg && duty_us_to_reg) {
|
||||
*p_period = period_us_to_reg;
|
||||
*p_duty = duty_us_to_reg;
|
||||
return 2;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
/* lxosc32k_clk */
|
||||
case (3):
|
||||
period_us_to_reg = ((32000*period) / 1000000);
|
||||
duty_us_to_reg = ((32000*duty ) / 1000000);
|
||||
|
||||
if (period_us_to_reg && duty_us_to_reg) {
|
||||
*p_period = period_us_to_reg;
|
||||
*p_duty = duty_us_to_reg;
|
||||
return 3;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_init(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
uint32 period_to_reg = 0;
|
||||
uint32 duty_to_reg = 0;
|
||||
uint32 led_timer_con0_tmp = 0;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
|
||||
if (dev->opened) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (pin_func(dev->dev.dev.dev_id , 1) != RET_OK) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* make sure the period & duty */
|
||||
hgtimer_v5_pwm_switch_period_duty(p_config->period, p_config->duty, &period_to_reg, &duty_to_reg);
|
||||
|
||||
hgtimer_v5_irq_config(dev, 0);
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, 0x00000000);
|
||||
|
||||
/* config reg */
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_MODE(0xFFF)) | LL_LED_TIMER_CON0_TMR_MODE(1 );
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PSR(0x00F )) | LL_LED_TIMER_CON0_TMR_PSR(0 );
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PR(0xFFF )) | LL_LED_TIMER_CON0_TMR_PR(period_to_reg);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_STEP(0xFFF)) | LL_LED_TIMER_CON0_TMR_STEP(duty_to_reg);
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
dev->opened = 1;
|
||||
dev->pwm_en = 1;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_deinit(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
|
||||
if ((!dev->opened) || (!dev->pwm_en)) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
irq_disable(dev->irq_num);
|
||||
pin_func(dev->dev.dev.dev_id , 0);
|
||||
hgtimer_v5_irq_config(dev, 0);
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, 0x00000000);
|
||||
dev->opened = 0;
|
||||
dev->pwm_en = 0;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_start(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
if (!dev->pwm_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
led_timer_con0_tmp |= LL_LED_TIMER_CON0_TMR_EN(1);
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_stop(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
if (!dev->pwm_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
led_timer_con0_tmp &= ~ LL_LED_TIMER_CON0_TMR_EN(1);
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_ioctl_set_period_duty(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
uint32 period_to_reg = 0;
|
||||
uint32 duty_to_reg = 0;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
if (!dev->pwm_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
if ((p_config->duty < 0) || ((p_config->duty) > (p_config->period))) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* make sure the period & duty */
|
||||
if ((-1) == hgtimer_v5_pwm_switch_period_duty(p_config->period, p_config->duty, &period_to_reg, &duty_to_reg)) {
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PR(0xFFF )) | LL_LED_TIMER_CON0_TMR_PR(period_to_reg);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_STEP(0xFFF)) | LL_LED_TIMER_CON0_TMR_STEP(duty_to_reg);
|
||||
|
||||
/* led timer must stop to config period & duty */
|
||||
hgtimer_v5_pwm_func_stop(dev, p_config);
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
hgtimer_v5_pwm_func_start(dev, p_config);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_ioctl_set_single_incream(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
uint32 period_to_reg = 0;
|
||||
uint32 none = 50; /* just for through the "func_switch_period_duty", no use */
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
if (!dev->pwm_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* make sure the pwm step > 0 */
|
||||
if (!p_config->duty) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* make sure the period & duty */
|
||||
if ((-1) == hgtimer_v5_pwm_switch_period_duty(p_config->period, p_config->duty, &period_to_reg, &none)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* config reg */
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_MODE(0xFFF)) | LL_LED_TIMER_CON0_TMR_MODE(2);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PSR(0x00F )) | LL_LED_TIMER_CON0_TMR_PSR(0);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PR(0xFFF )) | LL_LED_TIMER_CON0_TMR_PR(period_to_reg);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_STEP(0xFFF)) | LL_LED_TIMER_CON0_TMR_STEP(p_config->duty);
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_ioctl_set_incream_decrease(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
uint32 period_to_reg = 0;
|
||||
uint32 none = 50; /* just for through the "func_switch_period_duty", no use */
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
if (!dev->pwm_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* make sure the pwm step > 0 */
|
||||
if (!p_config->duty) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* make sure the period & duty */
|
||||
if ((-1) == hgtimer_v5_pwm_switch_period_duty(p_config->period, p_config->duty, &period_to_reg, &none)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* config reg */
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_MODE(0xFFF)) | LL_LED_TIMER_CON0_TMR_MODE(3);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PSR(0x00F )) | LL_LED_TIMER_CON0_TMR_PSR(0);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PR(0xFFF )) | LL_LED_TIMER_CON0_TMR_PR(period_to_reg);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_STEP(0xFFF)) | LL_LED_TIMER_CON0_TMR_STEP(p_config->duty);
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_cmd_ioctl_set_prescaler(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config)
|
||||
{
|
||||
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
if (!dev->pwm_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ (LL_LED_TIMER_CON0_TMR_PSR(0xF))) | (LL_LED_TIMER_CON0_TMR_PSR(p_config->param1));
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_cmd_ioctl_set_period_duty_immediately(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config)
|
||||
{
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_request_irq_period(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
if (!dev->pwm_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
dev->_pwm_irq_hdl = p_config->irq_hdl;
|
||||
dev->irq_data = p_config->irq_data;
|
||||
hgtimer_v5_irq_config(dev, 1);
|
||||
irq_enable(dev->irq_num);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static inline int32 hgtimer_v5_pwm_func_release_irq(struct hgtimer_v5 *dev, struct hgpwm_v0_config *p_config) {
|
||||
|
||||
if (!dev->pwm_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
irq_disable(dev->irq_num);
|
||||
dev->_pwm_irq_hdl = NULL;
|
||||
dev->irq_data = 0;
|
||||
hgtimer_v5_irq_config(dev, 0);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_pwm_config(struct hgtimer_v5 *dev, uint32 config, uint32 param) {
|
||||
|
||||
struct hgpwm_v0_config *p_config;
|
||||
int32 hgtimer_v5_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_v5_pwm_func_cmd = hgtimer_v5_pwm_switch_func_cmd(p_config->func_cmd);
|
||||
if ((-1) == hgtimer_v5_pwm_func_cmd) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (hgtimer_v5_pwm_func_cmd) {
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_INIT):
|
||||
ret_val = hgtimer_v5_pwm_func_init(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_DEINIT):
|
||||
ret_val = hgtimer_v5_pwm_func_deinit(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_START):
|
||||
ret_val = hgtimer_v5_pwm_func_start(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_STOP):
|
||||
ret_val = hgtimer_v5_pwm_func_stop(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_PERIOD_DUTY):
|
||||
ret_val = hgtimer_v5_pwm_func_ioctl_set_period_duty(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_SINGLE_INCREAM):
|
||||
ret_val = hgtimer_v5_pwm_func_ioctl_set_single_incream(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_INCREAM_DECREASE):
|
||||
ret_val = hgtimer_v5_pwm_func_ioctl_set_incream_decrease(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_REQUEST_IRQ_PERIOD):
|
||||
ret_val = hgtimer_v5_pwm_func_request_irq_period(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_RELEASE_IRQ):
|
||||
ret_val = hgtimer_v5_pwm_func_release_irq(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_PRESCALER):
|
||||
ret_val = hgtimer_v5_pwm_func_cmd_ioctl_set_prescaler(dev, p_config);
|
||||
break;
|
||||
case (HGTIMER_V5_PWM_FUNC_CMD_IOCTL_SET_PERIOD_DUTY_IMMEDIATELY):
|
||||
ret_val = hgtimer_v5_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_v5_counter_switch_hal_type(struct hgtimer_v5 *dev, enum timer_type param) {
|
||||
|
||||
switch (param) {
|
||||
case (TIMER_TYPE_ONCE):
|
||||
dev->type = HGTIMER_V5_TYPE_ONCE;
|
||||
return 0;
|
||||
break;
|
||||
case (TIMER_TYPE_PERIODIC):
|
||||
dev->type = HGTIMER_V5_TYPE_PERIODIC;
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_counter_switch_tmo_us(uint32 tmo_us) {
|
||||
|
||||
uint32 pmu_con0_tmp = 0;
|
||||
uint32 tmo_us_to_reg = 0;
|
||||
|
||||
pmu_con0_tmp = PMU->PMUCON0;
|
||||
|
||||
/* make sure the period */
|
||||
switch ((pmu_con0_tmp & (0x3 << 25)) >> 25) {
|
||||
/* rc128k_pre */
|
||||
case (0):
|
||||
tmo_us_to_reg = ((128000*tmo_us) / 1000000);
|
||||
if (tmo_us_to_reg) {
|
||||
return tmo_us_to_reg;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
/* x32m_div_clk */
|
||||
case (1):
|
||||
tmo_us_to_reg = ((32000000*tmo_us) / 1000000);
|
||||
if (tmo_us_to_reg) {
|
||||
return tmo_us_to_reg;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
/* rc10m_clk */
|
||||
case (2):
|
||||
tmo_us_to_reg = ((10000000*tmo_us) / 1000000);
|
||||
if (tmo_us_to_reg) {
|
||||
return tmo_us_to_reg;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
/* lxosc32k_clk */
|
||||
case (3):
|
||||
tmo_us_to_reg = ((32000*tmo_us) / 1000000);
|
||||
if (tmo_us_to_reg) {
|
||||
return tmo_us_to_reg;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_counter_set_psc(struct hgtimer_v5 *timer, uint32 psc)
|
||||
{
|
||||
struct hgtimer_v5 *dev = (struct hgtimer_v5 *)timer;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = 0;
|
||||
|
||||
if (!dev->counter_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PSR(0x00F)) | LL_LED_TIMER_CON0_TMR_PSR(psc);
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_counter_func_open(struct timer_device *timer, enum timer_type type, uint32 flags) {
|
||||
|
||||
struct hgtimer_v5 *dev = (struct hgtimer_v5 *)timer;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = 0;
|
||||
|
||||
if (dev->opened) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if ((-1) == hgtimer_v5_counter_switch_hal_type(dev, type)) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
irq_enable(dev->irq_num);
|
||||
hgtimer_v5_irq_config(dev, 0);
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, 0x00000000);
|
||||
|
||||
switch (dev->type) {
|
||||
/* TIMER_TYPE_ONCE */
|
||||
case (HGTIMER_V5_TYPE_ONCE):
|
||||
|
||||
/* TIMER_TYPE_PERIODIC */
|
||||
case (HGTIMER_V5_TYPE_PERIODIC):
|
||||
|
||||
/* TIMER_TYPE_COUNTER */
|
||||
case (HGTIMER_V5_TYPE_COUNTER):
|
||||
//Config reg
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_MODE(0xFFF)) | LL_LED_TIMER_CON0_TMR_MODE(0);
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PSR(0x00F )) | LL_LED_TIMER_CON0_TMR_PSR(0 );
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
break;
|
||||
default:
|
||||
return RET_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
dev->opened = 1;
|
||||
dev->counter_en = 1;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_counter_func_close(struct timer_device *timer) {
|
||||
|
||||
struct hgtimer_v5 *dev = (struct hgtimer_v5 *)timer;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
|
||||
if ((!dev->opened) || (!dev->counter_en)) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
irq_disable(dev->irq_num);
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, 0x00000000);
|
||||
dev->opened = 0;
|
||||
dev->counter_en = 0;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_counter_func_start(struct timer_device *timer, uint32 period_clkpd_cnt, timer_cb_hdl cb, uint32 cb_data) {
|
||||
|
||||
struct hgtimer_v5 *dev = (struct hgtimer_v5 *)timer;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
int32 tmo_us_to_reg = 0;
|
||||
uint32 led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
if (!dev->counter_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* make sure the period */
|
||||
// tmo_us_to_reg = hgtimer_v5_counter_switch_tmo_us(tmo_us);
|
||||
// if ((-1) == tmo_us_to_reg) {
|
||||
// return -EINVAL;
|
||||
// }
|
||||
tmo_us_to_reg = period_clkpd_cnt;
|
||||
if (!tmo_us_to_reg || (tmo_us_to_reg > 0xFFF)) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
switch (dev->type) {
|
||||
|
||||
/* TIMER_TYPE_ONCE */
|
||||
case (HGTIMER_V5_TYPE_ONCE):
|
||||
|
||||
dev->counter_once_en = 1;
|
||||
|
||||
/* config reg */
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PR(0xFFF)) | LL_LED_TIMER_CON0_TMR_PR(tmo_us_to_reg);
|
||||
led_timer_con0_tmp |= LL_LED_TIMER_CON0_TMR_EN(1);
|
||||
|
||||
if (cb) {
|
||||
dev->_counter_irq_hdl = cb;
|
||||
dev->irq_data = cb_data;
|
||||
hgtimer_v5_irq_config(dev, 1);
|
||||
}
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
break;
|
||||
|
||||
/* TIMER_TYPE_PERIODIC */
|
||||
case (HGTIMER_V5_TYPE_PERIODIC):
|
||||
|
||||
/* TIMER_TYPE_COUNTER */
|
||||
case (HGTIMER_V5_TYPE_COUNTER):
|
||||
|
||||
dev->counter_period_en = 1;
|
||||
|
||||
/* config reg */
|
||||
led_timer_con0_tmp = (led_timer_con0_tmp &~ LL_LED_TIMER_CON0_TMR_PR(0xFFF)) | LL_LED_TIMER_CON0_TMR_PR(tmo_us_to_reg);
|
||||
led_timer_con0_tmp |= LL_LED_TIMER_CON0_TMR_EN(1);
|
||||
|
||||
if (cb) {
|
||||
dev->_counter_irq_hdl = cb;
|
||||
dev->irq_data = cb_data;
|
||||
hgtimer_v5_irq_config(dev, 1);
|
||||
}
|
||||
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
break;
|
||||
default:
|
||||
return RET_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_counter_func_stop(struct timer_device *timer) {
|
||||
|
||||
struct hgtimer_v5 *dev = (struct hgtimer_v5 *)timer;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 led_timer_con0_tmp = hw->LED_TMR_CON0;
|
||||
|
||||
if (!dev->counter_en) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
led_timer_con0_tmp &= ~ LL_LED_TIMER_CON0_TMR_EN(1);
|
||||
pmu_reg_write((uint32)&hw->LED_TMR_CON0, led_timer_con0_tmp);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static int32 hgtimer_v5_counter_func_ioctl(struct timer_device *timer, uint32 cmd, uint32 param1, uint32 param2) {
|
||||
|
||||
int32 ret_val = RET_OK;
|
||||
struct hgtimer_v5 *dev = (struct hgtimer_v5 *)timer;
|
||||
|
||||
switch (cmd) {
|
||||
case (HGPWM_V0_FUNC_CMD_MASK):
|
||||
ret_val = hgtimer_v5_pwm_config(dev, param1, 0);
|
||||
break;
|
||||
case (TIMER_SET_CLK_PSC):
|
||||
ret_val = hgtimer_v5_counter_set_psc(dev, param1);
|
||||
break;
|
||||
default:
|
||||
ret_val = RET_ERR;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**********************************************************************************/
|
||||
/* COUNTER FUNCTION END */
|
||||
/**********************************************************************************/
|
||||
static inline void hgtimer_v5_clear_count_ov_pending(struct hgtimer_v5 *dev) {
|
||||
|
||||
uint32 pndclr_temp = PMU->PNDCLR;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
uint32 addr = (uint32)(&hw->LED_TMR_CON0);
|
||||
|
||||
//Confirm which led timer pending will be clear
|
||||
if (LED_TIMER0_BASE == addr) {
|
||||
pndclr_temp |= (1 << 25);
|
||||
} else if (LED_TIMER1_BASE == addr) {
|
||||
pndclr_temp |= (1 << 26);
|
||||
} else if (LED_TIMER2_BASE == addr) {
|
||||
pndclr_temp |= (1 << 27);
|
||||
} else if (LED_TIMER3_BASE == addr) {
|
||||
pndclr_temp |= (1 << 28);
|
||||
}
|
||||
|
||||
pmu_reg_write((uint32)&PMU->PNDCLR, pndclr_temp);
|
||||
}
|
||||
|
||||
static void hgtimer_v5_irq_handler(void *data) {
|
||||
|
||||
struct hgtimer_v5 *dev = (struct hgtimer_v5 *)data;
|
||||
struct hgtimer_v5_hw *hw = (struct hgtimer_v5_hw *)dev->hw;
|
||||
|
||||
if ((hw->LED_TMR_CON0 & LL_LED_TIMER_CON0_TMR_PENDING(1)) &&
|
||||
LL_LED_TIMER_CHECK_COUNT_OV_INTERRUPT_ENABLE(&(hw->LED_TMR_CON0))) {
|
||||
|
||||
hgtimer_v5_clear_count_ov_pending(dev);
|
||||
|
||||
/* 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 */
|
||||
hgtimer_v5_irq_config(dev, 0);
|
||||
}
|
||||
if (dev->_counter_irq_hdl) {
|
||||
dev->_counter_irq_hdl(dev->irq_data, TIMER_INTR_PERIOD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct timer_hal_ops timer_v5_ops = {
|
||||
.open = hgtimer_v5_counter_func_open,
|
||||
.close = hgtimer_v5_counter_func_close,
|
||||
.start = hgtimer_v5_counter_func_start,
|
||||
.stop = hgtimer_v5_counter_func_stop,
|
||||
.ioctl = hgtimer_v5_counter_func_ioctl,
|
||||
};
|
||||
|
||||
int32 hgtimer_v5_attach(uint32 dev_id, struct hgtimer_v5 *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_v5_ops;
|
||||
request_irq(timer->irq_num, hgtimer_v5_irq_handler, timer);
|
||||
dev_register(dev_id, (struct dev_obj *)timer);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user