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
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;
|
|
}
|