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