mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-25 05:28:55 +00:00
654 lines
19 KiB
C
654 lines
19 KiB
C
/*
|
|
* Copyright (c) 2022-2025, ArtInChip Technology Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Authors: zrq <ruiqi.zheng@artinchip.com>
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "aic_core.h"
|
|
#include "aic_hal_clk.h"
|
|
|
|
#include "hal_epwm.h"
|
|
|
|
/* Register definition of PWMCS Controller */
|
|
#define EPWM_BASE (PWMCS_BASE)
|
|
#define GLB_BASE_E (PWMCS_BASE + 0xF000)
|
|
|
|
#if defined (AIC_EPWM_DRV_V11) || defined (AIC_EPWM_DRV_V12)
|
|
#define GLB_CLK_CTL_E 0x020
|
|
#define GLB_DLL_LDO_EN 0x080
|
|
#elif defined (AIC_EPWM_DRV_V10)
|
|
#define GLB_CLK_CTL_E 0x000
|
|
#endif
|
|
#define GLB_PWM_INT_STS 0x004
|
|
#define GLB_PWM_EN 0x014
|
|
|
|
#define EPWM_CNT_PRDV(n) ((((n) & 0xF) << 8) + 0x000)
|
|
#define EPWM_CNT_V(n) ((((n) & 0xF) << 8) + 0x008)
|
|
#define EPWM_CNT_CONF(n) ((((n) & 0xF) << 8) + 0x00C)
|
|
#define EPWM_CNT_AV(n) ((((n) & 0xF) << 8) + 0x014)
|
|
#define EPWM_CNT_BV(n) ((((n) & 0xF) << 8) + 0x018)
|
|
#define EPWM_UPDT_MOD(n) ((((n) & 0xF) << 8) + 0x01C)
|
|
#define EPWMA_ACT(n) ((((n) & 0xF) << 8) + 0x020)
|
|
#define EPWMB_ACT(n) ((((n) & 0xF) << 8) + 0x024)
|
|
#define EPWM_SW_ACT(n) ((((n) & 0xF) << 8) + 0x028)
|
|
#define EPWM_ACT_SW_CT(n) ((((n) & 0xF) << 8) + 0x02C)
|
|
#define EPWM_FLT_PRTCT(n) ((((n) & 0xF) << 8) + 0x044)
|
|
#define EPWM_ADC_INT_CTL(n) ((((n) & 0xF) << 8) + 0x058)
|
|
#define EPWM_ADC_INT_PRE(n) ((((n) & 0xF) << 8) + 0x05C)
|
|
#define EPWM_EVNT_FLAG(n) ((((n) & 0xF) << 8) + 0x060)
|
|
#define EPWM_EVENT_CLR(n) ((((n) & 0xF) << 8) + 0x064)
|
|
#define EPWM_HRPWM_EN(n) ((((n) & 0xF) << 8) + 0x080)
|
|
#define EPWM_HRPWM_CFG(n) ((((n) & 0xF) << 8) + 0x084)
|
|
#if defined (AIC_EPWM_DRV_V11) || defined (AIC_EPWM_DRV_V12)
|
|
#define EPWM_PUL_OUT_CFG(n) ((((n) & 0xF) << 8) + 0x0A0)
|
|
#define EPWM_PUL_OUT_NUM(n) ((((n) & 0xF) << 8) + 0x0A4)
|
|
#endif
|
|
#define EPWM_VERSION(n) ((((n) & 0xF) << 8) + 0x0FC)
|
|
|
|
enum epwm_adc_cvra_mode {
|
|
PWM_ADC_CVRA_CNT_Z = 0,
|
|
PWM_ADC_CVRA_CNT_PRD,
|
|
PWM_ADC_CVRA_CNT_U_AV,
|
|
PWM_ADC_CVRA_CNT_D_AV,
|
|
PWM_ADC_CVRA_CNT_U_BV,
|
|
PWM_ADC_CVRA_CNT_D_BV
|
|
};
|
|
|
|
#define GLB_EPWM_EN_B BIT(0)
|
|
#define EPWM_S0_CLK_EN BIT(0)
|
|
#define EPMW_SX_CLK_EN(n) (EPWM_S0_CLK_EN << (n))
|
|
#define EPWMA_ACT_LP_CNT_ZRO 0x0
|
|
#define EPWMA_ACT_LP_PUL_CNT_ZRO 0x4
|
|
#define EPWMA_ACT_LP_MASK GENMASK(14, 12)
|
|
#define EPWMA_ACT_LP_SHIFT 12
|
|
#define EPWMA_ACT_CNTDBV_SHIFT 10
|
|
#define EPWMA_ACT_CNTUBV_SHIFT 8
|
|
#define EPWMA_ACT_CNTDAV_SHIFT 6
|
|
#define EPWMA_ACT_CNTUAV_SHIFT 4
|
|
#define EPWMA_ACT_CNTPRD_SHIFT 2
|
|
#define EPWM_TBPRD_MAX 0xFFFF
|
|
#define EPWM_CLK_DIV1_MAX 0x7
|
|
#define EPWM_CLK_DIV2_SHIFT 10
|
|
#define EPWM_CLK_DIV1_SHIFT 7
|
|
#define EPWM_CLK_DIV2_MASK GENMASK(12, 10)
|
|
#define EPWM_CLK_DIV1_MASK GENMASK(9, 7)
|
|
#define EPWM_CNT_MOD_MASK GENMASK(1, 0)
|
|
#define EPWM_CNT_MOD_SHIFT 0
|
|
|
|
#define EPWM_ADC_CVRA_SEL_EN BIT(11)
|
|
#define EPWM_ADC_CVRA_SEL_MASK GENMASK(10, 8)
|
|
#define EPWM_ADC_CVRA_SEL_SHIFT 8
|
|
#if defined (AIC_EPWM_DRV_V12)
|
|
#define EPWM_INT_EN BIT(4)
|
|
#else
|
|
#define EPWM_INT_EN BIT(3)
|
|
#endif
|
|
#define EPWM_INT_SEL_SHIFT 0
|
|
#define EPWM_INT_SEL_MASK GENMASK(2, 0)
|
|
#define EPWM_INT_CLR BIT(0)
|
|
|
|
#define EPWM_ADC_CRVA_DIV_MASK GENMASK(9, 8)
|
|
#define EPWM_ADC_CRVA_DIV_SHIFT 8
|
|
#define EPWM_INT_DIV_1 BIT(0)
|
|
|
|
#define EPWM_ACT_SW_CT_UPDT_PUL 0x4
|
|
#define EPWM_ACT_SW_CT_UPDT_MASK GENMASK(8, 6)
|
|
#define EPWM_ACT_SW_CT_UPDT 6
|
|
#define EPWM_SWACT_UPDT 3 << EPWM_ACT_SW_CT_UPDT
|
|
#define EPWMA_ACT_SW_CT_SHIFT 0
|
|
#define EPWMA_ACT_SW_CT_MASK GENMASK(1, 0)
|
|
#define EPWMB_ACT_SW_CT_SHIFT 2
|
|
#define EPWMB_ACT_SW_CT_MASK GENMASK(3, 2)
|
|
#define HRPWM_OUTPUT_MODE_NO_ACT 0xF00
|
|
#define EPWM_CNT_PRD_LD_SHIFT 4
|
|
#define EPWM_CNT_PRD_LD_MASK GENMASK(5, 4)
|
|
#define EPWM_PRD_LD_CNT_ZRO 0x0
|
|
#define EPWM_PRD_LD_PUL_CNT_ZRO 0x1
|
|
#define EPWM_CNT_PH_EN BIT(2)
|
|
#define EPWM_SW_FRC_SYNC BIT(6)
|
|
#define EPWM_CMPA_LP_SHIFT 0
|
|
#define EPWM_CMPA_LP_MASK GENMASK(2, 0)
|
|
#define EPWM_CMPB_LP_SHIFT 3
|
|
#define EPWM_CMPB_LP_MASK GENMASK(5, 3)
|
|
#define EPWM_CMP_LP_CNT_ZRO 0x0
|
|
#define EPWM_CMP_LP_PUL_CNT_ZRO 0x4
|
|
#if defined (AIC_EPWM_DRV_V11) || defined (AIC_EPWM_DRV_V12)
|
|
#define EPWM_PUL_CNT_SRC_SHIFT 1
|
|
#define EPWM_PUL_CNT_SRC_MASK GENMASK(3, 1)
|
|
#define EPWM_PUL_CNT_SRC_CNT_DB 0x5
|
|
#define EPWM_PUL_OUT_EN BIT(0)
|
|
#define EPWM_PUL_SW_UPDT BIT(4)
|
|
#endif
|
|
|
|
#ifndef NSEC_PER_SEC
|
|
#define NSEC_PER_SEC 1000000000
|
|
#endif
|
|
|
|
static struct aic_epwm_arg g_epwm_args[AIC_EPWM_CH_NUM] = {{0}};
|
|
|
|
static inline void epwm_writel(u32 val, int reg)
|
|
{
|
|
writel(val, EPWM_BASE + reg);
|
|
}
|
|
|
|
static inline u32 epwm_readl(int reg)
|
|
{
|
|
return readl(EPWM_BASE + reg);
|
|
}
|
|
|
|
static inline void epwm_writel_bits(u32 val, u32 mask, u32 shift, int reg)
|
|
{
|
|
writel_bits(val, mask, shift, EPWM_BASE + reg);
|
|
}
|
|
|
|
static void aic_epwm_ch_info(char *buf, u32 ch, u32 en, struct aic_epwm_arg *arg)
|
|
{
|
|
static const char *mode[] = {"Up", "Down", "UpDw"};
|
|
static const char *act[] = {"-", "Low", "Hgh", "Inv"};
|
|
|
|
snprintf(buf, 128, "%2d %2d %4s %11d %3d %3s %3s %3s %3s %3s %3s\n"
|
|
"%30s %3s %3s %3s %3s %3s\n",
|
|
ch, (en & EPMW_SX_CLK_EN(ch)) ? 1 : 0,
|
|
mode[arg->mode], arg->tb_clk_rate, arg->def_level,
|
|
act[arg->action0.CBD], act[arg->action0.CBU],
|
|
act[arg->action0.CAD], act[arg->action0.CAU],
|
|
act[arg->action0.PRD], act[arg->action0.ZRO],
|
|
act[arg->action1.CBD], act[arg->action1.CBU],
|
|
act[arg->action1.CAD], act[arg->action1.CAU],
|
|
act[arg->action1.PRD], act[arg->action1.ZRO]);
|
|
}
|
|
|
|
static int hal_epwm_ch_check(u32 ch)
|
|
{
|
|
if (ch >= AIC_EPWM_CH_NUM) {
|
|
hal_log_err("ch%d is out of range, max num:%d\n", ch, AIC_EPWM_CH_NUM -1);
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void hal_epwm_status_show(void)
|
|
{
|
|
int enable = readl(GLB_BASE_E + GLB_CLK_CTL_E);
|
|
char info[AIC_EPWM_CH_NUM][128] = {{0}};
|
|
u32 i;
|
|
|
|
printf("Ch En Mode Tb-clk-rate Def CBD CBU CAD CAU PRD ZRO\n");
|
|
|
|
for (i = 0; i < AIC_EPWM_CH_NUM; i++) {
|
|
aic_epwm_ch_info(info[i], i, enable, &g_epwm_args[i]);
|
|
printf("%s", info[i]);
|
|
}
|
|
}
|
|
|
|
static void epwm_reg_enable(int addr, int bit, int enable)
|
|
{
|
|
int tmp;
|
|
|
|
tmp = readl((ulong)addr);
|
|
if (enable)
|
|
tmp |= bit;
|
|
else
|
|
tmp &= ~bit;
|
|
|
|
writel(tmp, (ulong)addr);
|
|
}
|
|
|
|
u32 hal_epwm_int_sts(u32 ch)
|
|
{
|
|
return epwm_readl(EPWM_EVNT_FLAG(ch));
|
|
}
|
|
|
|
void hal_epwm_clr_int(u32 stat, u32 ch)
|
|
{
|
|
epwm_writel(stat, EPWM_EVENT_CLR(ch));
|
|
}
|
|
|
|
void hal_epwm_int_config(u32 ch, u8 irq_mode, u8 enable)
|
|
{
|
|
epwm_reg_enable(EPWM_BASE + EPWM_ADC_INT_PRE(ch), EPWM_INT_DIV_1, enable);
|
|
|
|
if (enable)
|
|
epwm_writel_bits(irq_mode + 2, EPWM_INT_SEL_MASK, EPWM_INT_SEL_SHIFT, EPWM_ADC_INT_CTL(ch));
|
|
|
|
epwm_reg_enable(EPWM_BASE + EPWM_ADC_INT_CTL(ch), EPWM_INT_EN, enable);
|
|
}
|
|
|
|
void hal_epwm_ch_init(struct aic_epwm_arg *epwm_arg)
|
|
{
|
|
struct aic_epwm_arg *arg = NULL;
|
|
u32 ch = 0;
|
|
|
|
ch = epwm_arg->id;
|
|
|
|
if (hal_epwm_ch_check(ch) < 0)
|
|
return;
|
|
|
|
arg = &g_epwm_args[ch];
|
|
|
|
arg->sync_mode = epwm_arg->sync_mode;
|
|
arg->mode = epwm_arg->mode;
|
|
arg->available = 1;
|
|
arg->def_level = epwm_arg->def_level;
|
|
memcpy(&arg->action0, &epwm_arg->action0, sizeof(struct aic_epwm_action));
|
|
memcpy(&arg->action1, &epwm_arg->action1, sizeof(struct aic_epwm_action));
|
|
|
|
epwm_reg_enable(GLB_BASE_E + GLB_CLK_CTL_E, EPMW_SX_CLK_EN(ch), 1);
|
|
epwm_writel(EPWM_SWACT_UPDT, EPWM_SW_ACT(ch));
|
|
|
|
if ((ch >= 0) && (ch <= 5)) {
|
|
epwm_writel(1, EPWM_HRPWM_EN(ch));
|
|
epwm_writel(EPWM_SWACT_UPDT, EPWM_SW_ACT(ch));
|
|
epwm_writel(HRPWM_OUTPUT_MODE_NO_ACT, EPWM_HRPWM_CFG(ch));
|
|
}
|
|
|
|
if (arg->def_level)
|
|
hal_epwm_act_sw_ct(ch, EPWM_SET_CMPA_CMPB, EPWM_ACT_SW_HIGH);
|
|
else
|
|
hal_epwm_act_sw_ct(ch, EPWM_SET_CMPA_CMPB, EPWM_ACT_SW_LOW);
|
|
}
|
|
|
|
static int hal_epwm_calculate_div(u32 ch, float tar_freq)
|
|
{
|
|
struct aic_epwm_arg *arg = &g_epwm_args[ch];
|
|
int div1 = 0, div2 = 0;
|
|
int div1_index = 0, div2_index = 0;
|
|
int available_div1[] = {1, 2, 4, 6, 8, 10, 12, 14};
|
|
int available_div2[] = {1, 2, 4, 8, 16, 32, 64, 128};
|
|
float min_error = 1e6;
|
|
|
|
for (int i = 0; i < sizeof(available_div1) / sizeof(available_div1[0]); ++i) {
|
|
for (int j = 0; j < sizeof(available_div2) / sizeof(available_div2[0]); ++j) {
|
|
int current_div = available_div1[i] * available_div2[j];
|
|
int count_value = arg->clk_rate / (current_div * tar_freq);
|
|
if (count_value < EPWM_TBPRD_MAX) {
|
|
float current_freq = arg->clk_rate / (current_div * count_value);
|
|
float error = fabs(current_freq - tar_freq);
|
|
|
|
if (error < min_error) {
|
|
min_error = error;
|
|
div1 = available_div1[i];
|
|
div2 = available_div2[j];
|
|
div1_index = i;
|
|
div2_index = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
hal_log_debug("div1:%d div2:%d\n", div1, div2);
|
|
|
|
if (div1 == 0 && div2 == 0) {
|
|
hal_log_err("calculate div error,should adjust the EPWM_CLK_RATE.\n");
|
|
return -1;
|
|
}
|
|
|
|
epwm_writel_bits(div1_index, EPWM_CLK_DIV1_MASK, EPWM_CLK_DIV1_SHIFT, EPWM_CNT_CONF(ch));
|
|
epwm_writel_bits(div2_index, EPWM_CLK_DIV2_MASK, EPWM_CLK_DIV2_SHIFT, EPWM_CNT_CONF(ch));
|
|
arg->tb_clk_rate = arg->clk_rate / (div1 * div2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_epwm_set(u32 ch, u32 duty_ns, u32 period_ns, u32 output)
|
|
{
|
|
u32 prd = 0;
|
|
u64 duty = 0;
|
|
struct aic_epwm_arg *arg = NULL;
|
|
|
|
if (hal_epwm_ch_check(ch) < 0)
|
|
return -EINVAL;
|
|
|
|
arg = &g_epwm_args[ch];
|
|
|
|
if (!arg->available) {
|
|
hal_log_err("ch%d is unavailable\n", ch);
|
|
return -EINVAL;
|
|
}
|
|
|
|
arg->freq = (float)NSEC_PER_SEC / period_ns;
|
|
|
|
if (hal_epwm_calculate_div(ch, arg->freq) < 0)
|
|
return -ERANGE;
|
|
|
|
prd = arg->tb_clk_rate / arg->freq;
|
|
|
|
hal_log_debug("output:Freq %d.%03d Hz, prd value %d, Time-base %d Hz\n",
|
|
(int)arg->freq, (int)((arg->freq - (int)arg->freq) * 1000), prd, arg->tb_clk_rate);
|
|
|
|
if (arg->mode == EPWM_MODE_UP_DOWN_COUNT)
|
|
prd >>= 1;
|
|
else
|
|
prd--;
|
|
|
|
if (prd > EPWM_TBPRD_MAX) {
|
|
hal_log_err("ch%d period %d is too big\n", ch, prd);
|
|
return -ERANGE;
|
|
}
|
|
arg->period = prd;
|
|
epwm_writel(prd, EPWM_CNT_PRDV(ch));
|
|
|
|
duty = (u64)duty_ns * (u64)prd;
|
|
do_div(duty, period_ns);
|
|
if (duty == prd)
|
|
duty++;
|
|
|
|
arg->duty = (u32)duty;
|
|
|
|
switch (output) {
|
|
case EPWM_SET_CMPA:
|
|
epwm_writel((u32)duty, EPWM_CNT_AV(ch));
|
|
hal_log_debug("ch%d Set CMPA %u/%u\n", ch, (u32)duty, prd);
|
|
break;
|
|
case EPWM_SET_CMPB:
|
|
epwm_writel((u32)duty, EPWM_CNT_BV(ch));
|
|
hal_log_debug("ch%d Set CMPB %u/%u\n", ch, (u32)duty, prd);
|
|
break;
|
|
case EPWM_SET_CMPA_CMPB:
|
|
epwm_writel((u32)duty, EPWM_CNT_AV(ch));
|
|
epwm_writel((u32)duty, EPWM_CNT_BV(ch));
|
|
hal_log_debug("ch%d Set CMPA&B %u/%u\n", ch, (u32)duty, prd);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void hal_epwm_act_sw_ct(u32 ch, u32 output, u32 action)
|
|
{
|
|
switch (output) {
|
|
case EPWM_SET_CMPA:
|
|
epwm_writel_bits(action, EPWMA_ACT_SW_CT_MASK, EPWMA_ACT_SW_CT_SHIFT, EPWM_ACT_SW_CT(ch));
|
|
break;
|
|
case EPWM_SET_CMPB:
|
|
epwm_writel_bits(action, EPWMB_ACT_SW_CT_MASK, EPWMB_ACT_SW_CT_SHIFT, EPWM_ACT_SW_CT(ch));
|
|
break;
|
|
case EPWM_SET_CMPA_CMPB:
|
|
epwm_writel_bits(action, EPWMA_ACT_SW_CT_MASK, EPWMA_ACT_SW_CT_SHIFT, EPWM_ACT_SW_CT(ch));
|
|
epwm_writel_bits(action, EPWMB_ACT_SW_CT_MASK, EPWMB_ACT_SW_CT_SHIFT, EPWM_ACT_SW_CT(ch));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void hal_epwm_count_ct(u32 ch, enum aic_epwm_mode mode)
|
|
{
|
|
epwm_writel_bits(mode, EPWM_CNT_MOD_MASK, EPWM_CNT_MOD_SHIFT, EPWM_CNT_CONF(ch));
|
|
}
|
|
|
|
#if defined (AIC_EPWM_DRV_V11) || defined (AIC_EPWM_DRV_V12)
|
|
void hal_epwm_pul_config(u32 ch)
|
|
{
|
|
hal_epwm_act_sw_ct(ch, EPWM_SET_CMPA_CMPB, EPWM_ACT_SW_LOW);
|
|
epwm_writel_bits(EPWM_PRD_LD_PUL_CNT_ZRO, EPWM_CNT_PRD_LD_MASK, EPWM_CNT_PRD_LD_SHIFT, EPWM_CNT_CONF(ch));
|
|
epwm_writel_bits(EPWM_CMP_LP_PUL_CNT_ZRO, EPWM_CMPA_LP_MASK, EPWM_CMPA_LP_SHIFT, EPWM_UPDT_MOD(ch));
|
|
epwm_writel_bits(EPWM_CMP_LP_PUL_CNT_ZRO, EPWM_CMPB_LP_MASK, EPWM_CMPB_LP_SHIFT, EPWM_UPDT_MOD(ch));
|
|
epwm_writel_bits(EPWMA_ACT_LP_PUL_CNT_ZRO, EPWMA_ACT_LP_MASK, EPWMA_ACT_LP_SHIFT, EPWMA_ACT(ch));
|
|
epwm_writel_bits(EPWMA_ACT_LP_PUL_CNT_ZRO, EPWMA_ACT_LP_MASK, EPWMA_ACT_LP_SHIFT, EPWMB_ACT(ch));
|
|
epwm_writel_bits(EPWM_ACT_SW_CT_UPDT_PUL, EPWM_ACT_SW_CT_UPDT_MASK, EPWM_ACT_SW_CT_UPDT, EPWM_SW_ACT(ch));
|
|
epwm_writel_bits(0x1, EPWM_PUL_CNT_SRC_MASK, EPWM_PUL_CNT_SRC_SHIFT, EPWM_PUL_OUT_CFG(ch));
|
|
hal_epwm_int_config(ch, 5, 1);
|
|
epwm_reg_enable(EPWM_BASE + EPWM_PUL_OUT_CFG(ch), EPWM_PUL_OUT_EN, 1);
|
|
}
|
|
|
|
int hal_epwm_pul_set(u32 ch, u32 duty_ns, u32 period_ns, u32 output, u32 num)
|
|
{
|
|
int ret;
|
|
|
|
ret = hal_epwm_set(ch, duty_ns, period_ns, output);
|
|
if (ret)
|
|
return ret;
|
|
|
|
epwm_writel(num - 1, EPWM_PUL_OUT_NUM(ch));
|
|
|
|
return 0;
|
|
}
|
|
|
|
void hal_epwm_pul_out_ct(u32 ch, u32 enable)
|
|
{
|
|
epwm_reg_enable(EPWM_BASE + EPWM_PUL_OUT_CFG(ch), EPWM_PUL_OUT_EN, enable);
|
|
}
|
|
|
|
void hal_epwm_pul_sw_updt(u32 ch)
|
|
{
|
|
epwm_reg_enable(EPWM_BASE + EPWM_PUL_OUT_CFG(ch), EPWM_PUL_SW_UPDT, 1);
|
|
}
|
|
#endif
|
|
|
|
int hal_epwm_get(u32 ch, u32 *duty_ns, u32 *period_ns)
|
|
{
|
|
struct aic_epwm_arg *arg = NULL;
|
|
|
|
if (hal_epwm_ch_check(ch) < 0)
|
|
return -EINVAL;
|
|
|
|
arg = &g_epwm_args[ch];
|
|
|
|
if (!arg->available) {
|
|
hal_log_err("ch%d is unavailable\n", ch);
|
|
return -EINVAL;
|
|
}
|
|
|
|
*duty_ns = arg->duty;
|
|
*period_ns = arg->period;
|
|
return 0;
|
|
}
|
|
|
|
int hal_epwm_get_default_level(u32 ch)
|
|
{
|
|
struct aic_epwm_arg *arg = NULL;
|
|
|
|
if (hal_epwm_ch_check(ch) < 0)
|
|
return -EINVAL;
|
|
|
|
arg = &g_epwm_args[ch];
|
|
|
|
if (!arg->available) {
|
|
hal_log_err("ch%d is unavailable\n", ch);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return (int)arg->def_level;
|
|
}
|
|
|
|
static void epwm_action_set(u32 ch, struct aic_epwm_action *act, char *name)
|
|
{
|
|
u32 offset;
|
|
u32 action = 0;
|
|
|
|
if (strcmp(name, "action0") == 0)
|
|
offset = EPWMA_ACT(ch);
|
|
else
|
|
offset = EPWMB_ACT(ch);
|
|
|
|
action |= (act->CBD << EPWMA_ACT_CNTDBV_SHIFT) |
|
|
(act->CBU << EPWMA_ACT_CNTUBV_SHIFT) |
|
|
(act->CAD << EPWMA_ACT_CNTDAV_SHIFT) |
|
|
(act->CAU << EPWMA_ACT_CNTUAV_SHIFT) |
|
|
(act->PRD << EPWMA_ACT_CNTPRD_SHIFT) | act->ZRO;
|
|
epwm_writel(action, offset);
|
|
}
|
|
|
|
#ifdef AIC_EPWM_TRIG_PSADC
|
|
int hal_epwm_trig_psadc(u32 ch, bool enable)
|
|
{
|
|
static bool active = false;
|
|
|
|
/* ONLY enable trigger mode once time */
|
|
if ((active && enable) || (!active && !enable))
|
|
return 0;
|
|
|
|
if (enable) {
|
|
epwm_writel_bits(PWM_ADC_CVRA_CNT_PRD,
|
|
EPWM_ADC_CVRA_SEL_MASK, EPWM_ADC_CVRA_SEL_SHIFT,
|
|
EPWM_ADC_INT_CTL(ch));
|
|
epwm_writel_bits(AIC_EPWM_TRIG_PERIOD,
|
|
EPWM_ADC_CRVA_DIV_MASK, EPWM_ADC_CRVA_DIV_SHIFT,
|
|
EPWM_ADC_INT_PRE(ch));
|
|
}
|
|
epwm_reg_enable(EPWM_BASE + EPWM_ADC_INT_CTL(ch), EPWM_ADC_CVRA_SEL_EN, enable);
|
|
active = enable;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int hal_epwm_enable(u32 ch)
|
|
{
|
|
struct aic_epwm_arg *arg = NULL;
|
|
|
|
if (hal_epwm_ch_check(ch) < 0)
|
|
return -EINVAL;
|
|
|
|
arg = &g_epwm_args[ch];
|
|
|
|
if (!arg->available) {
|
|
hal_log_err("ch%d is unavailable\n", ch);
|
|
return -EINVAL;
|
|
}
|
|
|
|
hal_epwm_act_sw_ct(ch, EPWM_SET_CMPA_CMPB, EPWM_ACT_SW_NONE);
|
|
|
|
epwm_action_set(ch, &arg->action0, "action0");
|
|
epwm_action_set(ch, &arg->action1, "action1");
|
|
|
|
#ifdef AIC_EPWM_TRIG_PSADC
|
|
hal_epwm_trig_psadc(ch, true);
|
|
#endif
|
|
|
|
//For sync mode
|
|
if (arg->sync_mode) {
|
|
epwm_reg_enable(EPWM_BASE + EPWM_CNT_CONF(ch), EPWM_CNT_PH_EN, 1);
|
|
epwm_reg_enable(EPWM_BASE + EPWM_CNT_CONF(ch), EPWM_SW_FRC_SYNC, 1);
|
|
}
|
|
|
|
epwm_writel_bits(arg->mode, EPWM_CNT_MOD_MASK, EPWM_CNT_MOD_SHIFT, EPWM_CNT_CONF(ch));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef AIC_EPWM_DRV_V11
|
|
static void hal_epwm_dll_ldo_en(void)
|
|
{
|
|
writel(0x10, GLB_BASE_E + GLB_DLL_LDO_EN);
|
|
aic_udelay(100);
|
|
writel(0x11, GLB_BASE_E + GLB_DLL_LDO_EN);
|
|
aic_udelay(100);
|
|
writel(0x13, GLB_BASE_E + GLB_DLL_LDO_EN);
|
|
aic_udelay(100);
|
|
writel(0x17, GLB_BASE_E + GLB_DLL_LDO_EN);
|
|
aic_udelay(100);
|
|
writel(0x1F, GLB_BASE_E + GLB_DLL_LDO_EN);
|
|
aic_udelay(100);
|
|
}
|
|
#endif
|
|
|
|
int hal_epwm_disable(u32 ch)
|
|
{
|
|
struct aic_epwm_arg *arg = NULL;
|
|
|
|
if (hal_epwm_ch_check(ch) < 0)
|
|
return -EINVAL;
|
|
|
|
arg = &g_epwm_args[ch];
|
|
|
|
if (!arg->available) {
|
|
hal_log_err("ch%d is unavailable\n", ch);
|
|
return -EINVAL;
|
|
}
|
|
|
|
hal_log_debug("ch%d disable\n", ch);
|
|
|
|
#if defined (AIC_EPWM_DRV_V11) || defined (AIC_EPWM_DRV_V12)
|
|
|
|
#ifdef AIC_EPWM_TRIG_PSADC
|
|
hal_epwm_trig_psadc(ch, false);
|
|
#endif
|
|
epwm_writel_bits(EPWM_PRD_LD_CNT_ZRO, EPWM_CNT_PRD_LD_MASK, EPWM_CNT_PRD_LD_SHIFT, EPWM_CNT_CONF(ch));
|
|
epwm_writel_bits(EPWM_CMP_LP_CNT_ZRO, EPWM_CMPA_LP_MASK, EPWM_CMPA_LP_SHIFT, EPWM_UPDT_MOD(ch));
|
|
epwm_writel_bits(EPWM_CMP_LP_CNT_ZRO, EPWM_CMPB_LP_MASK, EPWM_CMPB_LP_SHIFT, EPWM_UPDT_MOD(ch));
|
|
epwm_writel_bits(EPWMA_ACT_LP_CNT_ZRO, EPWMA_ACT_LP_MASK, EPWMA_ACT_LP_SHIFT, EPWMA_ACT(ch));
|
|
epwm_writel_bits(EPWMA_ACT_LP_CNT_ZRO, EPWMA_ACT_LP_MASK, EPWMA_ACT_LP_SHIFT, EPWMB_ACT(ch));
|
|
epwm_writel(EPWM_SWACT_UPDT, EPWM_SW_ACT(ch));
|
|
hal_epwm_int_config(ch, 0, 0);
|
|
epwm_reg_enable(EPWM_BASE + EPWM_PUL_OUT_CFG(ch), EPWM_PUL_OUT_EN, 0);
|
|
#endif
|
|
|
|
if (arg->def_level)
|
|
hal_epwm_act_sw_ct(ch, EPWM_SET_CMPA_CMPB, EPWM_ACT_SW_HIGH);
|
|
else
|
|
hal_epwm_act_sw_ct(ch, EPWM_SET_CMPA_CMPB, EPWM_ACT_SW_LOW);
|
|
|
|
epwm_writel_bits(EPWM_MODE_STOP_COUNT, EPWM_CNT_MOD_MASK, EPWM_CNT_MOD_SHIFT, EPWM_CNT_CONF(ch));
|
|
|
|
epwm_writel(0, EPWM_CNT_V(ch));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_epwm_init(void)
|
|
{
|
|
int i, ret = 0;
|
|
int clock_rate;
|
|
|
|
#if defined (AIC_EPWM_DRV_V11)
|
|
u32 clk_id = CLK_PWMCS_SDFM;
|
|
#elif defined (AIC_EPWM_DRV_V10)
|
|
u32 clk_id = CLK_PWMCS;
|
|
#endif
|
|
|
|
#if defined (AIC_EPWM_DRV_V10) || defined (AIC_EPWM_DRV_V11)
|
|
ret = hal_clk_set_freq(clk_id, EPWM_CLK_RATE);
|
|
if (ret < 0) {
|
|
hal_log_err("Failed to set EPWM clk %d\n", EPWM_CLK_RATE);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
clock_rate = hal_clk_get_freq(clk_id);
|
|
if (clock_rate < 0) {
|
|
hal_log_err("Failed to get EPWM clk\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = hal_clk_enable(CLK_PWMCS);
|
|
if (ret < 0) {
|
|
hal_log_err("Failed to enable EPWM clk\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = hal_clk_enable_deassertrst(CLK_PWMCS);
|
|
if (ret < 0) {
|
|
hal_log_err("Failed to reset EPWM deassert\n");
|
|
return -1;
|
|
}
|
|
|
|
epwm_reg_enable(GLB_BASE_E + GLB_PWM_EN, GLB_EPWM_EN_B, 1);
|
|
|
|
#ifdef AIC_EPWM_DRV_V11
|
|
hal_epwm_dll_ldo_en();
|
|
#endif
|
|
|
|
/* default configuration */
|
|
for (i = 0; i < AIC_EPWM_CH_NUM; i++) {
|
|
g_epwm_args[i].tb_clk_rate = clock_rate / 8;
|
|
g_epwm_args[i].clk_rate = clock_rate;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_epwm_deinit(void)
|
|
{
|
|
hal_clk_disable_assertrst(CLK_PWMCS);
|
|
hal_clk_disable(CLK_PWMCS);
|
|
return 0;
|
|
}
|