/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2020-2020. All rights reserved. * Description: sif drv * Author: Audio * Create: 2020-04-16 */ #include "drv_sif.h" #include "soc_log.h" #include "osal_ext.h" #include "soc_errno.h" #include "soc_module.h" #include "drv_sys_ext.h" #include "linux/huanglong/securec.h" #include "drv_sif_hal.h" #include "drv_ioctl_sif.h" #include "drv_sif_private.h" #include "drv_sif_hal_v4_0.h" #define SIGN_BIT 0x8000 #define REG_MAX_16BITS 0xffff #define SIF_SAMPLE_FREQ 18432 /* 18.432M */ sif_drv_ctx g_sif_drv_dev = {0}; static td_s32 g_sif_suspend_flag = 0; static td_s32 g_sif_resume_flag = 0; static osal_atomic g_sif_open_cnt = {TD_NULL}; static osal_semaphore g_sif_mutex = {TD_NULL}; /************************************************************************** addr value 0x02 0x00 set sample rate 0x09 0x05 set AAOS control and AAOS mode 0x80 0x08 set demulator mode:4.5_m_hz or 6.5_m_hz 0x00 0x00 set attributes relate to ASD:ASD atuo or system select 0x41 0x04 set mute ctl:mute override,left muted or right muted setting ***************************************************************************/ static td_s32 sif_get_carri_shift_value(td_u32 *shift_value); static td_u32 sif_get_quality1(td_void); static td_u32 sif_get_quality2(td_void); static td_s32 sif_get_out_mode(ext_sif_aaos_mode *paaos_mode); static td_s32 sif_set_over_mode(ext_sif_over_deviation over_mode); static td_s32 sif_get_over_mode(ext_sif_over_deviation *over_mode); static td_void sif_get_btsc_support(td_bool *support); static td_s32 sif_suspend(td_void); static td_s32 sif_resume(td_void); td_void sif_proc_show_help(td_void) { osal_proc_echo("=============================================sif" "================================================\n"); osal_proc_echo("echo command para path " "explanation\n"); osal_proc_echo("echo syssel DK > /proc/msp/sif " "set system select para(DK/BG/I/KOREA/BTSC/EIAJ)\n"); osal_proc_echo("echo overmode 50 > /proc/msp/sif " "set over modulation para(50k/100k/200k/384k/540k)\n"); osal_proc_echo("echo ascs 1 > /proc/msp/sif " "ascs on\n"); osal_proc_echo("echo ascs 0 > /proc/msp/sif " "ascs off\n"); osal_proc_echo("===============================================" "=================================================\n"); } static td_u8 *sys_sel_to_str(td_void) { sif_sys_sel sys_sel = sif_hal_get_det_standard(); switch (sys_sel) { case SIF_SYS_SEL_BG_FM: return "BG_FM"; case SIF_SYS_SEL_BG_NICAM: return "bg_nicam"; case SIF_SYS_SEL_L: return "secam_l"; case SIF_SYS_SEL_I: return "sys_i"; case SIF_SYS_SEL_DK1: return "dk1"; case SIF_SYS_SEL_DK2: return "dk2"; case SIF_SYS_SEL_DK3: return "dk3"; case SIF_SYS_SEL_DK_NICAM: return "nicam_dk"; case SIF_SYS_SEL_KOREA: return "korea"; case SIF_SYS_SEL_EIAJ: return "eiaj"; case SIF_SYS_SEL_BTSC: return "btsc"; default: return "sys_sel_no"; } } static td_u8 *en_asdctl45_to_str(const sif_hal_attr *pdev_attr) { switch (pdev_attr->asd45_ctl) { case SIF_ASDCTL_45M_BTSC: return "btsc"; case SIF_ASDCTL_45M_EIAJ: return "eiaj"; case SIF_ASDCTL_45M_M_KOREA: return "korea"; case SIF_ASDCTL_45M_PAL_SUM: return "pal_sum"; default: return "radio"; } } static td_u8 *en_asdctl65_to_str(const sif_hal_attr *pdev_attr) { switch (pdev_attr->asd65_ctl) { case SIF_ASDCTL_65M_SECAM_L: return "secam_l"; case SIF_ASDCTL_65M_DK: return "DK"; default: return "NONE"; } } static td_u8 *en_filter1_to_str(const sif_hal_attr *pdev_attr) { switch (pdev_attr->flt1) { case SIF_DEMOD1_FILTER_50K: return "50K"; case SIF_DEMOD1_FILTER_100K: return "100K"; case SIF_DEMOD1_FILTER_384K: return "384K"; case SIF_DEMOD1_FILTER_540K: return "540K"; case SIF_DEMOD1_FILTER_200K: return "200K"; case SIF_DEMOD1_FILTER_BUTT: default: return ""; } } static td_u8 *en_carri_status1_to_str(ext_sif_aaos_mode aaos_mode) { switch (aaos_mode) { case EXT_SIF_AAOS_MODE_MONO: return "mono"; case EXT_SIF_AAOS_MODE_STEREO: return "stereo"; case EXT_SIF_AAOS_MODE_DUAL: return "dual"; case EXT_SIF_AAOS_MODE_MONO_SAP: return "mono_sap"; case EXT_SIF_AAOS_MODE_STEREO_SAP: return "stereo_sap"; case EXT_SIF_AAOS_MODE_NICAM_MONO: return "nicam_mono"; case EXT_SIF_AAOS_MODE_NICAM_STEREO: return "nicam_stereo"; case EXT_SIF_AAOS_MODE_NICAM_DUAL: return "nicam_dual"; case EXT_SIF_AAOS_MODE_NICAM_FM_MOMO: return "nicam_fm_mono"; case EXT_SIF_AAOS_MODE_MAX: default: return ""; } } static td_u8 *deviation1_to_str(const sif_hal_attr *pdev_attr) { switch (pdev_attr->deviation1) { case SIF_DEVIATION_50K: return "50K"; case SIF_DEVIATION_100K: return "100K"; case SIF_DEVIATION_384K: return "384K"; case SIF_DEVIATION_540K: return "540K"; case SIF_DEVIATION_200K: return "200K"; case SIF_DEVIATION_BUTT: default: return ""; } } static td_u8 *en_dem_mode_to_str(sif_hal_attr *pdev_attr) { sif_hal_get_demulator_mode(&pdev_attr->demula_mode); switch (pdev_attr->demula_mode) { case SIF_DEMOD1_MODE_FM: return "fm"; case SIF_DEMOD1_MODE_AM: return "am"; case SIF_DEMOD1_MODE_BUTT: default: return ""; } } static td_u8 *en_out_to_str(sif_aaos_outmode output) { switch (output) { case SIF_AAOS_OUTMODE_MONO: return "mono"; case SIF_AAOS_OUTMODE_L_OR_R: return "LR"; case SIF_AAOS_OUTMODE_A: return "A"; case SIF_AAOS_OUTMODE_B: return "B"; case SIF_AAOS_OUTMODE_BUTT: default: return ""; } } static td_u8 *en_ascs_mode_to_str(const sif_hal_attr *pdev_attr) { switch (pdev_attr->ascs_chg_mode) { case SIF_ASCS_CHGMODE_NOT_AUTO: return "no_auto"; case SIF_ASCS_CHGMODE_AFTER_RST: return "aft_rst"; case SIF_ASCS_CHGMODE_AUTO: return "auto"; case SIF_ASCS_CHGMODE_AUTO1: return "auto1"; case SIF_ASCS_CHGMODE_BUTT: default: return ""; } } static td_u8 *en_ascs_ctl_to_str(const sif_hal_attr *pdev_attr) { switch (pdev_attr->ascs_ctl) { case SIF_ASCS_MODE_DISABLE: return "disable"; case SIF_ASCS_MODE_ONETIME: return "one_time"; case SIF_ASCS_MODE_ALWAYS: return "always"; case SIF_ASCS_MODE_ALWAYS1: return "always1"; case SIF_ASCS_MODE_BUTT: default: return ""; } } static td_u8 *en_carri1_to_str(sif_hal_attr *pdev_attr) { td_u32 carri_freq = sif_hal_get_carri1_freq(); switch (carri_freq) { case SIF_DEMOD1_45M_18432M: return "4.5M"; case SIF_DEMOD1_55M_18432M: return "5.5M"; case SIF_DEMOD1_60M_18432M: return "6.0M"; case SIF_DEMOD1_65M_18432M: return "6.5M"; default: return "no_freq"; } } static td_u8 *en_carri2_to_str(sif_hal_attr *pdev_attr) { td_u32 carri_freq = sif_hal_get_carri12_freq(); switch (carri_freq) { case SIF_DEMOD2_4_724212M_18432M: return "4.724M"; case SIF_DEMOD2_57421875M_18432M: return "5.742M"; case SIF_DEMOD2_585M_18432M: return "5.85M"; case SIF_DEMOD2_62578125M_18432M: return "6.26M"; case SIF_DEMOD2_6552M_18432M: return "6.55M"; case SIF_DEMOD2_6741875M_18432M: return "6.74M"; default: return "no_freq"; } } static const td_char *en_quality_to_str(td_u32 quality) { td_u32 i; const struct { td_u32 down_quality; td_u32 up_quality; const td_char *str; } quality_str[] = { { 0, 0x0001, "<-36dB" }, { 0x0001, 0x0004, "-36~-24dB" }, { 0x0004, 0x0010, "-24~-12dB" }, { 0x0010, 0x0040, "-12~0dB" }, { 0x0040, 0x0100, "0~12dB" }, { 0x0100, 0x0400, "12~24dB" }, { 0x0400, 0x1000, "24~36dB" }, { 0x1000, 0x4000, "36~48dB" }, { 0x4000, 0xFFFF, "48~60dB" }, }; for (i = 0; i < (sizeof(quality_str) / sizeof(quality_str[0])); i++) { if ((quality >= quality_str[i].down_quality) && (quality < quality_str[i].up_quality)) { return quality_str[i].str; } } return ">60dB"; } #define SIF_PROC_TITLE_LINE_LENGTH 72 static td_void sif_repeat_char_print(td_void *s, const td_char *t, td_u32 len) { td_u32 i; for (i = 0; i < len; i++) { if (s != TD_NULL) { osal_seq_printf(s, "%s", t); } else { osal_proc_echo("%s", t); } } } static td_void sif_proc_title_print(td_void *s, const td_char *str, td_u32 len) { td_u32 len1; td_u32 len2; len1 = (len - strlen(str)) / 2; /* 2: div 2 */ len2 = len - len1 - strlen(str); sif_repeat_char_print(s, "-", len1); osal_seq_printf(s, "%s", str); sif_repeat_char_print(s, "-", len2); osal_seq_printf(s, "\n"); } static td_void sif_proc_tail_print(td_void *s, td_u32 len) { sif_repeat_char_print(s, "=", len); osal_seq_printf(s, "\n"); } static td_void sif_proc_show_base(td_void *s, sif_hal_attr *pdev_attr) { td_s32 ret; ext_sif_aaos_mode aaos_mode = EXT_SIF_AAOS_MODE_MONO; ret = sif_get_out_mode(&aaos_mode); if (ret != TD_SUCCESS) { soc_log_err("get_out_mode is failed!\n"); return; } osal_seq_printf(s, "[sif]%s\n", VERSION_STRING); sif_proc_title_print(s, "sif", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-56s|\n", "carrier", en_carri_status1_to_str(aaos_mode)); sif_proc_title_print(s, "deviation", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-8s|", "filter1", en_filter1_to_str(pdev_attr)); osal_seq_printf(s, "%-14s:%-8s|", "deviation", deviation1_to_str(pdev_attr)); osal_seq_printf(s, "%-14s:%-8s|\n", "fm_mode", en_dem_mode_to_str(pdev_attr)); sif_proc_title_print(s, "system", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-8s|", "sys_sel", sys_sel_to_str()); osal_seq_printf(s, "%-14s:%-8s|", "asd_ctl45", en_asdctl45_to_str(pdev_attr)); osal_seq_printf(s, "%-14s:%-8s|\n", "asd_ctl65", en_asdctl65_to_str(pdev_attr)); sif_proc_title_print(s, "aaos", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-8d|", "aaos_en", pdev_attr->aaos_en); osal_seq_printf(s, "%-14s:%-8s|", "l_out", en_out_to_str(pdev_attr->l_output)); osal_seq_printf(s, "%-14s:%-8s|\n", "r_out", en_out_to_str(pdev_attr->r_output)); sif_proc_title_print(s, "ascs", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-8s|", "ascs_mode", en_ascs_mode_to_str(pdev_attr)); osal_seq_printf(s, "%-14s:%-8s|", "ascs_ctl", en_ascs_ctl_to_str(pdev_attr)); osal_seq_printf(s, "%24s\n", "|"); sif_proc_title_print(s, "mutectl", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-8d|", "mute_en", pdev_attr->mute_en); osal_seq_printf(s, "%-14s:%-8d|", "mute_l", pdev_attr->mute_l); osal_seq_printf(s, "%-14s:%-8d|\n", "mute_r", pdev_attr->mute_r); sif_proc_title_print(s, "carrier", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-8s|", "carrier1", en_carri1_to_str(pdev_attr)); osal_seq_printf(s, "%-14s:%-8s|", "carrier2", en_carri2_to_str(pdev_attr)); osal_seq_printf(s, "%24s\n", "|"); } static td_void sif_proc_show(td_void *s) { td_s32 ret; sif_hal_attr *pdev_attr = TD_NULL; td_u32 shfit_value = 0; td_u32 deviation; td_u32 negative = TD_FALSE; td_bool btsc_support = TD_FALSE; if (g_sif_drv_dev.dev_open == TD_FALSE) { sif_proc_title_print(s, "sif", SIF_PROC_TITLE_LINE_LENGTH); sif_proc_tail_print(s, SIF_PROC_TITLE_LINE_LENGTH); return; } pdev_attr = &g_sif_drv_dev.dev_attr; sif_proc_show_base(s, pdev_attr); /* quality */ ret = sif_get_carri_shift_value(&shfit_value); if (ret != TD_SUCCESS) { soc_log_err("get_carri_shift_value is failed!\n"); } deviation = sif_hal_get_phase_value(); if ((shfit_value) & SIGN_BIT) { negative = TD_TRUE; shfit_value = REG_MAX_16BITS - shfit_value; } shfit_value = shfit_value * SIF_SAMPLE_FREQ / (1 << 20); /* (shfit * fs) / 2^20 */ deviation = deviation * SIF_SAMPLE_FREQ / (1 << 20); /* (phase * FS) / 2^20 */ sif_proc_title_print(s, "nonstandard", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%c%-7d|", "shift1_khz", (negative == TD_TRUE) ? '-' : '+', shfit_value); osal_seq_printf(s, "%-14s:%-8d|", "deviation_khz", deviation); osal_seq_printf(s, "%24s\n", "|"); sif_proc_title_print(s, "quality", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-8s|", "qual1", en_quality_to_str(sif_get_quality1())); osal_seq_printf(s, "%-14s:%-8s|", "qual2", en_quality_to_str(sif_get_quality2())); osal_seq_printf(s, "%-14s:0x%-6x|\n", "qual_comp1", ((sif_get_quality1()) & (REG_MAX_16BITS)) >> 3); /* /2^3 */ osal_seq_printf(s, "%-14s:0x%-6x|", "qual_comp2", ((sif_get_quality2()) & (REG_MAX_16BITS)) >> 3); /* /2^3 */ osal_seq_printf(s, "%24s%24s\n", "|", "|"); sif_get_btsc_support(&btsc_support); sif_proc_title_print(s, "otp", SIF_PROC_TITLE_LINE_LENGTH); osal_seq_printf(s, "%-14s:%-56s|\n", "btsc", (btsc_support == TD_TRUE) ? "support" : "unsupport"); sif_proc_tail_print(s, SIF_PROC_TITLE_LINE_LENGTH); osal_proc_echo("\n"); } td_s32 sif_drv_read_proc(td_void *s, td_void *data) { td_s32 ret; ret = osal_sem_down_interruptible(&g_sif_mutex); if (ret != TD_SUCCESS) { soc_log_err("lock g_sif_mutex failed\n"); return ret; } if (s == TD_NULL) { soc_log_err("s is null\n"); osal_sem_up(&g_sif_mutex); return SOC_ERR_SIF_NULL_PTR; } sif_proc_show(s); osal_sem_up(&g_sif_mutex); return TD_SUCCESS; } td_s32 drv_sif_proc_cmd_syssel(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private) { td_s32 ret; ext_sif_standard_type sys_sel = EXT_SIF_STANDARD_DK; if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_notice("current state is not open, can not set syssel!\n"); return TD_SUCCESS; } if (argc != 2) { /* 2 is argc num. */ soc_log_err("the number of param should be 2.\n"); return TD_FAILURE; } if (argv == TD_NULL) { return TD_FAILURE; } if (!strncmp(argv[1], "DK", 2)) { /* 2 is number of characters to compare */ sys_sel = EXT_SIF_STANDARD_DK; } else if (!strncmp(argv[1], "BG", 2)) { /* 2 is number of characters to compare */ sys_sel = EXT_SIF_STANDARD_BG; } else if (!strncmp(argv[1], "I", 1)) { sys_sel = EXT_SIF_STANDARD_I; } else if (!strncmp(argv[1], "L", 1)) { sys_sel = EXT_SIF_STANDARD_L; } else if (!strncmp(argv[1], "KOREA", 5)) { /* 5 is number of characters to compare */ sys_sel = EXT_SIF_STANDARD_M_A2; } else if (!strncmp(argv[1], "BTSC", 4)) { /* 4 is number of characters to compare */ sys_sel = EXT_SIF_STANDARD_M_BTSC; } else if (!strncmp(argv[1], "EIAJ", 4)) { /* 4 is number of characters to compare */ sys_sel = EXT_SIF_STANDARD_M_EIA_J; } else { soc_log_err("the SIF sys_sel is not valid, can not set sys_sel!\n"); return TD_FAILURE; } ret = dspreg_sif_set_sys_sel(sys_sel); if (ret != TD_SUCCESS) { soc_log_err("set syssel failure!\n"); soc_err_print_err_code(ret); return ret; } return TD_SUCCESS; } td_s32 drv_sif_proc_cmd_overmode(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private) { td_s32 ret; ext_sif_over_deviation over_mode = EXT_SIF_OVER_DEVIATION_50K; if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_notice("current state is not open, can not set overmode!\n"); return TD_SUCCESS; } if (argc != 2) { /* 2 is argc num. */ soc_log_err("the number of param should be 2.\n"); return TD_FAILURE; } if (argv == TD_NULL) { return TD_FAILURE; } if (strstr(argv[1], "50k")) { over_mode = EXT_SIF_OVER_DEVIATION_50K; } else if (strstr(argv[1], "100k")) { over_mode = EXT_SIF_OVER_DEVIATION_100K; } else if (strstr(argv[1], "200k")) { over_mode = EXT_SIF_OVER_DEVIATION_200K; } else if (strstr(argv[1], "384k")) { over_mode = EXT_SIF_OVER_DEVIATION_384K; } else if (strstr(argv[1], "540k")) { over_mode = EXT_SIF_OVER_DEVIATION_540K; } else { soc_log_err("the SIF over_mode is not valid, can not set over_mode!\n"); return TD_FAILURE; } ret = sif_set_over_mode(over_mode); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(sif_set_over_mode, ret); return ret; } return TD_SUCCESS; } td_s32 drv_sif_proc_cmd_ascs(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private) { if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_notice("current state is not open, can not set ascs!\n"); return TD_SUCCESS; } if (argc != 2) { /* 2 is argc num. */ soc_log_err("the number of param should be 2.\n"); return TD_FAILURE; } if (argv == TD_NULL) { return TD_FAILURE; } if (strstr(argv[1], "1")) { g_sif_drv_dev.dev_attr.ascs_chg_mode = SIF_ASCS_CHGMODE_AUTO; g_sif_drv_dev.dev_attr.ascs_ctl = SIF_ASCS_MODE_ALWAYS; sif_hal_set_ascs_chg_mod(g_sif_drv_dev.dev_attr.ascs_chg_mode); sif_hal_set_ascs_en(g_sif_drv_dev.dev_attr.ascs_ctl); } else if (strstr(argv[1], "0")) { g_sif_drv_dev.dev_attr.ascs_chg_mode = SIF_ASCS_CHGMODE_NOT_AUTO; g_sif_drv_dev.dev_attr.ascs_ctl = SIF_ASCS_MODE_DISABLE; sif_hal_set_ascs_chg_mod(g_sif_drv_dev.dev_attr.ascs_chg_mode); sif_hal_set_ascs_en(g_sif_drv_dev.dev_attr.ascs_ctl); } else { soc_log_err("switch ascs param is valid, can not switch ascs on|off!\n"); return TD_FAILURE; } return TD_SUCCESS; } int drv_sif_proc_cmd_save_help(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private) { sif_proc_show_help(); return TD_SUCCESS; } static struct { ext_chip_name_id chip_name_id; ext_chip_revision chip_revision; } g_sif_chip_info = { .chip_name_id = 0, .chip_revision = CHIP_REVISION_MAX, }; static const sif_chip_compatible g_sif_chip_compatible[] = { {CHIP_NAME_RESERVED5}, {CHIP_NAME_RESERVED2}, {CHIP_NAME_RESERVED17}, {CHIP_NAME_RESERVED19}, {CHIP_NAME_HI3751V811}, }; td_bool sif_check_reserved5_reserved17_compatible(td_void) { td_u32 i; for (i = 0; i < (sizeof(g_sif_chip_compatible) / sizeof(g_sif_chip_compatible[0])); i++) { if (g_sif_chip_compatible[i].chip_name_id == g_sif_chip_info.chip_name_id) { return TD_TRUE; } } return TD_FALSE; } td_bool sif_check_reserved9_compatible(td_void) { #if defined(CONFIG_SOCT_TEE_SUPPORT) if (((g_sif_chip_info.chip_name_id == CHIP_NAME_RESERVED9) || (g_sif_chip_info.chip_name_id == CHIP_NAME_RESERVED8)) && ((g_sif_chip_info.chip_revision == CHIP_REVISION_B) || (g_sif_chip_info.chip_revision == CHIP_REVISION_C))) { return TD_TRUE; } #endif return TD_FALSE; } static td_s32 sif_open_dev(td_void) { td_s32 ret; ext_drv_sys_get_chip_name_id(&g_sif_chip_info.chip_name_id); ext_drv_sys_get_chip_revision(&g_sif_chip_info.chip_revision); if ((sif_check_reserved5_reserved17_compatible() == TD_FALSE) && (sif_check_reserved9_compatible() == TD_FALSE)) { soc_log_err("not support sif!\n"); return SOC_ERR_SIF_NOTSUPPORT; } ret = sif_hal_init(); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(sif_hal_init, ret); return ret; } ret = dspreg_sif_init(); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(dspreg_sif_init, ret); sif_hal_deinit(); return ret; } return ret; } static td_s32 sif_close_dev(td_void) { dspreg_sif_deinit(); sif_hal_deinit(); return TD_SUCCESS; } td_void sif_osal_init(td_void) { td_s32 ret; ret = osal_sem_init(&g_sif_mutex, 1); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(osal_sem_init, ret); } osal_atomic_init(&g_sif_open_cnt); } td_void sif_osal_deinit(td_void) { osal_atomic_destroy(&g_sif_open_cnt); osal_sem_destroy(&g_sif_mutex); } td_s32 sif_drv_open(td_void *private_data) { td_s32 ret; ret = osal_sem_down_interruptible(&g_sif_mutex); if (ret != TD_SUCCESS) { soc_log_err("lock g_sif_mutex failed\n"); return ret; } memset_s(&g_sif_drv_dev, sizeof(sif_drv_ctx), 0, sizeof(sif_drv_ctx)); if (osal_atomic_inc_return(&g_sif_open_cnt) == 1) { if (sif_open_dev() != TD_SUCCESS) { soc_log_fatal("sif_open_dev err!\n"); osal_atomic_dec(&g_sif_open_cnt); osal_sem_up(&g_sif_mutex); return SOC_ERR_SIF_DEV_OPENED; } soc_sif_asd_init(&g_sif_drv_dev.asd_drvier); g_sif_drv_dev.asd_drvier.asd_thread = osal_kthread_create(asd_thread_work, &g_sif_drv_dev.asd_drvier, "asd_thread", 0); if (g_sif_drv_dev.asd_drvier.asd_thread == TD_NULL) { soc_log_err("creat asd_thread_work failed\n"); osal_sem_up(&g_sif_mutex); return SOC_ERR_SIF_NULL_PTR; } if (sif_check_reserved9_compatible() == TD_TRUE) { if (sif_work_init() != TD_SUCCESS) { soc_log_err("call sif_work_init failed!\n"); osal_sem_up(&g_sif_mutex); return SOC_ERR_SIF_INVALID_PARA; } } } g_sif_drv_dev.dev_open = TD_FALSE; osal_sem_up(&g_sif_mutex); return TD_SUCCESS; } td_s32 sif_drv_close(td_void *private_data) { td_s32 ret; ret = osal_sem_down_interruptible(&g_sif_mutex); if (ret != TD_SUCCESS) { soc_log_err("lock g_sif_mutex failed\n"); return ret; } if ((osal_atomic_read(&g_sif_open_cnt) != 0) && osal_atomic_dec_and_test(&g_sif_open_cnt)) { if (sif_check_reserved9_compatible() == TD_TRUE) { sif_work_deinit(); } if (sif_close_dev() != TD_SUCCESS) { soc_log_fatal("sif_close_dev err!\n"); osal_sem_up(&g_sif_mutex); return SOC_ERR_SIF_DEV_CLOSED; } osal_kthread_destroy(g_sif_drv_dev.asd_drvier.asd_thread, 1); } g_sif_drv_dev.dev_open = TD_FALSE; osal_sem_up(&g_sif_mutex); return TD_SUCCESS; } static td_s32 sif_drv_suspend(td_void *private_data) { td_s32 ret; ret = osal_sem_down_interruptible(&g_sif_mutex); if (ret != TD_SUCCESS) { soc_log_err("lock g_sif_mutex failed\n"); return ret; } if (osal_atomic_read(&g_sif_open_cnt) != 0) { ret = sif_suspend(); if (ret != TD_SUCCESS) { soc_log_fatal("SIF suspend fail\n"); osal_sem_up(&g_sif_mutex); return SOC_ERR_SIF_DEVICE_BUSY; } } osal_sem_up(&g_sif_mutex); return TD_SUCCESS; } td_s32 sif_pm_suspend(td_void *private_data) { td_s32 ret; ret = sif_drv_suspend(private_data); if (ret == TD_SUCCESS) { soc_print("SIF suspend OK\n"); } return ret; } td_s32 sif_pm_lowpower_enter(td_void *private_data) { td_s32 ret; ret = sif_drv_suspend(private_data); if (ret == TD_SUCCESS) { soc_print("SIF lowpower enter OK\n"); } return ret; } static td_s32 sif_drv_resume(td_void *private_data) { td_s32 ret; ret = osal_sem_down_interruptible(&g_sif_mutex); if (ret != TD_SUCCESS) { soc_log_err("lock g_sif_mutex failed\n"); return ret; } if (osal_atomic_read(&g_sif_open_cnt) != 0) { ret = sif_resume(); if (ret != TD_SUCCESS) { soc_log_fatal("SIF resume fail\n"); osal_sem_up(&g_sif_mutex); return SOC_ERR_SIF_DEVICE_BUSY; } } osal_sem_up(&g_sif_mutex); return TD_SUCCESS; } td_s32 sif_pm_resume(td_void *private_data) { td_s32 ret; ret = sif_drv_resume(private_data); if (ret == TD_SUCCESS) { soc_print("SIF resume OK\n"); } return ret; } td_s32 sif_pm_lowpower_exit(td_void *private_data) { td_s32 ret; ret = sif_drv_resume(private_data); if (ret == TD_SUCCESS) { soc_print("SIF lowpower exit OK\n"); } return ret; } static td_s32 sif_check_dev_status(td_void) { if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not get syssel!\n"); return SOC_ERR_SIF_NOT_OPEN; } if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not start, can not get syssel!\n"); return SOC_ERR_SIF_NOT_START; } return TD_SUCCESS; } static td_void sif_get_sys_sel_val(sif_sys_sel sys_sel, ext_sif_standard_type *psys_sel) { switch (sys_sel) { case SIF_SYS_SEL_BG_FM: *psys_sel = EXT_SIF_STANDARD_BG_A2; break; case SIF_SYS_SEL_BG_NICAM: *psys_sel = EXT_SIF_STANDARD_BG_NICAM; break; case SIF_SYS_SEL_I: *psys_sel = EXT_SIF_STANDARD_I; break; case SIF_SYS_SEL_DK1: *psys_sel = EXT_SIF_STANDARD_DK1_A2; break; case SIF_SYS_SEL_DK2: *psys_sel = EXT_SIF_STANDARD_DK2_A2; break; case SIF_SYS_SEL_DK3: *psys_sel = EXT_SIF_STANDARD_DK3_A2; break; case SIF_SYS_SEL_DK_NICAM: *psys_sel = EXT_SIF_STANDARD_DK_NICAM; break; case SIF_SYS_SEL_L: *psys_sel = EXT_SIF_STANDARD_L; break; case SIF_SYS_SEL_BTSC: *psys_sel = EXT_SIF_STANDARD_M_BTSC; break; case SIF_SYS_SEL_KOREA: *psys_sel = EXT_SIF_STANDARD_M_A2; break; case SIF_SYS_SEL_EIAJ: *psys_sel = EXT_SIF_STANDARD_M_EIA_J; break; case SIF_SYS_SEL_FM_RADIO_EUROPE: case SIF_SYS_SEL_FM_RADIO_US: case SIF_SYS_SEL_FM_RADIO_EUROPE1: case SIF_SYS_SEL_FM_RADIO_EUROPE2: *psys_sel = EXT_SIF_STANDARD_NOTSTANDARD; break; case SIF_SYS_SEL_FM_RADIO_EUROPE3: *psys_sel = EXT_SIF_STANDARD_UNKNOW; /* try to decode nostandard signal */ break; default: *psys_sel = EXT_SIF_STANDARD_UNKNOW; break; } } static td_void sif_get_need_ascs_detect_status(td_bool *need_ascs_detect) { if ((g_sif_drv_dev.dev_attr.sys_sel >= SIF_SYS_SEL_BG_FM) && (g_sif_drv_dev.dev_attr.sys_sel <= SIF_SYS_SEL_BG_NICAM)) { *need_ascs_detect = TD_TRUE; } if ((g_sif_drv_dev.dev_attr.sys_sel >= SIF_SYS_SEL_DK1) && (g_sif_drv_dev.dev_attr.sys_sel <= SIF_SYS_SEL_DK_NICAM)) { *need_ascs_detect = TD_TRUE; } if ((g_sif_drv_dev.aaos_mode != EXT_SIF_AAOS_MODE_MONO) && (g_sif_drv_dev.aaos_mode != EXT_SIF_AAOS_MODE_NICAM_MONO)) { *need_ascs_detect = TD_FALSE; } } static td_s32 sif_get_sys_sel(ext_sif_standard_type *psys_sel) { td_s32 ret; sif_sys_sel sys_sel = SIF_SYS_SEL_BUTT; td_bool need_ascs_detect = TD_FALSE; static td_u32 wait_ascs_cnt = 0; sif_sys_sel ascs_sys_sel = SIF_SYS_SEL_BUTT; td_bool get_sys_sel_from_ascs = TD_FALSE; soc_dbg_func_enter(); if (psys_sel == TD_NULL) { soc_log_err("psys_sel is null!\n"); return SOC_ERR_SIF_NULL_PTR; } ret = sif_check_dev_status(); if (ret != TD_SUCCESS) { return ret; } sif_get_need_ascs_detect_status(&need_ascs_detect); if (need_ascs_detect == TD_TRUE) { osal_msleep(5); /* 5 is sleep time. */ wait_ascs_cnt++; if (wait_ascs_cnt > 40) { /* 40 is a threshold */ wait_ascs_cnt = 0; sif_hal_set_ascs_en(SIF_ASCS_MODE_ONETIME); osal_msleep(20); /* 20 is sleep time. */ } ascs_sys_sel = (sif_sys_sel)sif_hal_get_ascs_result(); if ((ascs_sys_sel != SIF_SYS_SEL_FM_RADIO_EUROPE3) && (g_sif_drv_dev.dev_attr.sys_sel != ascs_sys_sel)) { get_sys_sel_from_ascs = TD_TRUE; } } if (get_sys_sel_from_ascs == TD_TRUE) { soc_log_info("ASCS result: syssel\n"); soc_info_print_s32(ascs_sys_sel); sys_sel = ascs_sys_sel; } else { sys_sel = sif_hal_get_det_standard(); } sif_get_sys_sel_val(sys_sel, psys_sel); g_sif_drv_dev.dev_attr.sys_sel = sys_sel; g_sif_drv_dev.sif_stand = *psys_sel; soc_dbg_func_exit(); return TD_SUCCESS; } static td_void sif_get_btsc_support(td_bool *support) { sif_hal_get_btsc_support(support); } static td_void sif_btsc_get_out_mode(ext_sif_aaos_mode *pen_mode) { td_bool stereo; td_bool sap; stereo = sif_hal_is_stereo(); sap = sif_hal_is_bi_sap(); if (sap == TD_TRUE) { *pen_mode = stereo ? EXT_SIF_AAOS_MODE_STEREO_SAP : EXT_SIF_AAOS_MODE_MONO_SAP; } else { *pen_mode = stereo ? EXT_SIF_AAOS_MODE_STEREO : EXT_SIF_AAOS_MODE_MONO; } } static td_void sif_a2_get_out_mode(ext_sif_aaos_mode *pen_mode) { td_bool det_out_mode; sif_audmode_det aud_mode; *pen_mode = EXT_SIF_AAOS_MODE_MONO; det_out_mode = sif_hal_is_sec_car_exist(); if (det_out_mode == TD_FALSE) { return; } aud_mode = sif_hal_get_aud_mod_det(); switch (aud_mode) { case SIF_AUDMODE_MONO: *pen_mode = EXT_SIF_AAOS_MODE_MONO; break; case SIF_AUDMODE_STEREO: if (sif_hal_is_stereo() != TD_TRUE) { break; } *pen_mode = EXT_SIF_AAOS_MODE_STEREO; break; case SIF_AUDMODE_BILIGUAL: if (sif_hal_is_bi_sap() != TD_TRUE) { break; } *pen_mode = EXT_SIF_AAOS_MODE_DUAL; break; default: *pen_mode = EXT_SIF_AAOS_MODE_MONO; break; } } static td_void sif_nicam_get_out_mode(ext_sif_aaos_mode *pen_mode) { sif_nicam_ctrl nicam_ctl; sif_anadig_status ana_mode; ana_mode = sif_hal_get_ana_dig_status(); if (ana_mode != SIF_ANADIG_STATUS_DIG) { return; } nicam_ctl = sif_hal_get_nicam_ctrl(); switch (nicam_ctl) { case SIF_NICAM_CTRL_STEREO: *pen_mode = EXT_SIF_AAOS_MODE_NICAM_STEREO; break; case SIF_NICAM_CTRL_MONODATA: *pen_mode = EXT_SIF_AAOS_MODE_NICAM_MONO; break; case SIF_NICAM_CTRL_DUALMONO: *pen_mode = EXT_SIF_AAOS_MODE_NICAM_DUAL; break; default: break; } } static td_void sif_eiaj_get_out_mode(ext_sif_aaos_mode *pen_mode) { td_bool det_out_mode; sif_audmode_det aud_mode; det_out_mode = sif_hal_is_prm_car_exist(); if (det_out_mode == TD_FALSE) { return; } aud_mode = sif_hal_get_aud_mod_det(); switch (aud_mode) { case SIF_AUDMODE_MONO: *pen_mode = EXT_SIF_AAOS_MODE_MONO; break; case SIF_AUDMODE_BILIGUAL: *pen_mode = EXT_SIF_AAOS_MODE_DUAL; break; case SIF_AUDMODE_STEREO: *pen_mode = EXT_SIF_AAOS_MODE_STEREO; break; default: *pen_mode = EXT_SIF_AAOS_MODE_MONO; break; } } static td_s32 sif_get_out_mode(ext_sif_aaos_mode *paaos_mode) { td_s32 ret; ext_sif_aaos_mode mode = EXT_SIF_AAOS_MODE_MONO; ext_sif_standard_type sys_sel = EXT_SIF_STANDARD_UNKNOW; soc_dbg_func_enter(); ret = sif_check_dev_status(); if (ret != TD_SUCCESS) { return ret; } ret = sif_get_sys_sel(&sys_sel); if (ret != TD_SUCCESS) { soc_log_err("get_sys_sel is failed!\n"); } switch (g_sif_drv_dev.dev_attr.sys_sel) { case SIF_SYS_SEL_BTSC: sif_btsc_get_out_mode(&mode); break; case SIF_SYS_SEL_BG_FM: case SIF_SYS_SEL_DK1: case SIF_SYS_SEL_DK2: case SIF_SYS_SEL_DK3: case SIF_SYS_SEL_KOREA: /* FM-korea */ sif_a2_get_out_mode(&mode); break; case SIF_SYS_SEL_L: case SIF_SYS_SEL_BG_NICAM: case SIF_SYS_SEL_DK_NICAM: case SIF_SYS_SEL_I: sif_nicam_get_out_mode(&mode); break; case SIF_SYS_SEL_EIAJ: sif_eiaj_get_out_mode(&mode); break; case SIF_SYS_SEL_FM_RADIO_US: case SIF_SYS_SEL_FM_RADIO_EUROPE1: case SIF_SYS_SEL_FM_RADIO_EUROPE2: case SIF_SYS_SEL_FM_RADIO_EUROPE3: mode = EXT_SIF_AAOS_MODE_MONO; break; default: mode = EXT_SIF_AAOS_MODE_MONO; break; } g_sif_drv_dev.aaos_mode = mode; *paaos_mode = mode; soc_dbg_func_exit(); return TD_SUCCESS; } static inline td_void sif_get_aaos_nicam_forced_mono(td_void) { if (g_sif_drv_dev.dev_attr.sys_sel == SIF_SYS_SEL_BTSC) { g_sif_drv_dev.dev_attr.btsc_sap = TD_FALSE; sif_hal_set_btsc_sap(SIF_SIGSEL_BTSC_STEREO); } g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_MONO; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_MONO; g_sif_drv_dev.dev_attr.aaos_en = TD_FALSE; } static inline td_void sif_get_aaos_nicam_stereo(td_void) { if (g_sif_drv_dev.dev_attr.sys_sel == SIF_SYS_SEL_BTSC) { g_sif_drv_dev.dev_attr.btsc_sap = TD_FALSE; sif_hal_set_btsc_sap(SIF_SIGSEL_BTSC_STEREO); } g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_L_OR_R; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_L_OR_R; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; } static inline td_void sif_get_aaos_nicam_dual_b(td_void) { if (g_sif_drv_dev.dev_attr.sys_sel == SIF_SYS_SEL_BTSC) { g_sif_drv_dev.dev_attr.btsc_sap = TD_TRUE; sif_hal_set_btsc_sap(SIF_SIGSEL_BTSC_SAP); } g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_B; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_B; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; } static inline td_void sif_get_aaos_btsc_sap(td_void) { if (g_sif_drv_dev.dev_attr.sys_sel == SIF_SYS_SEL_BTSC) { g_sif_drv_dev.dev_attr.btsc_sap = TD_TRUE; sif_hal_set_btsc_sap(SIF_SIGSEL_BTSC_SAP); } g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_B; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_B; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; } static inline td_void sif_get_aaos_nicam_dual_ab(td_void) { if (g_sif_drv_dev.dev_attr.sys_sel == SIF_SYS_SEL_BTSC) { g_sif_drv_dev.dev_attr.btsc_sap = TD_TRUE; sif_hal_set_btsc_sap(SIF_SIGSEL_BTSC_SAP); } g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_A; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_B; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; } static inline td_void sif_get_aaos_btsc_stereo(td_void) { g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_L_OR_R; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_L_OR_R; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; } static td_void sif_get_aaos_by_outmode(ext_sif_out_mode out_mode) { switch (out_mode) { case EXT_SIF_OUT_MODE_MONO: case EXT_SIF_OUT_MODE_NICAM_MONO: g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_MONO; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_MONO; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; break; case EXT_SIF_OUT_MODE_BTSC_MONO: g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_MONO; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_MONO; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; break; case EXT_SIF_OUT_MODE_NICAM_FORCED_MONO: sif_get_aaos_nicam_forced_mono(); break; case EXT_SIF_OUT_MODE_STEREO: case EXT_SIF_OUT_MODE_NICAM_STEREO: sif_get_aaos_nicam_stereo(); break; case EXT_SIF_OUT_MODE_BTSC_STEREO: sif_get_aaos_btsc_stereo(); break; case EXT_SIF_OUT_MODE_DUAL_A: case EXT_SIF_OUT_MODE_NICAM_DUAL_A: g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_A; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_A; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; break; case EXT_SIF_OUT_MODE_DUAL_B: case EXT_SIF_OUT_MODE_NICAM_DUAL_B: sif_get_aaos_nicam_dual_b(); break; case EXT_SIF_OUT_MODE_BTSC_SAP: sif_get_aaos_btsc_sap(); break; case EXT_SIF_OUT_MODE_DUAL_AB: case EXT_SIF_OUT_MODE_NICAM_DUAL_AB: sif_get_aaos_nicam_dual_ab(); break; default: soc_log_warn("set invalid out mode:\n"); soc_warn_print_u32(out_mode); g_sif_drv_dev.dev_attr.l_output = SIF_AAOS_OUTMODE_L_OR_R; g_sif_drv_dev.dev_attr.r_output = SIF_AAOS_OUTMODE_L_OR_R; g_sif_drv_dev.dev_attr.aaos_en = TD_TRUE; break; } } static td_s32 sif_set_out_mode(ext_sif_out_mode out_mode) { td_s32 ret; ext_sif_standard_type sys_sel_type = EXT_SIF_STANDARD_UNKNOW; soc_dbg_func_enter(); ret = sif_get_sys_sel(&sys_sel_type); if (ret != TD_SUCCESS) { soc_log_err("get_sys_sel is failed!\n"); } ret = sif_check_dev_status(); if (ret != TD_SUCCESS) { return ret; } sif_get_aaos_by_outmode(out_mode); sif_hal_set_aaos_lf_sel(g_sif_drv_dev.dev_attr.l_output); sif_hal_set_aaos_rt_sel(g_sif_drv_dev.dev_attr.r_output); sif_hal_aaos_en(g_sif_drv_dev.dev_attr.aaos_en); soc_dbg_func_exit(); return TD_SUCCESS; } static td_s32 sif_set_carri_shift(td_u32 carri_shift) { soc_info_func_enter(); if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not set carrier shift!\n"); return SOC_ERR_SIF_NOT_OPEN; } if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not start, can not set carrier shift!\n"); return SOC_ERR_SIF_NOT_START; } g_sif_drv_dev.dev_attr.crri_freq1 = carri_shift; sif_hal_set_demod_carri_freq1(g_sif_drv_dev.dev_attr.crri_freq1); soc_info_func_exit(); return TD_SUCCESS; } /* the order of value is wrong on logic, should exchange here */ static ext_sif_over_deviation g_real_over_mode[EXT_SIF_OVER_DEVIATION_MAX] = { EXT_SIF_OVER_DEVIATION_50K, EXT_SIF_OVER_DEVIATION_100K, EXT_SIF_OVER_DEVIATION_540K, EXT_SIF_OVER_DEVIATION_200K, EXT_SIF_OVER_DEVIATION_384K, }; static td_s32 sif_set_over_mode(ext_sif_over_deviation over_mode) { soc_info_func_enter(); if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not set over mode!\n"); return SOC_ERR_SIF_NOT_OPEN; } if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not start, can not set over mode!\n"); return SOC_ERR_SIF_NOT_START; } if (over_mode >= EXT_SIF_OVER_DEVIATION_MAX) { soc_log_err("invalid over mode param error: \n"); soc_err_print_u32(over_mode); return SOC_ERR_SIF_INVALID_PARA; } if ((g_sif_drv_dev.dev_attr.sys_sel == SIF_SYS_SEL_BTSC) || (g_sif_drv_dev.dev_attr.sys_sel == SIF_SYS_SEL_EIAJ) || (g_sif_drv_dev.dev_attr.sys_sel == SIF_SYS_SEL_KOREA)) { g_sif_drv_dev.dev_attr.flt1 = SIF_DEMOD1_FILTER_100K; g_sif_drv_dev.dev_attr.deviation1 = SIF_DEVIATION_100K; } else { g_sif_drv_dev.dev_attr.flt1 = (sif_filter1)g_real_over_mode[over_mode]; g_sif_drv_dev.dev_attr.deviation1 = (sif_deviation1)g_real_over_mode[over_mode]; } sif_hal_set_filter1(g_sif_drv_dev.dev_attr.flt1); sif_hal_set_deviation1(g_sif_drv_dev.dev_attr.deviation1); sif_hal_set_deviation2(g_sif_drv_dev.dev_attr.deviation1); soc_info_func_exit(); return TD_SUCCESS; } /* the order of value is wrong on logic, should exchange here */ static sif_deviation1 g_real_deviation1[SIF_DEVIATION_BUTT] = { EXT_SIF_OVER_DEVIATION_50K, EXT_SIF_OVER_DEVIATION_100K, EXT_SIF_OVER_DEVIATION_384K, EXT_SIF_OVER_DEVIATION_540K, EXT_SIF_OVER_DEVIATION_200K, }; static td_s32 sif_get_over_mode(ext_sif_over_deviation *pover_mode) { sif_deviation1 deviation1 = SIF_DEVIATION_BUTT; soc_info_func_enter(); if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not start ASD detect!\n"); return SOC_ERR_SIF_NOT_OPEN; } if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not stop, can not set attr!\n"); return SOC_ERR_SIF_NOT_START; } sif_hal_get_deviation1(&deviation1); *pover_mode = (ext_sif_over_deviation)g_real_deviation1[deviation1]; soc_info_func_exit(); return TD_SUCCESS; } static td_s32 sif_set_auto_mute(td_bool auto_mute) { if (auto_mute == TD_FALSE) { sif_hal_set_mute_right(TD_FALSE); sif_hal_set_mute_left(TD_FALSE); } sif_hal_set_mute_auto(auto_mute); return TD_SUCCESS; } static td_s32 sif_set_freq_error(ext_sif_freq_err_threshold freq_err) { sif_freq_err_threshold hal_freq_err = SIF_FREQ_ERR_THRESHOLD_27K; switch (freq_err) { case EXT_SIF_FREQ_ERR_THRESHOLD_10K: hal_freq_err = SIF_FREQ_ERR_THRESHOLD_10K; break; case EXT_SIF_FREQ_ERR_THRESHOLD_20K: hal_freq_err = SIF_FREQ_ERR_THRESHOLD_20K; break; case EXT_SIF_FREQ_ERR_THRESHOLD_27K: hal_freq_err = SIF_FREQ_ERR_THRESHOLD_27K; break; case EXT_SIF_FREQ_ERR_THRESHOLD_30K: hal_freq_err = SIF_FREQ_ERR_THRESHOLD_30K; break; case EXT_SIF_FREQ_ERR_THRESHOLD_40K: hal_freq_err = SIF_FREQ_ERR_THRESHOLD_40K; break; case EXT_SIF_FREQ_ERR_THRESHOLD_50K: hal_freq_err = SIF_FREQ_ERR_THRESHOLD_50K; break; default: hal_freq_err = SIF_FREQ_ERR_THRESHOLD_27K; break; } sif_hal_set_freq_err(hal_freq_err); return TD_SUCCESS; } static td_s32 sif_set_attr(ext_sif_attr attr) { td_s32 ret; if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not set attr!\n"); return SOC_ERR_SIF_NOT_OPEN; } if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_STOP) { soc_log_err("current state is not stop, can not set attr!\n"); return SOC_ERR_SIF_NOT_STOP; } ret = memcpy_s(&g_sif_drv_dev.attr, sizeof(ext_sif_attr), &attr, sizeof(attr)); if (ret != TD_SUCCESS) { soc_log_err("memcpy_s failed"); return ret; } ret = sif_set_freq_error(g_sif_drv_dev.attr.freq_threshold); if (ret != TD_SUCCESS) { soc_log_err("sif_set_freq_error is failed!\n"); } ret = sif_set_auto_mute(g_sif_drv_dev.attr.auto_mute); if (ret != TD_SUCCESS) { soc_log_err("sif_set_auto_mute is failed!\n"); } return TD_SUCCESS; } static td_s32 sif_get_attr(ext_sif_attr *attr) { td_s32 ret; if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not get attr!\n"); return SOC_ERR_SIF_NOT_OPEN; } if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not start, can not get attr!\n"); return SOC_ERR_SIF_NOT_START; } ret = memcpy_s(attr, sizeof(ext_sif_attr), &g_sif_drv_dev.attr, sizeof(g_sif_drv_dev.attr)); if (ret != TD_SUCCESS) { soc_log_err("memcpy_s failed"); return ret; } return TD_SUCCESS; } static td_s32 sif_open(td_void) { soc_info_func_enter(); g_sif_drv_dev.curn_status = SIF_CHANNEL_STATUS_STOP; g_sif_drv_dev.dev_open = TD_TRUE; soc_info_func_exit(); return TD_SUCCESS; } static td_s32 sif_close(td_void) { soc_info_func_enter(); /* 复位即ok */ if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_STOP) { soc_log_err("current state is not stop, can not close sif!\n"); return SOC_ERR_SIF_NOT_STOP; } g_sif_drv_dev.dev_open = TD_FALSE; soc_info_func_exit(); return TD_SUCCESS; } static td_s32 sif_start(td_void) { soc_info_func_enter(); if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not start sif!\n"); return SOC_ERR_SIF_NOT_OPEN; } g_sif_drv_dev.dev_attr.ascs_chg_mode = SIF_ASCS_CHGMODE_AFTER_RST; g_sif_drv_dev.dev_attr.ascs_ctl = SIF_ASCS_MODE_DISABLE; sif_hal_set_ascs_chg_mod(g_sif_drv_dev.dev_attr.ascs_chg_mode); sif_hal_set_ascs_en(g_sif_drv_dev.dev_attr.ascs_ctl); g_sif_drv_dev.curn_status = SIF_CHANNEL_STATUS_START; soc_info_func_exit(); return TD_SUCCESS; } static td_s32 sif_stop(td_void) { soc_info_func_enter(); if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not stop sif!\n"); return SOC_ERR_SIF_NOT_OPEN; } g_sif_drv_dev.curn_status = SIF_CHANNEL_STATUS_STOP; soc_info_func_exit(); return TD_SUCCESS; } static td_u32 sif_get_quality1(td_void) { if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not start, can not get quality1!\n"); return SOC_ERR_SIF_NOT_START; } return sif_hal_get_quality1(); } static td_u32 sif_get_quality2(td_void) { if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not start, can not get quality2!\n"); return SOC_ERR_SIF_NOT_START; } return sif_hal_get_quality2(); } static td_s32 sif_get_carri_shift_value(td_u32 *shift_value) { if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not start, can not get carrier shift value!\n"); return SOC_ERR_SIF_NOT_START; } *shift_value = sif_hal_get_carrier_shift_value(); g_sif_drv_dev.dev_attr.carri_shift_value = *shift_value; return TD_SUCCESS; } static td_s32 sif_suspend(td_void) { td_s32 ret; ext_sif_standard_type sys_sel = EXT_SIF_STANDARD_UNKNOW; if (!g_sif_suspend_flag) { g_sif_suspend_flag = 1; } /* 7. sap状态 */ /* 仅在设置输出时设置,默认为解stereo,没有改变就无需设置 */ /* 6. auto mute */ /* 设置属性中已经保存该值 */ /* 5. 输出选择,从寄存器中获取状态 */ g_sif_drv_dev.dev_attr.l_output = sif_hal_get_aaos_lf_sel(); g_sif_drv_dev.dev_attr.r_output = sif_hal_get_aaos_rt_sel(); g_sif_drv_dev.dev_attr.aaos_en = sif_hal_get_aaos_en(); /* 4. 制式 */ ret = sif_get_sys_sel(&sys_sel); if (ret != TD_SUCCESS) { soc_log_err("get_sys_sel is failed!\n"); } dspreg_sif_deinit(); g_sif_resume_flag = 0; return TD_SUCCESS; } static td_s32 sif_resume(td_void) { if (!g_sif_resume_flag) { dspreg_sif_init(); /* 3. 阈值 */ sif_set_freq_error(g_sif_drv_dev.attr.freq_threshold); /* 4. 制式 */ dspreg_sif_set_sys_sel(g_sif_drv_dev.sif_stand); /* 5. 设置自动载波跟随 */ sif_hal_set_ascs_chg_mod(g_sif_drv_dev.dev_attr.ascs_chg_mode); sif_hal_set_ascs_en(g_sif_drv_dev.dev_attr.ascs_ctl); /* 6. 输出选择 */ sif_hal_set_aaos_lf_sel(g_sif_drv_dev.dev_attr.l_output); sif_hal_set_aaos_rt_sel(g_sif_drv_dev.dev_attr.r_output); sif_hal_aaos_en(g_sif_drv_dev.dev_attr.aaos_en); /* 7. auto mute */ sif_set_auto_mute(g_sif_drv_dev.dev_attr.auto_mute); /* 8. sap状态 */ if (g_sif_drv_dev.dev_attr.btsc_sap == TD_TRUE) { sif_hal_set_btsc_sap(SIF_SIGSEL_BTSC_SAP); } g_sif_resume_flag = 1; } g_sif_suspend_flag = 0; return TD_SUCCESS; } static td_void sif_reset(td_void) { td_s32 ret; /* 保存原来的输出模式 */ g_sif_drv_dev.dev_attr.l_output = sif_hal_get_aaos_lf_sel(); g_sif_drv_dev.dev_attr.r_output = sif_hal_get_aaos_rt_sel(); g_sif_drv_dev.dev_attr.aaos_en = sif_hal_get_aaos_en(); osal_msleep(2); /* 2 is time for sleep */ /* 恢复 阈值 */ ret = sif_set_freq_error(g_sif_drv_dev.attr.freq_threshold); if (ret != TD_SUCCESS) { soc_log_err("sif_set_freq_error is failed!\n"); } /* 恢复自动载波跟随 */ sif_hal_set_ascs_chg_mod(g_sif_drv_dev.dev_attr.ascs_chg_mode); sif_hal_set_ascs_en(g_sif_drv_dev.dev_attr.ascs_ctl); /* 输出选择 */ sif_hal_set_aaos_lf_sel(g_sif_drv_dev.dev_attr.l_output); sif_hal_set_aaos_rt_sel(g_sif_drv_dev.dev_attr.r_output); sif_hal_aaos_en(g_sif_drv_dev.dev_attr.aaos_en); /* 恢复自动mute */ ret = sif_set_auto_mute(g_sif_drv_dev.dev_attr.auto_mute); if (ret != TD_SUCCESS) { soc_log_err("sif_set_auto_mute is failed!\n"); } /* 恢复sap */ if (g_sif_drv_dev.dev_attr.btsc_sap == TD_TRUE) { sif_hal_set_btsc_sap(SIF_SIGSEL_BTSC_SAP); } return; } static int sif_drv_ioctl_standard_type(unsigned int cmd, td_void *arg) { td_s32 ret = TD_FAILURE; sif_standard_type_param *sys_sel = (sif_standard_type_param *)arg; switch (cmd) { case CMD_SIF_SET_STANDDARD: sif_reset(); ret = dspreg_sif_set_sys_sel(sys_sel->stand); break; case CMD_SIF_GET_ASD_RESULT: ret = dspreg_sif_get_asd_result(&sys_sel->stand); break; case CMD_SIF_GET_STANDARD: ret = sif_get_sys_sel(&sys_sel->stand); break; default: soc_log_err("invalid parameter!\n"); break; } return ret; } static int sif_drv_ioctl_over_deviation(unsigned int cmd, td_void *arg) { td_s32 ret = TD_FAILURE; sif_over_deviation_param *over_mod = (sif_over_deviation_param *)arg; switch (cmd) { case CMD_SIF_SET_OVER_DEV: ret = sif_set_over_mode(over_mod->over_mode); break; case CMD_SIF_GET_OVER_DEV: ret = sif_get_over_mode(&over_mod->over_mode); break; default: soc_log_err("invalid parameter!\n"); break; } return ret; } static const struct { sif_sys_sel sys_sel; ext_sif_standard_type standard_type; } g_sif_sys_to_standard[] = { {SIF_SYS_SEL_BG_FM, EXT_SIF_STANDARD_BG_A2}, {SIF_SYS_SEL_BG_NICAM, EXT_SIF_STANDARD_BG_NICAM}, {SIF_SYS_SEL_I, EXT_SIF_STANDARD_I}, {SIF_SYS_SEL_DK1, EXT_SIF_STANDARD_DK1_A2}, {SIF_SYS_SEL_DK2, EXT_SIF_STANDARD_DK2_A2}, {SIF_SYS_SEL_DK3, EXT_SIF_STANDARD_DK3_A2}, {SIF_SYS_SEL_DK_NICAM, EXT_SIF_STANDARD_DK_NICAM}, {SIF_SYS_SEL_L, EXT_SIF_STANDARD_L}, {SIF_SYS_SEL_BTSC, EXT_SIF_STANDARD_M_BTSC}, {SIF_SYS_SEL_KOREA, EXT_SIF_STANDARD_M_A2}, {SIF_SYS_SEL_EIAJ, EXT_SIF_STANDARD_M_EIA_J}, {SIF_SYS_SEL_FM_RADIO_EUROPE, EXT_SIF_STANDARD_NOTSTANDARD}, {SIF_SYS_SEL_FM_RADIO_US, EXT_SIF_STANDARD_NOTSTANDARD}, {SIF_SYS_SEL_FM_RADIO_EUROPE1, EXT_SIF_STANDARD_NOTSTANDARD}, {SIF_SYS_SEL_FM_RADIO_EUROPE2, EXT_SIF_STANDARD_NOTSTANDARD}, {SIF_SYS_SEL_FM_RADIO_EUROPE3, EXT_SIF_STANDARD_UNKNOW}, }; static const struct { ext_sif_standard_type standard_type; sif_sys_sel sys_sel; } g_sif_standard_to_sys[] = { {EXT_SIF_STANDARD_BG, SIF_SYS_SEL_BG_FM}, {EXT_SIF_STANDARD_BG_A2, SIF_SYS_SEL_BG_FM}, {EXT_SIF_STANDARD_BG_NICAM, SIF_SYS_SEL_BG_NICAM}, {EXT_SIF_STANDARD_I, SIF_SYS_SEL_I}, {EXT_SIF_STANDARD_DK, SIF_SYS_SEL_DK3}, {EXT_SIF_STANDARD_DK3_A2, SIF_SYS_SEL_DK3}, {EXT_SIF_STANDARD_DK1_A2, SIF_SYS_SEL_DK1}, {EXT_SIF_STANDARD_DK2_A2, SIF_SYS_SEL_DK2}, {EXT_SIF_STANDARD_DK_NICAM, SIF_SYS_SEL_DK_NICAM}, {EXT_SIF_STANDARD_M, SIF_SYS_SEL_KOREA}, {EXT_SIF_STANDARD_M_A2, SIF_SYS_SEL_KOREA}, {EXT_SIF_STANDARD_M_BTSC, SIF_SYS_SEL_BTSC}, {EXT_SIF_STANDARD_M_EIA_J, SIF_SYS_SEL_EIAJ}, {EXT_SIF_STANDARD_L, SIF_SYS_SEL_L}, }; static td_s32 sif_get_standard_try(ext_sif_carrier_attr *attr) { td_s32 i; td_s32 ret; soc_dbg_func_enter(); if (g_sif_drv_dev.dev_open == TD_FALSE) { soc_log_err("current state is not open, can not try standard!\n"); return SOC_ERR_SIF_NOT_OPEN; } if (g_sif_drv_dev.curn_status != SIF_CHANNEL_STATUS_START) { soc_log_err("current state is not start, can not try standard!\n"); return SOC_ERR_SIF_NOT_START; } ret = sif_hal_get_standard_try((sif_hal_carrier_attr *)attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(sif_hal_get_standard_try, ret); return ret; } for (i = 0; i < sizeof(g_sif_sys_to_standard) / sizeof(g_sif_sys_to_standard[0]); i++) { if (attr->standard_type == (ext_sif_standard_type)g_sif_sys_to_standard[i].sys_sel) { attr->standard_type = g_sif_sys_to_standard[i].standard_type; break; } } if (i == sizeof(g_sif_sys_to_standard) / sizeof(g_sif_sys_to_standard[0])) { attr->standard_type = EXT_SIF_STANDARD_UNKNOW; } soc_dbg_func_exit(); return TD_SUCCESS; } static td_u32 sif_set_standard_try_priority(ext_sif_standard_priority_list *priority_list) { td_u32 i; td_u32 j; td_s32 ret; td_u32 list_len = priority_list->list_len; if (list_len > EXT_SIF_STANDARD_MAX) { soc_log_err("standardtry list length is too big!\n"); return SOC_ERR_SIF_INVALID_PARA; } for (i = 0; i < list_len; i++) { for (j = 0; j < sizeof(g_sif_standard_to_sys) / sizeof(g_sif_standard_to_sys[0]); j++) { if (priority_list->priority_list[i] == g_sif_standard_to_sys[j].standard_type) { priority_list->priority_list[i] = (ext_sif_standard_type)g_sif_standard_to_sys[j].sys_sel; break; } } if (j == sizeof(g_sif_standard_to_sys) / sizeof(g_sif_standard_to_sys[0])) { priority_list->priority_list[i] = (ext_sif_standard_type)SIF_SYS_SEL_FM_RADIO_EUROPE3; } } ret = sif_hal_set_standard_try_priority((sif_hal_syssel_priority_list *)priority_list); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(sif_set_standard_try_priority, ret); return ret; } return TD_SUCCESS; } static int sif_drv_ioctl_try_standard(td_void *arg) { sif_carrier_attr_param *attr = (sif_carrier_attr_param *)arg; return sif_get_standard_try(&(attr->carrier_attr)); } static int sif_drv_ioctl_standard_list(const td_void *arg) { sif_standard_list_param *standard_list_param = (sif_standard_list_param *)arg; return sif_set_standard_try_priority(&(standard_list_param->priority_list)); } static int sif_drv_ioctl_start_asd(const td_void *arg) { sif_sysctl_param *sys_ctl = (sif_sysctl_param *)arg; hal_set_core_reset(TD_TRUE); hal_set_core_reset(TD_FALSE); return dspreg_sif_start_asd_detect(sys_ctl->sys_ctl); } static int sif_drv_ioctl_asd_cmpl(td_void *arg) { sif_asd_complete_param *asd_cmpl = (sif_asd_complete_param *)arg; return dspreg_sif_get_asd_complete(&asd_cmpl->asd_complete); } int sif_drv_ioctl_inner_ext(unsigned int cmd, td_void *arg, td_void *private_data) { td_s32 ret; sif_attr_param *attr = TD_NULL; soc_dbg_func_enter(); if (arg == TD_NULL) { soc_log_err("arg is null!\n"); return SOC_ERR_SIF_NULL_PTR; } attr = (sif_attr_param *)arg; ret = osal_sem_down_interruptible(&g_sif_mutex); if (ret != TD_SUCCESS) { soc_log_fatal("lock g_sif_mutex failed\n"); return ret; } switch (cmd) { case CMD_SIF_SET_ATTR: ret = sif_set_attr(attr->sif_attr); break; case CMD_SIF_GET_ATTR: ret = sif_get_attr(&attr->sif_attr); break; case CMD_SIF_OPEN: { /* fall-through */ ret = sif_open(); break; } case CMD_SIF_CLOSE: ret = sif_close(); break; case CMD_SIF_SET_START: ret = sif_start(); break; case CMD_SIF_SET_STOP: ret = sif_stop(); break; case CMD_SIF_TRY_STANDARD: ret = sif_drv_ioctl_try_standard(arg); break; case CMD_SIF_SET_STANDARD_LIST: ret = sif_drv_ioctl_standard_list(arg); break; default: soc_log_err("INVALID IOCTL CMD: %#x\n", cmd); ret = SOC_ERR_SIF_INVALID_PARA; break; } osal_sem_up(&g_sif_mutex); soc_dbg_func_exit(); return ret; } static td_s32 sif_drv_ioctl_outmode(unsigned int cmd, td_void *arg) { switch (cmd) { case CMD_SIF_SET_OUTMODE: { sif_out_mode_param *out_mode = (sif_out_mode_param *)arg; return sif_set_out_mode(out_mode->out_mode); } case CMD_SIF_GET_OUTMODE: { sif_aaos_mode_param *aaos_mode = (sif_aaos_mode_param *)arg; return sif_get_out_mode(&aaos_mode->aaos_mode); } default: soc_log_err("invalid parameter!\n"); return SOC_ERR_SIF_INVALID_PARA; } } int sif_drv_ioctl_inner(unsigned int cmd, td_void *arg, td_void *private_data) { td_s32 ret; sif_carri_shift_param *carri_shift = (sif_carri_shift_param *)arg; soc_dbg_func_enter(); if (arg == TD_NULL) { soc_log_err("arg is null!\n"); return SOC_ERR_SIF_NULL_PTR; } ret = osal_sem_down_interruptible(&g_sif_mutex); if (ret != TD_SUCCESS) { soc_log_fatal("lock g_sif_mutex failed\n"); return ret; } switch (cmd) { case CMD_SIF_START_ASD: ret = sif_drv_ioctl_start_asd(arg); break; case CMD_SIF_SET_STANDDARD: case CMD_SIF_GET_ASD_RESULT: case CMD_SIF_GET_STANDARD: ret = sif_drv_ioctl_standard_type(cmd, arg); break; case CMD_SIF_SET_OVER_DEV: case CMD_SIF_GET_OVER_DEV: ret = sif_drv_ioctl_over_deviation(cmd, arg); break; case CMD_SIF_SET_CARRI_SHIFT: ret = sif_set_carri_shift(carri_shift->carri_shift); break; case CMD_SIF_SET_OUTMODE: case CMD_SIF_GET_OUTMODE: /* fall-through */ ret = sif_drv_ioctl_outmode(cmd, arg); break; case CMD_SIF_GET_ASD_CMPL: ret = sif_drv_ioctl_asd_cmpl(arg); break; default: soc_log_err("ERR IOCTL CMD: %#x\n", cmd); ret = SOC_ERR_SIF_INVALID_PARA; break; } osal_sem_up(&g_sif_mutex); soc_dbg_func_exit(); return ret; } sif_drv_ctx* get_sif_drv_dev(void) { return &g_sif_drv_dev; }