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.
936 lines
30 KiB
936 lines
30 KiB
/*
|
|
* 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 <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/time.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <net/if.h>
|
|
#include <securec.h>
|
|
|
|
#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;
|
|
}
|
|
|