Files

369 lines
11 KiB
C

/*================================================================
Copyright (c) 2022, Quectel Wireless Solutions Co., Ltd. All rights reserved.
Quectel Wireless Solutions Proprietary and Confidential.
=================================================================*/
/*=================================================================
EDIT HISTORY FOR MODULE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
WHEN WHO WHAT, WHERE, WHY
------------ ------- -------------------------------------------------------------------------------
19/04/2022 Fias.fan Added PWM interface
=================================================================*/
#include "quec_pwm.h"
#include "utlTimer.h"
//#include "quec_atcmd_network.h"
#include "quec_rtos.h"
#include "quec_gpio.h"
#include "gpio.h"
#include "bsp.h"
#if defined QUEC_PWM_ENBALE
#ifndef MIN_SYS
#if defined QUEC_PWM_LOG_ENABLE
#define pwm_log(msg, ...) custom_log("PWM", msg, ##__VA_ARGS__)
#else
#define pwm_log(msg, ...)
#endif
#define PWM_PSCLK (13000000) // 13 MHz
#define PWM_PSCLK_32K (32000) //32KHz
#define PWM_MAX_FREQ (PWM_PSCLK)
#define PWM_SD_POS (6)
#define PWM_FD_POS (10)
#define PWM_FREQ_MASK (0x3f)
#define PWM_DUTY_CYCLE_MASK (0x3ff)
#define PWM_PERIOD_MASK (0x3ff)
#define PWM_0_START_ADDRESS (0xD401A000)
#define PWM_1_START_ADDRESS (0xD401A400)
#define PWM_2_START_ADDRESS (0xD401A800)
#define PWM_3_START_ADDRESS (0xD401AC00)
#define APBC_PWM0_CLK_RST (0xD401500C)
#define APBC_PWM1_CLK_RST (0xD4015010)
#define APBC_PWM2_CLK_RST (0xD4015014)
#define APBC_PWM3_CLK_RST (0xD4015018)
#define PWM_RST_BIT 0x4
#define PWM_FUNC_CLK_EN_BIT 0x2
#define PWM_APB_CLK_EN_BIT 0x1
#define pwm_reg_read(reg) *(volatile unsigned int *)(reg)
#define pwm_reg_write(reg, val) *(volatile unsigned int *)(reg) = (val);
#define pwm_reg_bit_set(reg, val) *(volatile unsigned int *)(reg) |= (val);
#define pwm_reg_bit_clr(reg, val) *(volatile unsigned int *)(reg) &= ~(val);
static volatile QUEC_PWM_REGISTERED_T *pwm_register[QUEC_PWM_MAX_DEVICE] =
{
(volatile QUEC_PWM_REGISTERED_T *)(PWM_0_START_ADDRESS),
(volatile QUEC_PWM_REGISTERED_T *)(PWM_1_START_ADDRESS),
(volatile QUEC_PWM_REGISTERED_T *)(PWM_2_START_ADDRESS),
(volatile QUEC_PWM_REGISTERED_T *)(PWM_3_START_ADDRESS)
};
static unsigned long pwm_apb_register[QUEC_PWM_MAX_DEVICE] =
{
(APBC_PWM0_CLK_RST),
(APBC_PWM1_CLK_RST),
(APBC_PWM2_CLK_RST),
(APBC_PWM3_CLK_RST)
};
struct QUEC_PWM_MAP_GPIO_S gpio_map_pwm_table[] =
{
{117, 0, 2},
{32, 1, 2},
{10, 2, 3},
{11, 3, 3},
#ifdef __QUECTEL_PROJECT_EG800WCN_11LG__
{6, 2, 5},
#else
{6, 2, 3},
#endif
#ifdef __QUECTEL_PROJECT_EG800PCN_LA__
{8, 2, 1},
#else
{8, 0, 1},
#endif
#ifdef __QUECTEL_PROJECT_EG800WCN_11LG__
{7, 3, 5},
{9, 3, 3},
#else
{7, 3, 3},
#endif
{69, 0, 1},
{70, 1, 1},
{89, 2, 2},
{29, 0, 1},
{56, 1, 2},
{58, 3, 2},
};
extern void Delay(unsigned long uSec);
void quec_pwm_apb_bus_clk_enable(QUEC_PWM_DEVICE_NUM_E pwm_num)
{
if(IsChipCraneLRH() || IsChipCraneLG())
{
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_RST_BIT);
pwm_reg_bit_set(pwm_apb_register[pwm_num],PWM_APB_CLK_EN_BIT);
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[pwm_num],pwm_reg_read(pwm_apb_register[pwm_num]));
}
else
{
if(pwm_num <= QUEC_PWM_DEVICE_1)
{
pwm_reg_bit_clr(pwm_apb_register[QUEC_PWM_DEVICE_0],PWM_RST_BIT);
pwm_reg_bit_set(pwm_apb_register[QUEC_PWM_DEVICE_0],PWM_APB_CLK_EN_BIT);
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[QUEC_PWM_DEVICE_0],pwm_reg_read(pwm_apb_register[QUEC_PWM_DEVICE_0]));
}
else
{
pwm_reg_bit_clr(pwm_apb_register[QUEC_PWM_DEVICE_2],PWM_RST_BIT);
pwm_reg_bit_set(pwm_apb_register[QUEC_PWM_DEVICE_2],PWM_APB_CLK_EN_BIT);
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[QUEC_PWM_DEVICE_2],pwm_reg_read(pwm_apb_register[QUEC_PWM_DEVICE_2]));
}
}
}
//获取GPIO复用为pwm功能的pwm号
int quec_gpio_mapto_pwm_device_num(unsigned int gpio_num)
{
unsigned int i;
for(i = 0; i < (sizeof(gpio_map_pwm_table)/sizeof(gpio_map_pwm_table[0])); i++)
{
if(gpio_map_pwm_table[i].gpio_num == gpio_num)
{
return gpio_map_pwm_table[i].pwm_num;
}
}
return QUEC_PWM_MAX_DEVICE;
}
//获取GPIO复用为pwm功能的fun号
int quec_pwm_get_gpio_function(unsigned int gpio_num)
{
unsigned int i;
for(i = 0; i < (sizeof(gpio_map_pwm_table)/sizeof(gpio_map_pwm_table[0])); i++)
{
if(gpio_map_pwm_table[i].gpio_num == gpio_num)
{
return gpio_map_pwm_table[i].gpio_fun;
}
}
return -1;
}
void quec_pwm_apb_bus_clk_disable(QUEC_PWM_DEVICE_NUM_E pwm_num)
{
if(IsChipCraneLRH() || IsChipCraneLG())
{
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_APB_CLK_EN_BIT);
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[pwm_num],pwm_reg_read(pwm_apb_register[pwm_num]));
}
else
{
if(pwm_num <= QUEC_PWM_DEVICE_1)
{
pwm_reg_bit_clr(pwm_apb_register[QUEC_PWM_DEVICE_0],PWM_APB_CLK_EN_BIT);
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[QUEC_PWM_DEVICE_0],pwm_reg_read(pwm_apb_register[QUEC_PWM_DEVICE_0]));
}
else
{
pwm_reg_bit_clr(pwm_apb_register[QUEC_PWM_DEVICE_2],PWM_APB_CLK_EN_BIT);
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[QUEC_PWM_DEVICE_2],pwm_reg_read(pwm_apb_register[QUEC_PWM_DEVICE_2]));
}
}
}
int quec_pwm_enable(unsigned int gpio_num)
{
int pwm_num = 0;
pwm_num = (QUEC_PWM_DEVICE_NUM_E)quec_gpio_mapto_pwm_device_num(gpio_num);
if( pwm_num >= QUEC_PWM_MAX_DEVICE )
{
return -1;
}
//barry 解决宝蓝低功耗pwm无法关闭
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_RST_BIT);
quec_pwm_apb_bus_clk_enable((QUEC_PWM_DEVICE_NUM_E)pwm_num);
Delay(1*1000);
pwm_reg_bit_set(pwm_apb_register[pwm_num],PWM_FUNC_CLK_EN_BIT);
//pwm_log("%s, addr=%x,,reg=%x",__func__,pwm_apb_register[pwm_num],pwm_reg_read(pwm_apb_register[pwm_num]));
return 0;
}
int quec_pwm_disable(unsigned int gpio_num)
{
int pwm_num = 0;
pwm_num = quec_gpio_mapto_pwm_device_num(gpio_num);
if ( pwm_num >= QUEC_PWM_MAX_DEVICE )
return -1;
/* Warning !!! Using of a Graceful shutdown should be done with a care */
/* Writing 0 to the SD bit, needs a little delay before turn the clock to off */
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_FUNC_CLK_EN_BIT);
Delay(100*1000);
quec_pwm_apb_bus_clk_disable((QUEC_PWM_DEVICE_NUM_E)pwm_num);
//pwm_log("%s, addr=%x,reg=%x",__func__,pwm_apb_register[pwm_num],pwm_reg_read(pwm_apb_register[pwm_num]));
return 0;
}
int quec_pwm_pinmux_configure(unsigned int gpio_num)
{
int fun = quec_pwm_get_gpio_function(gpio_num);
if(fun != -1)
{
(*(volatile unsigned long *)(GPIO_MFPR_ADDR(gpio_num))) = (0x10c0 | fun);
return 0;
}
return -1;
}
QUEC_PWM_RETURN_CODE_E quec_pwm_configure( QUEC_PWM_DEVICE_NUM_E pwm_num , QUEC_PWM_CONFIG_T *configuration )
{
unsigned short total_cycle;
unsigned char i;
if ( pwm_num >= QUEC_PWM_MAX_DEVICE )
return QUEC_PWM_RC_ILLEGALL_DEVICE_NUMBER;
if( (PWM_PSCLK/configuration->clk_freq ) > PWM_MAX_FREQ )
return QUEC_PWM_RC_ILLEGALL_FREQUENCY;
if ( configuration->high_one_cycle_duration > configuration->total_one_cycle_duration )
return QUEC_PWM_RC_ILLEGALL_DUTY_CYCLE;
quec_pwm_apb_bus_clk_enable(pwm_num);
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_RST_BIT); //clear rst bit
pwm_reg_bit_clr(pwm_apb_register[pwm_num], 1<< 4); //clr clk src
pwm_reg_bit_set(pwm_apb_register[pwm_num],configuration->clk_src << 4); //set clk src 32K or 13M
pwm_register[pwm_num]->control = ( ( configuration->shutdown << PWM_SD_POS) | (( configuration->clk_freq - 1 ) & PWM_FREQ_MASK ));
pwm_register[pwm_num]->duty_cycle = (( configuration->pwm_out << PWM_FD_POS) | (configuration->high_one_cycle_duration & PWM_DUTY_CYCLE_MASK));
pwm_register[pwm_num]->period_val = ( configuration->total_one_cycle_duration & PWM_PERIOD_MASK);
//pwm_log("%s,control=%x,,duty_cycle=%x,, period_val=%x",__func__,pwm_register[pwm_num]->control,pwm_register[pwm_num]->duty_cycle,pwm_register[pwm_num]->period_val);
return QUEC_PWM_RC_OK;
}
int quec_pwm_config_plus_ex(unsigned int gpio_num,QL_PWM_CONFIG_EX *pwm_parameter)
{
int ret = 0;
int pwm_num = 0;
QUEC_PWM_CONFIG_T pwm_config ;
memset(&pwm_config,0,sizeof(QUEC_PWM_CONFIG_T));
if(CHIP_IS_CRANEL)
{
if(gpio_num != 117 && gpio_num != 32 && gpio_num != 11 && gpio_num != 10
&& gpio_num != 6 && gpio_num != 8 && gpio_num != 7){
return -1;
}
}
else if(CHIP_IS_CRANELR)
{
if(gpio_num != 69 && gpio_num != 70 && gpio_num != 89){
return -1;
}
}
else if(CHIP_IS_CRANELS)
{
if(gpio_num != 29 && gpio_num != 56 && gpio_num != 58){
return -1;
}
}
else if(CHIP_IS_CRANELG)
{
if(gpio_num != 6 && gpio_num != 7 && gpio_num != 9 && gpio_num != 69
&& gpio_num != 70 && gpio_num != 89){
return -1;
}
}
//Although the register has a full duty cycle output of 1, it will show a little duty cycle from the oscilloscope, so it is replaced by a gpio output high and low level
if(pwm_parameter->high_one_cycle_duration==0 || pwm_parameter->total_one_cycle_duration==0)
{
quec_gpio_init( (GPIO_PIN_NUMBER_E)gpio_num,PIN_DIRECTION_OUT, PIN_PULL_PD,PIN_LEVEL_LOW);
return 0;
}
if(pwm_parameter->high_one_cycle_duration==pwm_parameter->total_one_cycle_duration)
{
quec_gpio_init( (GPIO_PIN_NUMBER_E)gpio_num,PIN_DIRECTION_OUT, PIN_PULL_PU,PIN_LEVEL_HIGH );
return 0;
}
/**/
pwm_num = quec_gpio_mapto_pwm_device_num(gpio_num);
ret = quec_pwm_pinmux_configure(gpio_num);
if(ret != 0)
{
//pwm_log("gpio number =%d is invalid.\n",gpio_num);
return -1;
}
pwm_config.shutdown = QUEC_PWM_SHUTDOWN_ABRUPTLY;
pwm_config.pwm_out = QUEC_PWM_OUT_SET_BY_DCYCLE;
pwm_config.clk_src = (QUEC_PWM_CLK_SRC_E)pwm_parameter->clk_src;
pwm_config.clk_freq =pwm_parameter->pwm_psc;
pwm_config.high_one_cycle_duration = pwm_parameter->high_one_cycle_duration;
pwm_config.total_one_cycle_duration = pwm_parameter->total_one_cycle_duration ;
// printf("PWM=%d\n %d\n %ld\n %d\n %d\n",gpio_num,pwm_parameter->clk_src,pwm_parameter->pwm_psc,pwm_parameter->high_one_cycle_duration,pwm_parameter->total_one_cycle_duration);
if(pwm_config.total_one_cycle_duration>1024)
{
return -1;
}
ret = (int)quec_pwm_configure((QUEC_PWM_DEVICE_NUM_E)pwm_num,&pwm_config);
if((QUEC_PWM_RETURN_CODE_E)ret != QUEC_PWM_RC_OK)
{
return -1;
}
return 0;
}
#endif /*MIN_SYS*/
#endif