android13/external/wifi_driver/rtl8852be/phl/phl_led.c

1034 lines
28 KiB
C

/******************************************************************************
*
* Copyright(c) 2019 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*****************************************************************************/
#define _PHL_LED_C_
#include "phl_headers.h"
#define PHL_LED_INTERVALS_ARR_LEN_MAX 4
struct phl_led_event_args_t {
enum rtw_led_state state_condition;
struct rtw_led_action_args_t *action_args_arr;
u8 action_args_arr_len;
u32 toggle_delay_unit;
struct phl_led_event_args_t *next;
};
struct phl_led_timer_args_t {
struct phl_info_t *phl_info;
_os_timer timer;
u32 delay_unit;
bool timer_alive;
bool is_avail;
u32 led_manage_mask;
};
struct phl_led_info_t {
enum rtw_led_ctrl_mode ctrl_mode;
enum rtw_led_ctrl_mode reg_ctrl_mode;
enum rtw_led_opt curr_opt;
const struct rtw_led_toggle_args_t *toggle_args;
struct phl_led_timer_args_t *toggle_timer_args;
u32 toggle_interval_counter;
u32 toggle_start_delay_counter;
bool toggle_start_delay_over;
u32 toggle_loop_counter;
u8 toggle_curr_interval_idx;
};
struct phl_led_ctrl_t {
struct phl_led_info_t led_info_arr[RTW_LED_ID_LENGTH];
struct phl_led_event_args_t *event_args_list_arr[RTW_LED_EVENT_LENGTH];
struct rtw_led_intervals_t intervals_arr[PHL_LED_INTERVALS_ARR_LEN_MAX];
enum rtw_led_state state;
struct phl_led_timer_args_t *toggle_timer_args[RTW_LED_TIMER_LENGTH];
};
static void _phl_led_timer_release(struct phl_led_timer_args_t *timer_args)
{
void *drv_priv = phl_to_drvpriv(timer_args->phl_info);
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_manage_mask == 0x%x\n",
__func__, timer_args->led_manage_mask);
_os_cancel_timer(drv_priv, &(timer_args->timer));
_os_release_timer(drv_priv, &(timer_args->timer));
_os_mem_free(drv_priv, timer_args, sizeof(struct phl_led_timer_args_t));
}
static void _phl_led_remove_from_timer(struct phl_led_info_t *led_info,
enum rtw_led_id led_id)
{
u32 *mask = NULL;
if (led_info->toggle_timer_args != NULL) {
mask = &(led_info->toggle_timer_args->led_manage_mask);
*mask &= ~(BIT(led_id));
if (*mask == 0)
led_info->toggle_timer_args->timer_alive = false;
led_info->toggle_timer_args = NULL;
led_info->toggle_args = NULL;
}
}
static void _phl_led_timer_cb_done(void* priv, struct phl_msg* msg)
{
struct phl_led_timer_args_t *timer_args =
(struct phl_led_timer_args_t *)(msg->inbuf);
if (!timer_args->timer_alive)
timer_args->is_avail = true;
}
static void _phl_led_timer_cb(void *args)
{
struct phl_led_timer_args_t *timer_args =
(struct phl_led_timer_args_t *) args;
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
struct phl_info_t *phl_info = timer_args->phl_info;
struct phl_msg msg = {0};
struct phl_msg_attribute attr = {0};
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_LED);
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_LED_TICK);
msg.band_idx = HW_BAND_0;
msg.inbuf = (u8 *)(timer_args);
msg.inlen = sizeof(struct phl_led_timer_args_t);
attr.completion.completion = _phl_led_timer_cb_done;
attr.completion.priv = phl_info;
phl_status = phl_disp_eng_send_msg(timer_args->phl_info,
&msg, &attr, NULL);
if(phl_status != RTW_PHL_STATUS_SUCCESS){
PHL_ERR("%s: phl_disp_eng_send_msg failed!\n", __func__);
timer_args->timer_alive = false;
_phl_led_timer_cb_done(phl_info, &msg);
}
}
static enum rtw_phl_status _phl_led_ctrl_write_opt(void *hal,
enum rtw_led_id led_id,
enum rtw_led_opt *curr_opt,
enum rtw_led_opt opt)
{
if (opt >= RTW_LED_OPT_UNKNOWN) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: unknown opt (%d)\n",
__func__, opt);
return RTW_PHL_STATUS_FAILURE;
}
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_led_control(hal, led_id, opt))
return RTW_PHL_STATUS_FAILURE;
*curr_opt = opt;
return RTW_PHL_STATUS_SUCCESS;
}
static enum rtw_phl_status
_phl_led_ctrl_start_delay_hdlr(void *hal, struct phl_led_info_t *led_info,
enum rtw_led_id led_id)
{
if (led_info->toggle_start_delay_counter >=
led_info->toggle_args->start_delay) {
led_info->toggle_start_delay_over = true;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: start delay is over\n",
__func__);
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_write_opt(hal, led_id, &(led_info->curr_opt),
led_info->toggle_args->start_opt))
return RTW_PHL_STATUS_FAILURE;
return RTW_PHL_STATUS_SUCCESS;
}
(led_info->toggle_start_delay_counter)++;
return RTW_PHL_STATUS_SUCCESS;
}
static enum rtw_phl_status
_phl_led_ctrl_interval_hdlr(void *hal, struct phl_led_info_t *led_info,
enum rtw_led_id led_id,
struct rtw_led_intervals_t *intervals)
{
u32 interval = 0;
enum rtw_led_opt opt = RTW_LED_OPT_UNKNOWN;
if (intervals == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: intervals == NULL\n",
__func__);
return RTW_PHL_STATUS_FAILURE;
}
if (intervals->interval_arr == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: interval_arr == NULL\n", __func__);
return RTW_PHL_STATUS_FAILURE;
}
if (led_info->toggle_curr_interval_idx >= intervals->len) {
PHL_TRACE(
COMP_PHL_LED, _PHL_INFO_,
"%s: curr_interval_idx ( %d ) >= intervals' len ( %d )\n",
__func__, led_info->toggle_curr_interval_idx,
intervals->len);
return RTW_PHL_STATUS_FAILURE;
}
interval = intervals->interval_arr[led_info->toggle_curr_interval_idx];
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: curr_interval_idx == %d, interval == %d, "
"interval_counter == %d\n",
__func__, led_info->toggle_curr_interval_idx, interval,
led_info->toggle_interval_counter);
if (interval > ++(led_info->toggle_interval_counter))
/* it is not time to toggle */
return RTW_PHL_STATUS_SUCCESS;
led_info->toggle_interval_counter = 0;
/* set curr_interval_idx to next */
if (++(led_info->toggle_curr_interval_idx) >= intervals->len) {
led_info->toggle_curr_interval_idx = 0;
if (led_info->toggle_args->loop > 0)
(led_info->toggle_loop_counter)++;
}
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: toggle led_id: %d\n", __func__,
led_id);
if (led_info->curr_opt == RTW_LED_OPT_LOW)
opt = RTW_LED_OPT_HIGH;
else if (led_info->curr_opt == RTW_LED_OPT_HIGH)
opt = RTW_LED_OPT_LOW;
else {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: incorrect curr_opt ( %d ). led_id: %d\n",
__func__, led_info->curr_opt, led_id);
return RTW_PHL_STATUS_FAILURE;
}
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_write_opt(hal, led_id, &(led_info->curr_opt), opt))
return RTW_PHL_STATUS_FAILURE;
return RTW_PHL_STATUS_SUCCESS;
}
static enum rtw_phl_status
_phl_led_ctrl_toggle_hdlr(struct phl_led_timer_args_t *timer_args)
{
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
void *drv_priv = phl_to_drvpriv(timer_args->phl_info);
enum rtw_led_id led_id = 0;
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)(timer_args->phl_info->led_ctrl);
struct phl_led_info_t *led_info = NULL;
u8 intervals_idx = 0;
for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
if ((timer_args->led_manage_mask & BIT(led_id)) == 0)
continue;
led_info = &(led_ctrl->led_info_arr[led_id]);
/* start_delay handling */
if (!led_info->toggle_start_delay_over) {
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_start_delay_hdlr(
timer_args->phl_info->hal, led_info, led_id)) {
status = RTW_PHL_STATUS_FAILURE;
}
continue;
}
/* start_delay is over, handle intervals */
intervals_idx = led_info->toggle_args->intervals_idx;
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_interval_hdlr(
timer_args->phl_info->hal, led_info, led_id,
&(led_ctrl->intervals_arr[intervals_idx]))) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: intervals handling failed. led_id: %d\n",
__func__, led_id);
status = RTW_PHL_STATUS_FAILURE;
}
if (led_info->toggle_args->loop > 0 &&
led_info->toggle_args->loop ==
led_info->toggle_loop_counter) {
_phl_led_remove_from_timer(led_info, led_id);
}
}
if (timer_args->timer_alive)
_os_set_timer(drv_priv, &(timer_args->timer),
timer_args->delay_unit);
return status;
}
static enum rtw_phl_status
_phl_led_ctrl_action_hdlr(struct phl_info_t *phl_info, enum rtw_led_id led_id,
enum rtw_led_action action,
struct rtw_led_toggle_args_t *toggle_args,
struct phl_led_timer_args_t **timer_args_ptr)
{
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
struct phl_led_info_t *led_info = &(led_ctrl->led_info_arr[led_id]);
enum rtw_led_ctrl_mode target_ctrl_mode;
u8 i = 0;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: led_id == %d, action == 0X%X\n", __func__, led_id,
action);
/* Set ctrl mode*/
switch (action) {
case RTW_LED_ACTION_LOW:
case RTW_LED_ACTION_HIGH:
case RTW_LED_ACTION_TOGGLE:
target_ctrl_mode = led_info->reg_ctrl_mode;
break;
case RTW_LED_ACTION_HW_TRX:
target_ctrl_mode = RTW_LED_CTRL_HW_TRX_MODE;
break;
default:
target_ctrl_mode = led_info->ctrl_mode;
break;
}
if(led_info->ctrl_mode != target_ctrl_mode){
if (rtw_hal_led_set_ctrl_mode(phl_info->hal, led_id,
target_ctrl_mode)){
status = RTW_PHL_STATUS_FAILURE;
return status;
}
led_info->ctrl_mode = target_ctrl_mode;
}
/* Sw action */
switch (action) {
case RTW_LED_ACTION_LOW:
if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
break;
_phl_led_remove_from_timer(led_info, led_id);
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_write_opt(phl_info->hal, led_id,
&(led_info->curr_opt),
RTW_LED_OPT_LOW))
status = RTW_PHL_STATUS_FAILURE;
break;
case RTW_LED_ACTION_HIGH:
if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
break;
_phl_led_remove_from_timer(led_info, led_id);
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_write_opt(phl_info->hal, led_id,
&(led_info->curr_opt),
RTW_LED_OPT_HIGH))
status = RTW_PHL_STATUS_FAILURE;
break;
case RTW_LED_ACTION_HW_TRX:
_phl_led_remove_from_timer(led_info, led_id);
break;
case RTW_LED_ACTION_TOGGLE:
if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
break;
_phl_led_remove_from_timer(led_info, led_id);
led_info->toggle_args = toggle_args;
led_info->toggle_interval_counter = 0;
led_info->toggle_start_delay_counter = toggle_args->start_delay;
led_info->toggle_start_delay_over = false;
led_info->toggle_loop_counter = 0;
led_info->toggle_curr_interval_idx = 0;
if (*timer_args_ptr == NULL) {
for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
if (led_ctrl->toggle_timer_args[i] == NULL)
continue;
if (led_ctrl->toggle_timer_args[i]->is_avail ==
true) {
*timer_args_ptr =
led_ctrl->toggle_timer_args[i];
(*timer_args_ptr)->is_avail = false;
break;
}
}
if (*timer_args_ptr == NULL) {
PHL_ERR("%s: get available timer failed!\n", __func__);
break;
}
(*timer_args_ptr)->phl_info = phl_info;
(*timer_args_ptr)->led_manage_mask = 0;
(*timer_args_ptr)->timer_alive = true;
(*timer_args_ptr)->delay_unit = 0;
}
(*timer_args_ptr)->led_manage_mask |= BIT(led_id);
led_info->toggle_timer_args = *timer_args_ptr;
break;
default:
status = RTW_PHL_STATUS_FAILURE;
break;
}
return status;
}
static enum rtw_phl_status _phl_led_ctrl_event_hdlr(struct phl_info_t *phl_info,
enum rtw_led_event event)
{
enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
struct phl_led_event_args_t *event_args = NULL;
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
u8 args_idx;
enum rtw_led_id led_id;
struct phl_led_info_t *led_info = NULL;
struct rtw_led_action_args_t *action_args = NULL;
struct phl_led_timer_args_t *timer_args = NULL;
if(event >= RTW_LED_EVENT_LENGTH){
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: invalid event(0X%X) >= RTW_LED_EVENT_LENGTH(0X%X).\n",
__func__, event, RTW_LED_EVENT_LENGTH);
return RTW_PHL_STATUS_FAILURE;
}
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: event == 0X%X\n", __func__,
event);
/* set state */
switch (event) {
case RTW_LED_EVENT_SW_RF_ON:
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: set state sw rf on\n",
__func__);
led_ctrl->state |= RTW_LED_STATE_SW_RF_ON;
break;
case RTW_LED_EVENT_SW_RF_OFF:
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: set state sw rf off\n",
__func__);
led_ctrl->state &= ~RTW_LED_STATE_SW_RF_ON;
break;
default:
break;
}
/* handle event */
event_args =
led_ctrl->event_args_list_arr[event]; /* event_args = list head */
for (; event_args != NULL; event_args = event_args->next) {
if (!(event_args->state_condition &
(led_ctrl->state | RTW_LED_STATE_IGNORE)))
continue;
timer_args = NULL;
for (args_idx = 0; args_idx < event_args->action_args_arr_len;
args_idx++) {
action_args = &(event_args->action_args_arr[args_idx]);
led_id = action_args->led_id;
led_info = &(led_ctrl->led_info_arr[led_id]);
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_action_hdlr(
phl_info, led_id, action_args->led_action,
&(action_args->toggle_args), &timer_args)) {
status = RTW_PHL_STATUS_FAILURE;
}
}
if (timer_args == NULL)
continue;
timer_args->delay_unit = event_args->toggle_delay_unit;
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_toggle_hdlr(timer_args))
status = RTW_PHL_STATUS_FAILURE;
}
return status;
}
static enum phl_mdl_ret_code _phl_led_module_init(void *phl, void *dispr,
void **priv)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
void *drv_priv = phl_to_drvpriv(phl_info);
struct phl_led_ctrl_t *led_ctrl = NULL;
enum rtw_led_id led_id = 0;
enum rtw_led_event event_id = 0;
struct phl_led_info_t *led_info = NULL;
struct rtw_led_intervals_t *intervals = NULL;
u8 intervals_idx = 0, i = 0;
struct phl_led_timer_args_t *timer_args = NULL;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_init()\n");
if (NULL == (led_ctrl = _os_mem_alloc(drv_priv,
sizeof(struct phl_led_ctrl_t)))) {
PHL_ERR("%s: alloc buffer failed!\n", __func__);
phl_info->led_ctrl = NULL;
return MDL_RET_FAIL;
}
*priv = phl;
phl_info->led_ctrl = led_ctrl;
/* set default value in led_ctrl */
led_ctrl->state = 0;
for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
led_info = &(led_ctrl->led_info_arr[led_id]);
led_info->ctrl_mode = RTW_LED_CTRL_NOT_SUPPORT;
led_info->reg_ctrl_mode = RTW_LED_CTRL_NOT_SUPPORT;
led_info->curr_opt = RTW_LED_OPT_UNKNOWN;
led_info->toggle_interval_counter = 0;
led_info->toggle_start_delay_counter = 0;
led_info->toggle_start_delay_over = false;
led_info->toggle_loop_counter = 0;
led_info->toggle_curr_interval_idx = 0;
led_info->toggle_timer_args = NULL;
led_info->toggle_args = NULL;
}
for (event_id = 0; event_id < RTW_LED_EVENT_LENGTH; event_id++) {
led_ctrl->event_args_list_arr[event_id] = NULL;
}
for (intervals_idx = 0; intervals_idx < PHL_LED_INTERVALS_ARR_LEN_MAX;
intervals_idx++) {
intervals = &(led_ctrl->intervals_arr[intervals_idx]);
intervals->interval_arr = NULL;
intervals->len = 0;
}
for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
if (NULL == (timer_args = _os_mem_alloc( drv_priv,
sizeof(struct phl_led_timer_args_t)))) {
PHL_ERR("%s: alloc #%d timer buffer failed!\n", __func__, i);
led_ctrl->toggle_timer_args[i] = NULL;
continue;
}
timer_args->phl_info = phl_info;
_os_init_timer(drv_priv, &(timer_args->timer),
_phl_led_timer_cb, timer_args, "phl_led_timer");
timer_args->delay_unit = 0;
timer_args->timer_alive = false;
timer_args->is_avail = true;
timer_args->led_manage_mask = 0;
led_ctrl->toggle_timer_args[i] = timer_args;
}
return MDL_RET_SUCCESS;
}
static void _phl_led_module_deinit(void *dispr, void *priv)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
void *drv_priv = phl_to_drvpriv(phl_info);
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
enum rtw_led_event event = 0;
struct phl_led_event_args_t *event_args = NULL;
struct phl_led_event_args_t *event_args_next = NULL;
struct rtw_led_intervals_t *intervals = NULL;
u8 intervals_idx = 0, i = 0;
enum rtw_led_id led_id = 0;
struct phl_led_info_t *led_info = NULL;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_deinit()\n");
if (led_ctrl == NULL)
return;
/* free event_args_list_arr */
for (event = 0; event < RTW_LED_EVENT_LENGTH; event++) {
event_args = led_ctrl->event_args_list_arr[event];
if (event_args == NULL)
continue;
while (event_args != NULL) {
event_args_next = event_args->next;
if (event_args->action_args_arr != NULL)
_os_mem_free(
drv_priv, event_args->action_args_arr,
event_args->action_args_arr_len *
sizeof(struct rtw_led_action_args_t));
_os_mem_free(drv_priv, event_args,
sizeof(struct phl_led_event_args_t));
event_args = event_args_next;
}
}
/* free intervals_arr */
for (intervals_idx = 0; intervals_idx < PHL_LED_INTERVALS_ARR_LEN_MAX;
intervals_idx++) {
intervals = &(led_ctrl->intervals_arr[intervals_idx]);
if (intervals->interval_arr == NULL)
continue;
_os_mem_free(drv_priv, intervals->interval_arr,
intervals->len * sizeof(u32));
}
/* free all timers */
for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
led_info = &(led_ctrl->led_info_arr[led_id]);
if (led_info->toggle_timer_args == NULL)
continue;
_phl_led_remove_from_timer(led_info, led_id);
}
for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
if (led_ctrl->toggle_timer_args[i] == NULL)
continue;
_phl_led_timer_release(led_ctrl->toggle_timer_args[i]);
}
_os_mem_free(drv_priv, led_ctrl, sizeof(struct phl_led_ctrl_t));
phl_info->led_ctrl = NULL;
}
static enum phl_mdl_ret_code _phl_led_module_start(void *dispr, void *priv)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
enum rtw_led_id led_id = 0;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_start()\n");
if (led_ctrl == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
__func__);
return MDL_RET_FAIL;
}
for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
if (RTW_HAL_STATUS_SUCCESS !=
rtw_hal_led_set_ctrl_mode(
phl_info->hal, led_id,
led_ctrl->led_info_arr[led_id].ctrl_mode))
ret = MDL_RET_FAIL;
}
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_PHL_START))
ret = MDL_RET_FAIL;
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_SW_RF_ON))
ret = MDL_RET_FAIL;
return ret;
}
static enum phl_mdl_ret_code _phl_led_module_stop(void *dispr, void *priv)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
void *drv_priv = phl_to_drvpriv(phl_info);
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
u8 i = 0;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_stop()\n");
if (led_ctrl == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
__func__);
return MDL_RET_FAIL;
}
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_SW_RF_OFF))
ret = MDL_RET_FAIL;
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_PHL_STOP))
ret = MDL_RET_FAIL;
for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
_os_cancel_timer(drv_priv, &(led_ctrl->toggle_timer_args[i]->timer));
led_ctrl->toggle_timer_args[i]->timer_alive = false;
led_ctrl->toggle_timer_args[i]->is_avail = true;
}
return ret;
}
static enum phl_mdl_ret_code _phl_led_module_msg_hdlr(void *dispr, void *priv,
struct phl_msg *msg)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)(phl_info->led_ctrl);
enum phl_msg_evt_id msg_evt_id = MSG_EVT_ID_FIELD(msg->msg_id);
struct phl_led_timer_args_t *timer_args = NULL;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"===> _phl_led_module_msg_hdlr()\n");
if (IS_MSG_IN_PRE_PHASE(msg->msg_id))
return MDL_RET_SUCCESS;
if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_LED)
return MDL_RET_IGNORE;
if(IS_MSG_CANNOT_IO(msg->msg_id))
return MDL_RET_FAIL;
if (led_ctrl == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
__func__);
return MDL_RET_FAIL;
}
if(msg_evt_id < MSG_EVT_LED_EVT_START || msg_evt_id > MSG_EVT_LED_EVT_END){
if (msg_evt_id == MSG_EVT_LED_TICK) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: MSG_EVT_LED_TICK\n",
__func__);
timer_args = (struct phl_led_timer_args_t *)(msg->inbuf);
if (!timer_args->timer_alive)
return MDL_RET_SUCCESS;
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_toggle_hdlr(timer_args))
return MDL_RET_FAIL;
return MDL_RET_SUCCESS;
}
}
else {
if (RTW_PHL_STATUS_SUCCESS !=
_phl_led_ctrl_event_hdlr(phl_info, msg_evt_id - MSG_EVT_LED_EVT_START))
return MDL_RET_FAIL;
}
return MDL_RET_SUCCESS;
}
static enum phl_mdl_ret_code
_phl_led_module_set_info(void *dispr, void *priv,
struct phl_module_op_info *info)
{
return MDL_RET_SUCCESS;
}
static enum phl_mdl_ret_code
_phl_led_module_query_info(void *dispr, void *priv,
struct phl_module_op_info *info)
{
return MDL_RET_SUCCESS;
}
enum rtw_phl_status phl_register_led_module(struct phl_info_t *phl_info)
{
#ifdef CONFIG_CMD_DISP
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
struct phl_bk_module_ops bk_ops;
bk_ops.init = _phl_led_module_init;
bk_ops.deinit = _phl_led_module_deinit;
bk_ops.start = _phl_led_module_start;
bk_ops.stop = _phl_led_module_stop;
bk_ops.msg_hdlr = _phl_led_module_msg_hdlr;
bk_ops.set_info = _phl_led_module_set_info;
bk_ops.query_info = _phl_led_module_query_info;
phl_status = phl_disp_eng_register_module(phl_info, HW_BAND_0,
PHL_MDL_LED, &bk_ops);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s register LED module in cmd disp failed\n",
__func__);
phl_status = RTW_PHL_STATUS_FAILURE;
}
return phl_status;
#else
return RTW_PHL_STATUS_FAILURE;
#endif
}
void rtw_phl_led_set_ctrl_mode(void *phl, enum rtw_led_id led_id,
enum rtw_led_ctrl_mode ctrl_mode)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)phl_info->led_ctrl;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"===> %s()\n", __func__);
if (led_ctrl == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
__func__);
return;
}
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: led_id == %d, ctrl_mode == %d\n", __func__, led_id,
ctrl_mode);
led_ctrl->led_info_arr[led_id].ctrl_mode = ctrl_mode;
led_ctrl->led_info_arr[led_id].reg_ctrl_mode = ctrl_mode;
}
void rtw_phl_led_set_toggle_intervals(void *phl, u8 intervals_idx,
u32 *interval_arr, u8 intervals_len)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)phl_info->led_ctrl;
void *drv_priv = phl_to_drvpriv(phl_info);
struct rtw_led_intervals_t *intervals = NULL;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"===> rtw_phl_led_set_toggle_intervals()\n");
if (led_ctrl == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
__func__);
return;
}
if (intervals_idx >= PHL_LED_INTERVALS_ARR_LEN_MAX) {
PHL_TRACE(
COMP_PHL_LED, _PHL_INFO_,
"%s: intervals_idx >= PHL_LED_INTERVALS_ARR_LEN_MAX\n",
__func__);
return;
}
intervals = &(led_ctrl->intervals_arr[intervals_idx]);
/* check if the target intervals_arr has already been set */
if (intervals->interval_arr != NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: intervals_arr[%d] has already been set. "
"The new one is going to replace the old one!\n",
__func__, intervals_idx);
_os_mem_free(drv_priv, intervals->interval_arr,
intervals->len * sizeof(u32));
intervals->interval_arr = NULL;
intervals->len = 0;
}
if (NULL == (intervals->interval_arr = _os_mem_alloc(
drv_priv, intervals_len * sizeof(u32)))) {
PHL_ERR("%s: alloc buffer failed!\n", __func__);
return;
}
_os_mem_cpy(drv_priv, intervals->interval_arr, interval_arr,
intervals_len * sizeof(u32));
intervals->len = intervals_len;
return;
}
void rtw_phl_led_set_action(void *phl, enum rtw_led_event event,
enum rtw_led_state state_condition,
struct rtw_led_action_args_t *action_args_arr,
u8 action_args_arr_len, u32 toggle_delay_unit)
{
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct phl_led_ctrl_t *led_ctrl =
(struct phl_led_ctrl_t *)phl_info->led_ctrl;
void *drv_priv = phl_to_drvpriv(phl_info);
struct phl_led_event_args_t *event_args = NULL;
struct phl_led_event_args_t *event_args_prev = NULL;
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> %s()\n", __func__);
if (led_ctrl == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
__func__);
return;
}
if (action_args_arr == NULL) {
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: input -- action_args_arr == NULL\n", __func__);
return;
}
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
"%s: event == %d, state_condition == %d\n", __func__, event,
state_condition);
event_args =
led_ctrl->event_args_list_arr[event]; /* event_args = list head */
while (event_args != NULL) {
if (event_args->state_condition == state_condition) {
PHL_TRACE(
COMP_PHL_LED, _PHL_INFO_,
"%s: the event_args_list of event 0x%x already has "
"a node with state_condition == 0x%x\n",
__func__, event, state_condition);
return;
}
event_args_prev = event_args;
event_args = event_args->next;
}
if (NULL == (event_args = _os_mem_alloc(
drv_priv, sizeof(struct phl_led_event_args_t)))) {
PHL_ERR("%s: alloc buffer failed!\n", __func__);
return;
}
if (NULL == (event_args->action_args_arr = _os_mem_alloc(
drv_priv, action_args_arr_len *
sizeof(struct rtw_led_action_args_t)))) {
PHL_ERR("%s: alloc buffer failed!\n", __func__);
_os_mem_free(drv_priv, event_args,
sizeof(struct phl_led_event_args_t));
return;
}
event_args->action_args_arr_len = action_args_arr_len;
event_args->state_condition = state_condition;
event_args->toggle_delay_unit = toggle_delay_unit;
_os_mem_cpy(drv_priv, event_args->action_args_arr, action_args_arr,
action_args_arr_len * sizeof(struct rtw_led_action_args_t));
event_args->next = NULL;
if (event_args_prev == NULL)
/* the event_args_list was empty */
led_ctrl->event_args_list_arr[event] = event_args;
else
event_args_prev->next = event_args;
}
void phl_led_control(struct phl_info_t *phl_info, enum rtw_led_event led_event)
{
#ifdef CONFIG_CMD_DISP
struct phl_msg msg = {0};
struct phl_msg_attribute attr = {0};
PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> rtw_phl_led_control()\n");
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_LED);
/*
* led_event here is passed via the msg_evt_id field instead of
* msg_evt_id due to the following reason:
*
* (a) led_event is used for mapping LED events with LED actions, and
* the mapping can be configured in core layer according to the
* customized LED table.
*
* (b) LED module inside uses led_event as the index of led action
* arrays, and hence it would be inappropriate to directly replace
* led_event with msg_evt_id which is not continuous and does not
* start from zero.
*
* (c) It is not worth it to use inbuf with the overhead of dynamic
* allocation and completion callback only for a number.
*/
SET_MSG_EVT_ID_FIELD(msg.msg_id, led_event + MSG_EVT_LED_EVT_START);
msg.band_idx = HW_BAND_0;
phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
#else
PHL_ERR("phl_fsm not support %s\n", __func__);
#endif
}
void rtw_phl_led_control(void *phl, enum rtw_led_event led_event)
{
phl_led_control((struct phl_info_t *)phl, led_event);
}