You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
8.4 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd.. 2021-2021. All rights reserved.
* Description:
* Author:
* Create: 2021-05-12
* Note:
*/
/********************************************************************************************/
/* Includes */
/********************************************************************************************/
#include "drv_sys_ext.h"
#include "drv_pwm_ext.h"
#include "osal_ext.h"
#include "pwm_common.h"
/********************************************************************************************/
/* Defines */
/********************************************************************************************/
#define PWM_CARRIER_SIGNAL_DURATION_US_MAX (120 * 1000 * 1000) /* 120 seconds */
#define PWM_LOW_LEVEL_SIGNAL_DURATION_US_MAX (120 * 1000 * 1000) /* 120 seconds */
/********************************************************************************************/
/* Globals */
/********************************************************************************************/
static ext_chip_name_id g_chip_name_id = 0xFFFF;
static ext_chip_revision g_chip_revision = CHIP_REVISION_MAX;
/********************************************************************************************
Function Implementation
********************************************************************************************/
static inline td_bool pwm_check_v1(td_void)
{
return ((g_chip_name_id == CHIP_NAME_RESERVED13 &&
(g_chip_revision == CHIP_REVISION_B || g_chip_revision == CHIP_REVISION_C)) ||
(g_chip_name_id == CHIP_NAME_RESERVED9 &&
(g_chip_revision == CHIP_REVISION_B || g_chip_revision == CHIP_REVISION_C)) ||
(g_chip_name_id == CHIP_NAME_RESERVED6) ||
(g_chip_name_id == CHIP_NAME_RESERVED8));
}
static inline td_bool pwm_check_v2(td_void)
{
return (g_chip_name_id == CHIP_NAME_RESERVED5 ||
g_chip_name_id == CHIP_NAME_RESERVED2);
}
static inline td_bool pwm_check_v3(td_void)
{
return (g_chip_name_id == CHIP_NAME_RESERVED17 ||
g_chip_name_id == CHIP_NAME_RESERVED19 ||
g_chip_name_id == CHIP_NAME_HI3751V811);
}
pwm_version pwm_get_version(td_void)
{
td_s32 ret;
pwm_version version = PWM_VERSION_MAX;
pwm_func_call(ret, ext_drv_sys_get_chip_name_id(&g_chip_name_id), goto out);
pwm_func_call(ret, ext_drv_sys_get_chip_revision(&g_chip_revision), goto out);
if (pwm_check_v1()) {
version = PWM_VERSION_V1;
} else if (pwm_check_v2()) {
version = PWM_VERSION_V2;
} else if (pwm_check_v3()) {
version = PWM_VERSION_V3;
} else {
soc_log_err("Not support chip_name_id:0x%x, chip_revision:0x%x\n",
g_chip_name_id, g_chip_revision);
version = PWM_VERSION_MAX;
}
out:
return version;
}
td_s32 pwm_gpio_convert(td_u32 gpio_no, td_u16 gpio_pwm_bit_num, td_u32 *group_no, td_u32 *bit_no)
{
td_s32 ret = TD_SUCCESS;
pwm_check_param(ret, TD_FAILURE, gpio_pwm_bit_num == 0, goto out);
pwm_check_param(ret, TD_FAILURE, group_no == TD_NULL, goto out);
pwm_check_param(ret, TD_FAILURE, bit_no == TD_NULL, goto out);
*group_no = gpio_no / gpio_pwm_bit_num;
*bit_no = gpio_no % gpio_pwm_bit_num;
out:
return ret;
}
td_s32 pwm_get_attr(td_u32 freq, td_u32 period, td_u32 duty, td_u32 inv, ext_drv_pwm_attr *pwm_attr)
{
td_s32 ret = TD_SUCCESS;
pwm_check_param(ret, TD_FAILURE, pwm_attr == TD_NULL, goto out);
pwm_attr->freq = 0;
pwm_attr->duty_ratio = 0;
pwm_attr->freq = freq / (period + 1);
if (inv == 1) {
if (duty >= period) {
pwm_attr->duty_ratio = 0;
} else {
/* 1000:percentage ratio */
pwm_attr->duty_ratio = (period - duty) * 1000 / (period + 1);
}
} else {
pwm_attr->duty_ratio = (duty + 1) * 1000 / (period + 1); /* 1000 means us-->ms */
}
out:
return ret;
}
td_s32 pwm_set_attr(pwm_info *info)
{
td_s32 ret = TD_SUCCESS;
td_u32 period, pwm_cfg, pwm_ctrl, pwm_cnt;
pwm_check_param(ret, TD_FAILURE, info == TD_NULL, goto out);
pwm_check_param(ret, TD_FAILURE, info->pwm_attr == TD_NULL, goto out);
pwm_check_param(ret, TD_FAILURE, info->pwm_reg == TD_NULL, goto out);
period = info->pwm_clk_freq / info->pwm_attr->freq;
/* Decrease 1 for increment 1 by logic design */
pwm_cfg = period - 1;
if (info->pwm_attr->freq <= info->pwm_freq_critical) {
pwm_ctrl = period / 1000 * info->pwm_attr->duty_ratio; /* 1000 :ms to us */
} else {
if (period * info->pwm_attr->duty_ratio < 1000) { /* 1000: duty_ratio max */
pwm_ctrl = 0;
} else {
pwm_ctrl = period * info->pwm_attr->duty_ratio / 1000 - 1; /* 1000 :ms to us */
}
}
pwm_cfg <<= info->period_duty_offset;
pwm_ctrl <<= info->period_duty_offset;
if (info->pwm_attr->duty_ratio == 0) {
/* pwm_cfg = pwm_ctrl means pwm always high level */
pwm_ctrl = pwm_cfg | 0x3; /* 0x3 means enable pwm and signal inversion output */
}
/* pwm_cnt is only used for moto pwm */
pwm_cnt = (td_u64)((td_u64)info->pwm_attr->freq * (td_u64)info->time_us) / 1000000; /* 1000000 :us to s */
if (pwm_cnt == 0) {
pwm_cnt = 1; /* 1 : The minimum value is a period. */
soc_log_info("The current duration is shorter than the duration of a period.\n");
}
osal_writel(pwm_cfg, (td_void *)(uintptr_t)info->pwm_reg->cfg);
osal_writel(pwm_ctrl, (td_void *)(uintptr_t)info->pwm_reg->ctrl);
info->cfg_reg_value = pwm_cfg; /* for fix reserved13/reserved9 logic bug can't read the register cfg */
info->ctrl_reg_value = pwm_ctrl; /* for fix reserved13/reserved9 logic bug can't read the registe ctrl */
info->cnt_reg_value = pwm_cnt;
out:
return ret;
}
td_u32 pwm_get_bit_count(td_u32 value)
{
td_u32 result = 0;
while (value) {
value &= (value - 1);
++result;
}
return result;
}
td_s32 pwm_check_carrier_signal_duration_us(td_u32 carrier_signal_duration_us)
{
td_s32 ret;
td_u32 pwm_carrier_signal_duration_us_max = 0;
ret = osal_dts_get_u32_byname("huanglong,plat_pwm", "pwm_carrier_signal_duration_us",
&pwm_carrier_signal_duration_us_max);
if (ret == TD_SUCCESS) {
if (carrier_signal_duration_us > pwm_carrier_signal_duration_us_max) {
soc_log_err("carrier_signal_duration_us is bigger than the value read from pwm.dtsi !\n");
return TD_FAILURE;
}
} else {
if (carrier_signal_duration_us > PWM_CARRIER_SIGNAL_DURATION_US_MAX) {
soc_log_err("carrier_signal_duration_us is bigger than the default value !\n");
return TD_FAILURE;
}
}
return TD_SUCCESS;
}
td_s32 pwm_check_low_level_signal_duration_us(td_u32 low_level_signal_duration_us)
{
td_s32 ret;
td_u32 pwm_low_level_signal_duration_us_max = 0;
ret = osal_dts_get_u32_byname("huanglong,plat_pwm", "pwm_low_level_signal_duration_us",
&pwm_low_level_signal_duration_us_max);
if (ret == TD_SUCCESS) {
if (low_level_signal_duration_us > pwm_low_level_signal_duration_us_max) {
soc_log_err("low_level_signal_duration_us is bigger than the value read from pwm.dtsi !\n");
return TD_FAILURE;
}
} else {
if (low_level_signal_duration_us > PWM_LOW_LEVEL_SIGNAL_DURATION_US_MAX) {
soc_log_err("low_level_signal_duration_us is bigger than the default value !\n");
return TD_FAILURE;
}
}
return TD_SUCCESS;
}
td_s32 pwm_output_carrier_signal(td_u32 carrier_signal_duration_us)
{
ktime_t wait_time = {0};
wait_time = ns_to_ktime((td_u64)carrier_signal_duration_us * 1000); // 1000:*1000ns = 1us
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_hrtimeout(&wait_time, HRTIMER_MODE_REL);
return TD_SUCCESS;
}
td_s32 pwm_output_low_level_signal(td_u32 low_level_signal_duration_us)
{
ktime_t wait_time = {0};
wait_time = ns_to_ktime((td_u64)low_level_signal_duration_us * 1000); // 1000:*1000ns = 1us
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_hrtimeout(&wait_time, HRTIMER_MODE_REL);
return TD_SUCCESS;
}