/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2021. All rights reserved. * Description: pmoc api code */ #define LOG_MODULE_ID SOC_ID_PM #define LOG_UNF_TRACE 0 #define LOG_FUNC_TRACE 0 #include "mpi_pmoc_ext.h" #include #include #include #include #include #include #include #include #include #include #include "soc_log.h" #include "soc_errno.h" #include "mpi_ir_ext.h" #include "api_pmoc_usb_wakeup.h" /* socket ioctl */ #define SIOCDEVPRIVATE 0x89F0 /* to 89FF, copy from include/linux/sockios.h */ #define SIOCSETPM (SIOCDEVPRIVATE + 4) /* set pmt wake up config */ #define SIOCGETPM (SIOCDEVPRIVATE + 7) /* get pmt wake up config */ #define PMOC_MAX_COUNT 100 #define BUFFER_ARRAY_SIZE 8 #define NUMBER_TEN 10 #define SOC_DEV_PM_NAME "soc_pm" #define ONE_BYTE_BITS 8 #define TWO_BYTE_BITS 16 #define check_param_return(val, err_code_print, err_code_ret) do { \ if (val) { \ soc_err_print_err_code(err_code_print); \ return err_code_ret; \ } \ } while (0) static td_s32 g_pmoc_dev_fd = -1; static td_s32 g_net_dev_fd = -1; static td_u32 g_pmoc_init_count = 0; typedef struct { td_char eth_index; /* bit0--eth0 bit1--eth1 */ td_char unicast_pkts_enable; td_char magic_pkts_enable; td_char wakeup_pkts_enable; struct { td_u32 mask_bytes; td_u8 offset; /* >= 12 */ td_u8 value[EXT_PMOC_FILTER_VALUE_COUNT]; /* byte string */ td_char valid; /* valid filter */ } filter[EXT_PMOC_FILTER_COUNT]; } pmoc_ifr_config; typedef struct { td_u32 eth_index; /* 0: eth0, 1: eth1 */ td_bool unicast_packet_enable; td_bool magic_packet_enable; td_bool wakeup_frame_enable; ext_pmoc_wakeup_frame frame[EXT_PMOC_FILTER_COUNT]; td_u32 time_to_passive_standby; td_bool mute_wakeup_enable; } ext_pmoc_eth_work; typedef union { td_u32 val32; td_u8 val8[4]; /* 4: array size */ } u32_data; td_s32 ext_mpi_pmoc_init(td_void) { soc_dbg_func_enter(); g_pmoc_init_count++; if (g_pmoc_dev_fd < 0) { g_pmoc_dev_fd = open("/dev/" SOC_DEV_PM_NAME, O_RDWR, 0); if (g_pmoc_dev_fd < 0) { soc_err_print_call_fun_err(open, SOC_ERR_PMOC_FAILED_INIT); return SOC_ERR_PMOC_FAILED_INIT; } } if (g_net_dev_fd < 0) { g_net_dev_fd = socket(AF_INET, SOCK_DGRAM, 0); if (g_net_dev_fd < 0) { soc_warn_print_call_fun_err(socket, TD_FAILURE); } } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_deinit(td_void) { td_s32 ret; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); g_pmoc_init_count--; /* clean wake up param */ ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_CLEAN_WAKEUP_PARAM); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return TD_FAILURE; } if (g_pmoc_init_count == 0) { ret = close(g_pmoc_dev_fd); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(close, ret); return TD_FAILURE; } g_pmoc_dev_fd = -1; if (g_net_dev_fd >= 0) { close(g_net_dev_fd); g_net_dev_fd = -1; } } soc_dbg_func_exit(); return TD_SUCCESS; } static td_s32 set_eth_wakeup_config(ext_pmoc_eth_work *eth_wakeup_attr) { td_s32 ret; td_u32 i; td_u8 filter_number; pmoc_ifr_config config = {0}; struct ifreq ifr; td_char buffer[BUFFER_ARRAY_SIZE] = {0}; soc_dbg_func_enter(); if (memset_s((void *)&ifr, sizeof(struct ifreq), 0, sizeof(struct ifreq)) != EOK) { soc_err_print_call_fun_err(memset_s, TD_FAILURE); return TD_FAILURE; } ret = sprintf_s(buffer, sizeof(buffer), "%s%u", "eth", eth_wakeup_attr->eth_index); if (ret <= 0) { soc_err_print_call_fun_err(sprintf_s, ret); return TD_FAILURE; } ret = strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), buffer, sizeof(ifr.ifr_name) - 1); if (ret != EOK) { soc_err_print_call_fun_err(strncpy_s, ret); return ret; } config.eth_index = (td_char)(eth_wakeup_attr->eth_index); config.unicast_pkts_enable = eth_wakeup_attr->unicast_packet_enable; config.magic_pkts_enable = eth_wakeup_attr->magic_packet_enable; config.wakeup_pkts_enable = eth_wakeup_attr->wakeup_frame_enable; if (config.wakeup_pkts_enable == TD_TRUE) { for (filter_number = 0; filter_number < EXT_PMOC_FILTER_COUNT; filter_number++) { config.filter[filter_number].valid = eth_wakeup_attr->frame[filter_number].filter_valid; if (eth_wakeup_attr->frame[filter_number].offset < EXT_PMOC_FILTER_MIN_OFFSET) { soc_warn_print_info(" Filter Offset less than 12, force it to be 12 \n"); config.filter[filter_number].offset = EXT_PMOC_FILTER_MIN_OFFSET; } else { config.filter[filter_number].offset = eth_wakeup_attr->frame[filter_number].offset; } config.filter[filter_number].mask_bytes = eth_wakeup_attr->frame[filter_number].mask_bytes; for (i = 0; i < EXT_PMOC_FILTER_VALUE_COUNT; i++) { config.filter[filter_number].value[i] = eth_wakeup_attr->frame[filter_number].value[i]; } } } ifr.ifr_data = (caddr_t)&config; ret = ioctl(g_net_dev_fd, SIOCSETPM, &ifr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); /* don't return error status */ } soc_dbg_func_exit(); return TD_SUCCESS; } static td_s32 get_eth_wakeup_config(ext_pmoc_eth_work *eth_wakeup_attr) { td_s32 ret; td_u32 i; td_u8 filter_number; pmoc_ifr_config config = {0}; struct ifreq ifr; td_char buffer[BUFFER_ARRAY_SIZE] = {0}; soc_dbg_func_enter(); if (memset_s(&ifr, sizeof(struct ifreq), 0, sizeof(struct ifreq)) != EOK) { soc_err_print_call_fun_err(memset_s, TD_FAILURE); return TD_FAILURE; } ret = sprintf_s(buffer, sizeof(buffer), "%s%u", "eth", eth_wakeup_attr->eth_index); if (ret <= 0) { soc_err_print_call_fun_err(sprintf_s, ret); return TD_FAILURE; } ret = strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), buffer, sizeof(ifr.ifr_name) - 1); if (ret != EOK) { soc_err_print_call_fun_err(strncpy_s, ret); return ret; } ifr.ifr_data = (caddr_t)&config; ret = ioctl(g_net_dev_fd, SIOCGETPM, &ifr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return ret; } eth_wakeup_attr->eth_index = config.eth_index; eth_wakeup_attr->unicast_packet_enable = config.unicast_pkts_enable; eth_wakeup_attr->magic_packet_enable = config.magic_pkts_enable; eth_wakeup_attr->wakeup_frame_enable = config.wakeup_pkts_enable; if (config.wakeup_pkts_enable == TD_TRUE) { for (filter_number = 0; filter_number < EXT_PMOC_FILTER_COUNT; filter_number++) { eth_wakeup_attr->frame[filter_number].filter_valid = config.filter[filter_number].valid; eth_wakeup_attr->frame[filter_number].offset = config.filter[filter_number].offset; eth_wakeup_attr->frame[filter_number].mask_bytes = config.filter[filter_number].mask_bytes; for (i = 0; i < EXT_PMOC_FILTER_VALUE_COUNT; i++) { eth_wakeup_attr->frame[filter_number].value[i] = config.filter[filter_number].value[i]; } } } soc_dbg_func_exit(); return TD_SUCCESS; } static td_s32 pmoc_check_ir_config(const pmoc_cmd_suspend_attr *attr) { check_param_return(attr->param.ir_param.ir_type >= EXT_MPI_IR_CODE_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(attr->param.ir_param.ir_num == 0, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(attr->param.ir_param.ir_num > EXT_PMOC_WAKEUP_IRKEY_MAXNUM, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); return TD_SUCCESS; } static td_s32 pmoc_check_gpio_config(const pmoc_cmd_suspend_attr *attr) { td_u8 i; check_param_return(attr->param.gpio_param.num == 0, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(attr->param.gpio_param.num > EXT_PMOC_WAKEUP_GPIO_MAXNUM, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); for (i = 0; i < attr->param.gpio_param.num; i++) { check_param_return(attr->param.gpio_param.bit[i] < EXT_PMOC_GPIO_BIT_MIN, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(attr->param.gpio_param.bit[i] > EXT_PMOC_GPIO_BIT_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(attr->param.gpio_param.interrupt_type[i] >= EXT_GPIO_INTTYPE_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); } return TD_SUCCESS; } static td_s32 pmoc_get_usb_mask(td_bool enable, td_u32 *mask) { td_s32 ret; td_u32 int_mask = 0; if (enable) { ret = get_remotewakeup_devnum(&int_mask); if (ret == TD_FAILURE) { soc_err_print_call_fun_err(get_remotewakeup_devnum, ret); return SOC_ERR_PMOC_FAILED_SETWAKEUPVAL; } soc_info_print_s32(ret); soc_info_print_u32(int_mask); ret = set_remotewakeup(); if (ret == TD_FAILURE) { soc_err_print_call_fun_err(set_remotewakeup, ret); return SOC_ERR_PMOC_FAILED_SETWAKEUPVAL; } *mask = int_mask; } else { *mask = 0; } return TD_SUCCESS; } static td_s32 pmoc_eth_config_check(pmoc_cmd_suspend_attr *attr) { td_s32 ret; ext_pmoc_eth_work eth_work = {0}; if (attr->param.eth_param.unicast_packet_enable || attr->param.eth_param.magic_packet_enable || attr->param.eth_param.wakeup_frame_enable) { ret = memcpy_s(ð_work, sizeof(ext_pmoc_eth_work), &attr->param.eth_param, sizeof(attr->param.eth_param)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } ret = set_eth_wakeup_config(ð_work); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(set_eth_wakeup_config, ret); return ret; } ret = get_eth_wakeup_config(ð_work); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(get_eth_wakeup_config, ret); return ret; } attr->param.eth_param.unicast_packet_enable = eth_work.unicast_packet_enable; attr->param.eth_param.magic_packet_enable = eth_work.magic_packet_enable; attr->param.eth_param.wakeup_frame_enable = eth_work.wakeup_frame_enable; } return TD_SUCCESS; } static td_s32 pmoc_check_hdmitx_cec_config(const pmoc_cmd_suspend_attr *attr) { td_u8 i; for (i = 0; i < EXT_PMOC_HDMITX_ID_MAXNUM; i++) { if (attr->param.hdmitx_cec_param.id[i]) { check_param_return(attr->param.hdmitx_cec_param.cec_control[i] >= EXT_PMOC_CEC_CONTROL_TYPE_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); return TD_SUCCESS; } } soc_err_print_info("There is no valid hdmitx cec id \n"); return TD_FAILURE; } static td_s32 pmoc_check_config(pmoc_cmd_suspend_attr *attr) { td_s32 ret; td_u32 usb_wakeup_mask; if ((attr->source == EXT_PMOC_WAKEUP_TYPE_IR) && (attr->enable)) { ret = pmoc_check_ir_config(attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pmoc_check_ir_config, ret); return ret; } } else if ((attr->source == EXT_PMOC_WAKEUP_TYPE_KEYLED) && (attr->enable)) { check_param_return(attr->param.keyled_param.keyled_type >= EXT_KEYLED_TYPE_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); } else if ((attr->source == EXT_PMOC_WAKEUP_TYPE_GPIO) && (attr->enable)) { ret = pmoc_check_gpio_config(attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pmoc_check_gpio_config, ret); return ret; } } else if ((attr->source == EXT_PMOC_WAKEUP_TYPE_ETH) && (attr->enable)) { ret = pmoc_eth_config_check(attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pmoc_eth_config_check, ret); return ret; } if (attr->param.eth_param.unicast_packet_enable || attr->param.eth_param.magic_packet_enable || attr->param.eth_param.wakeup_frame_enable) { attr->enable = TD_TRUE; } else { attr->enable = TD_FALSE; } } else if (attr->source == EXT_PMOC_WAKEUP_TYPE_USB) { ret = pmoc_get_usb_mask(attr->enable, &usb_wakeup_mask); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pmoc_get_usb_mask, ret); return ret; } attr->param.usb_param.usb_wakeup_mask = usb_wakeup_mask; attr->enable = (usb_wakeup_mask != 0) ? TD_TRUE : TD_FALSE; } else if ((attr->source == EXT_PMOC_WAKEUP_TYPE_HDMITX_CEC) && (attr->enable)) { ret = pmoc_check_hdmitx_cec_config(attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pmoc_check_hdmitx_cec_config, ret); return ret; } } return TD_SUCCESS; } td_s32 ext_mpi_pmoc_set_suspend_param(ext_pmoc_wakeup_src source, td_bool enable, ext_pmoc_suspend_param *param) { td_s32 ret; pmoc_cmd_suspend_attr attr = {0}; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(source >= EXT_PMOC_WAKEUP_TYPE_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); if ((source == EXT_PMOC_WAKEUP_TYPE_IR || source == EXT_PMOC_WAKEUP_TYPE_KEYLED || source == EXT_PMOC_WAKEUP_TYPE_GPIO || source == EXT_PMOC_WAKEUP_TYPE_LSADC || source == EXT_PMOC_WAKEUP_TYPE_UART || source == EXT_PMOC_WAKEUP_TYPE_ETH || source == EXT_PMOC_WAKEUP_TYPE_HDMIRX_PLUGIN || source == EXT_PMOC_WAKEUP_TYPE_HDMITX_CEC || source == EXT_PMOC_WAKEUP_TYPE_TIMEOUT) && (enable)) { check_param_return(param == TD_NULL, SOC_ERR_PMOC_INVALID_POINT, SOC_ERR_PMOC_INVALID_POINT); ret = memcpy_s(&attr.param, sizeof(ext_pmoc_suspend_param), param, sizeof(ext_pmoc_suspend_param)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } } attr.source = source; attr.enable = enable; ret = pmoc_check_config(&attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(pmoc_check_config, ret); return ret; } ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_SET_SUSPEND_ATTR, &attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_SETWAKEUPVAL; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_get_suspend_param(ext_pmoc_wakeup_src source, td_bool *enable, ext_pmoc_suspend_param *param) { td_s32 ret; td_u32 time_to_passive_standby; td_bool mute_wakeup_enable = 0; pmoc_cmd_suspend_attr attr = {0}; ext_pmoc_eth_work eth_work = {0}; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(source >= EXT_PMOC_WAKEUP_TYPE_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(enable == TD_NULL, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); attr.source = source; ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_GET_SUSPEND_ATTR, &attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_GETWAKEUPVAL; } *enable = attr.enable; if (source == EXT_PMOC_WAKEUP_TYPE_IR || source == EXT_PMOC_WAKEUP_TYPE_KEYLED || source == EXT_PMOC_WAKEUP_TYPE_GPIO || source == EXT_PMOC_WAKEUP_TYPE_LSADC || source == EXT_PMOC_WAKEUP_TYPE_UART || source == EXT_PMOC_WAKEUP_TYPE_ETH || source == EXT_PMOC_WAKEUP_TYPE_HDMIRX_PLUGIN || source == EXT_PMOC_WAKEUP_TYPE_HDMITX_CEC || source == EXT_PMOC_WAKEUP_TYPE_TIMEOUT) { check_param_return(param == TD_NULL, SOC_ERR_PMOC_INVALID_POINT, SOC_ERR_PMOC_INVALID_POINT); ret = memcpy_s(param, sizeof(ext_pmoc_suspend_param), &attr.param, sizeof(ext_pmoc_suspend_param)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } } /* get net_wakeup params from eth driver */ if (source == EXT_PMOC_WAKEUP_TYPE_ETH) { time_to_passive_standby = attr.param.eth_param.time_to_passive_standby; mute_wakeup_enable = attr.param.eth_param.mute_wakeup_enable; ret = get_eth_wakeup_config(ð_work); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(get_eth_wakeup_config, ret); return ret; } ret = memcpy_s(¶m->eth_param, sizeof(param->eth_param), ð_work, sizeof(ext_pmoc_eth_work)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } param->eth_param.time_to_passive_standby = time_to_passive_standby; param->eth_param.mute_wakeup_enable = mute_wakeup_enable; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_set_wakeup_type(ext_pmoc_wakeup_type wakeup_type) { td_s32 ret; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(wakeup_type >= EXT_PMOC_WAKEUP_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_SET_WAKEUP_TYPE, &wakeup_type); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return TD_FAILURE; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_enter_standby(ext_pmoc_wakeup_src *wakeup_src) { td_s32 ret; td_u32 cnt; ext_pmoc_wakeup_attr wakeup_attr = {0}; FILE *fp = TD_NULL_PTR; struct timeval tv = { 0, 0 }; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); /* handle things before entering standby, for example: close dvfs */ ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_STANDBY_READY); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_STANDBY; } /* standby and then wait for wake up */ fp = fopen("/sys/power/state", "r+"); if (fp == NULL) { soc_err_print_call_fun_err(fopen, NULL); return SOC_ERR_PMOC_FAILED_STANDBY; } (void)fputs("mem", fp); (void)fclose(fp); tv.tv_sec = 0; tv.tv_usec = 100000; /* 100000 usec */ select(0, NULL, NULL, NULL, &tv); /* wake up */ cnt = 0; wakeup_attr.source = EXT_PMOC_WAKEUP_TYPE_MAX; while (cnt < PMOC_MAX_COUNT) { cnt++; ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_GET_WAKEUP_ATTR, &wakeup_attr); if ((ret != TD_SUCCESS) || (wakeup_attr.source >= EXT_PMOC_WAKEUP_TYPE_MAX)) { tv.tv_sec = 0; tv.tv_usec = 10000; /* 10000 usec */ select(0, NULL, NULL, NULL, &tv); continue; } break; } if (cnt >= PMOC_MAX_COUNT) { soc_err_print_info(" fail to get wake up mode after resume \n"); return SOC_ERR_PMOC_FAILED_STANDBY; } soc_info_print_s32(wakeup_attr.source); if (wakeup_src != TD_NULL) { *wakeup_src = wakeup_attr.source; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_get_wakeup_attr(ext_pmoc_wakeup_attr *attr) { td_s32 ret; ext_pmoc_wakeup_attr wakeup_attr = {0}; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(attr == TD_NULL, SOC_ERR_PMOC_INVALID_POINT, SOC_ERR_PMOC_INVALID_POINT); ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_GET_WAKEUP_ATTR, &wakeup_attr); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_GETWAKEUPMODE; } attr->source = wakeup_attr.source; if (wakeup_attr.source == EXT_PMOC_WAKEUP_TYPE_IR || wakeup_attr.source == EXT_PMOC_WAKEUP_TYPE_GPIO || wakeup_attr.source == EXT_PMOC_WAKEUP_TYPE_LSADC) { ret = memcpy_s(attr, sizeof(ext_pmoc_wakeup_attr), &wakeup_attr, sizeof(ext_pmoc_wakeup_attr)); if (ret != EOK) { soc_err_print_call_fun_err(memcpy_s, ret); return ret; } } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_get_standby_period(td_u32 *standby_period) { td_s32 ret; td_u32 period = 0; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(standby_period == TD_NULL, SOC_ERR_PMOC_INVALID_POINT, SOC_ERR_PMOC_INVALID_POINT); ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_GET_STANDBY_PERIOD, &period); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_GETPERIOD; } *standby_period = period; soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_enter_active_standby(ext_pmoc_active_standby_modle model) { td_s32 ret; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_ENTER_ACTIVE_STANDBY, &model); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return TD_FAILURE; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_quit_active_standby(td_void) { td_s32 ret; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_QUIT_ACTIVE_STANDBY); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return TD_FAILURE; } soc_dbg_func_exit(); return TD_SUCCESS; } static td_u32 parse_display_value(td_u32 src) { td_u32 tmp0, tmp1; td_u32 dst = 0; tmp0 = src; tmp1 = tmp0 % NUMBER_TEN; dst |= tmp1 & 0xff; tmp0 = tmp0 / NUMBER_TEN; tmp1 = tmp0 % NUMBER_TEN; dst |= ((tmp1 & 0xff) << 8); /* left shift 8 */ tmp0 = tmp0 / NUMBER_TEN; tmp1 = tmp0 % NUMBER_TEN; dst |= ((tmp1 & 0xff) << 16); /* left shift 16 */ tmp0 = tmp0 / NUMBER_TEN; tmp1 = tmp0 % NUMBER_TEN; dst |= ((tmp1 & 0xff) << 24); /* left shift 24 */ return dst; } td_s32 ext_mpi_pmoc_set_standby_display_param(ext_pmoc_display_param *display_param) { td_s32 ret; ext_pmoc_display_param disp_info = {0}; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(display_param == TD_NULL, SOC_ERR_PMOC_INVALID_POINT, SOC_ERR_PMOC_INVALID_POINT); check_param_return(display_param->keyled_type >= EXT_KEYLED_TYPE_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(display_param->display_type >= EXT_PMOC_DISPLAY_TYPE_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); disp_info.keyled_type = display_param->keyled_type; disp_info.display_type = display_param->display_type; if (display_param->display_type == EXT_PMOC_DISPLAY_TIME) { if ((display_param->display_time_info.hour > EXT_PMOC_DISPLAY_MAX_HOUR) || (display_param->display_time_info.minute > EXT_PMOC_DISPLAY_MAX_MINUTE) || (display_param->display_time_info.second > EXT_PMOC_DISPLAY_MAX_SECOND)) { soc_err_print_info("time parameter is illegal \n"); return SOC_ERR_PMOC_INVALID_PARA; } disp_info.display_value = (((display_param->display_time_info.hour & 0xff) << TWO_BYTE_BITS) | ((display_param->display_time_info.minute & 0xff) << ONE_BYTE_BITS) | ((display_param->display_time_info.second & 0xff))); } else if (display_param->display_type == EXT_PMOC_DISPLAY_DIGIT) { if (display_param->display_value > EXT_PMOC_DISPLAY_MAX_DIGIT) { soc_err_print_info("chan num is illegal \n"); return SOC_ERR_PMOC_INVALID_PARA; } disp_info.display_value = parse_display_value(display_param->display_value); } else { disp_info.display_value = 0; } ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_SET_DISPLAY_PARAM, (&disp_info)); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_STANDBY; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_set_gpio_power_off(ext_pmoc_poweroff_gpio_param *param) { td_s32 ret; td_u32 i; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(param == TD_NULL, SOC_ERR_PMOC_INVALID_POINT, SOC_ERR_PMOC_INVALID_POINT); check_param_return(param->num == 0, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(param->num > EXT_PMOC_POWEROFF_GPIO_MAXNUM, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); for (i = 0; i < param->num; i++) { check_param_return(param->bit[i] < EXT_PMOC_GPIO_BIT_MIN, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(param->bit[i] > EXT_PMOC_GPIO_BIT_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return((param->level[i] > 1), SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); } ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_SET_GPIO_POWEROFF, param); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_SETDEV; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_set_breath_led(td_u8 group, td_u8 bit, td_u32 led_breath_cycle) { td_s32 ret; ext_pmoc_breath_led_param param = {0}; soc_dbg_func_enter(); check_param_return(bit < EXT_PMOC_GPIO_BIT_MIN, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(bit > EXT_PMOC_GPIO_BIT_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); param.group = group; param.bit = bit; param.led_breath_cycle = led_breath_cycle; ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_SET_BREATH_LED, ¶m); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_SETDEV; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_set_standby_led(td_u8 group, td_u8 bit, td_u8 level) { td_s32 ret; u32_data tmp; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(bit < EXT_PMOC_GPIO_BIT_MIN, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(bit > EXT_PMOC_GPIO_BIT_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return((level != 0) && (level != 1), SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); tmp.val32 = 0; tmp.val8[0] = group; tmp.val8[1] = bit; tmp.val8[2] = level; /* 2: array offset */ ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_SET_STANDBY_LED, &tmp.val32); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_SETDEV; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_set_mcu_msg(td_u32 msg_index, td_u32 value) { td_s32 ret; ext_pmoc_mcu_message message = {0}; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(msg_index >= EXT_PMOC_CUSTOM_REG_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); message.index = msg_index; message.value = value; ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_SET_MCU_MSG, &message); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_SETDEV; } soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_get_mcu_msg(td_u32 msg_index, td_u32 *value) { td_s32 ret; ext_pmoc_mcu_message message = {0}; soc_dbg_func_enter(); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); check_param_return(msg_index >= EXT_PMOC_CUSTOM_REG_MAX, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); check_param_return(value == TD_NULL, SOC_ERR_PMOC_INVALID_PARA, SOC_ERR_PMOC_INVALID_PARA); message.index = msg_index; ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_GET_MCU_MSG, &message); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_SETDEV; } *value = message.value; soc_dbg_func_exit(); return TD_SUCCESS; } td_s32 ext_mpi_pmoc_get_chip_temperature(ext_mpi_pmoc_chip_temperature *chip_temprature) { td_s32 ret; td_s32 temprature; soc_dbg_func_enter(); check_param_return(chip_temprature == TD_NULL, SOC_ERR_PMOC_INVALID_POINT, SOC_ERR_PMOC_INVALID_POINT); check_param_return(g_pmoc_dev_fd < 0, SOC_ERR_PMOC_NOT_INIT, SOC_ERR_PMOC_NOT_INIT); ret = ioctl(g_pmoc_dev_fd, CMD_PMOC_GET_CHIP_TEMPERATURE, &temprature); if (ret != TD_SUCCESS) { soc_err_print_call_fun_err(ioctl, ret); return SOC_ERR_PMOC_FAILED_GETTEMPERATURE; } chip_temprature->t_sensor1_temperature = temprature; chip_temprature->t_sensor2_temperature = 0; chip_temprature->t_sensor3_temperature = 0; chip_temprature->t_sensor4_temperature = 0; soc_dbg_func_exit(); return TD_SUCCESS; }