xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/phl_led.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2019 Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  *****************************************************************************/
15 #define _PHL_LED_C_
16 #include "phl_headers.h"
17 
18 #define PHL_LED_INTERVALS_ARR_LEN_MAX 4
19 
20 struct phl_led_event_args_t {
21 	enum rtw_led_state state_condition;
22 	struct rtw_led_action_args_t *action_args_arr;
23 	u8 action_args_arr_len;
24 	u32 toggle_delay_unit;
25 	struct phl_led_event_args_t *next;
26 };
27 
28 struct phl_led_timer_args_t {
29 	struct phl_info_t *phl_info;
30 	_os_timer timer;
31 	u32 delay_unit;
32 	bool timer_alive;
33 	bool is_avail;
34 	u32 led_manage_mask;
35 };
36 
37 struct phl_led_info_t {
38 	enum rtw_led_ctrl_mode ctrl_mode;
39 	enum rtw_led_ctrl_mode reg_ctrl_mode;
40 	enum rtw_led_opt curr_opt;
41 	const struct rtw_led_toggle_args_t *toggle_args;
42 	struct phl_led_timer_args_t *toggle_timer_args;
43 	u32 toggle_interval_counter;
44 	u32 toggle_start_delay_counter;
45 	bool toggle_start_delay_over;
46 	u32 toggle_loop_counter;
47 	u8 toggle_curr_interval_idx;
48 };
49 
50 struct phl_led_ctrl_t {
51 	struct phl_led_info_t led_info_arr[RTW_LED_ID_LENGTH];
52 	struct phl_led_event_args_t *event_args_list_arr[RTW_LED_EVENT_LENGTH];
53 	struct rtw_led_intervals_t intervals_arr[PHL_LED_INTERVALS_ARR_LEN_MAX];
54 	enum rtw_led_state state;
55 	struct phl_led_timer_args_t *toggle_timer_args[RTW_LED_TIMER_LENGTH];
56 };
57 
_phl_led_timer_release(struct phl_led_timer_args_t * timer_args)58 static void _phl_led_timer_release(struct phl_led_timer_args_t *timer_args)
59 {
60 	void *drv_priv = phl_to_drvpriv(timer_args->phl_info);
61 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_manage_mask == 0x%x\n",
62 		  __func__, timer_args->led_manage_mask);
63 
64 	_os_cancel_timer(drv_priv, &(timer_args->timer));
65 	_os_release_timer(drv_priv, &(timer_args->timer));
66 	_os_mem_free(drv_priv, timer_args, sizeof(struct phl_led_timer_args_t));
67 }
68 
_phl_led_remove_from_timer(struct phl_led_info_t * led_info,enum rtw_led_id led_id)69 static void _phl_led_remove_from_timer(struct phl_led_info_t *led_info,
70 				       enum rtw_led_id led_id)
71 {
72 	u32 *mask = NULL;
73 
74 	if (led_info->toggle_timer_args != NULL) {
75 		mask = &(led_info->toggle_timer_args->led_manage_mask);
76 		*mask &= ~(BIT(led_id));
77 
78 		if (*mask == 0)
79 			led_info->toggle_timer_args->timer_alive = false;
80 
81 		led_info->toggle_timer_args = NULL;
82 		led_info->toggle_args = NULL;
83 	}
84 }
85 
_phl_led_timer_cb_done(void * priv,struct phl_msg * msg)86 static void _phl_led_timer_cb_done(void* priv, struct phl_msg* msg)
87 {
88 	struct phl_led_timer_args_t *timer_args =
89 		 (struct phl_led_timer_args_t *)(msg->inbuf);
90 
91 	if (!timer_args->timer_alive)
92 		timer_args->is_avail = true;
93 }
94 
_phl_led_timer_cb(void * args)95 static void _phl_led_timer_cb(void *args)
96 {
97 	struct phl_led_timer_args_t *timer_args =
98 			(struct phl_led_timer_args_t *) args;
99 	enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
100 	struct phl_info_t *phl_info = timer_args->phl_info;
101 
102 	struct phl_msg msg = {0};
103 	struct phl_msg_attribute attr = {0};
104 
105 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_LED);
106 	SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_LED_TICK);
107 	msg.band_idx = HW_BAND_0;
108 	msg.inbuf = (u8 *)(timer_args);
109 	msg.inlen = sizeof(struct phl_led_timer_args_t);
110 
111 	attr.completion.completion = _phl_led_timer_cb_done;
112 	attr.completion.priv = phl_info;
113 
114 	phl_status = phl_disp_eng_send_msg(timer_args->phl_info,
115 						&msg, &attr, NULL);
116 	if(phl_status != RTW_PHL_STATUS_SUCCESS){
117 		PHL_ERR("%s: phl_disp_eng_send_msg failed!\n", __func__);
118 		timer_args->timer_alive = false;
119 		_phl_led_timer_cb_done(phl_info, &msg);
120 	}
121 }
122 
_phl_led_ctrl_write_opt(void * hal,enum rtw_led_id led_id,enum rtw_led_opt * curr_opt,enum rtw_led_opt opt)123 static enum rtw_phl_status _phl_led_ctrl_write_opt(void *hal,
124 						   enum rtw_led_id led_id,
125 						   enum rtw_led_opt *curr_opt,
126 						   enum rtw_led_opt opt)
127 {
128 	if (opt >= RTW_LED_OPT_UNKNOWN) {
129 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: unknown opt (%d)\n",
130 			  __func__, opt);
131 		return RTW_PHL_STATUS_FAILURE;
132 	}
133 
134 	if (RTW_HAL_STATUS_SUCCESS != rtw_hal_led_control(hal, led_id, opt))
135 		return RTW_PHL_STATUS_FAILURE;
136 
137 	*curr_opt = opt;
138 	return RTW_PHL_STATUS_SUCCESS;
139 }
140 
141 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)142 _phl_led_ctrl_start_delay_hdlr(void *hal, struct phl_led_info_t *led_info,
143 			       enum rtw_led_id led_id)
144 {
145 	if (led_info->toggle_start_delay_counter >=
146 	    led_info->toggle_args->start_delay) {
147 
148 		led_info->toggle_start_delay_over = true;
149 
150 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: start delay is over\n",
151 			  __func__);
152 
153 		if (RTW_PHL_STATUS_SUCCESS !=
154 		    _phl_led_ctrl_write_opt(hal, led_id, &(led_info->curr_opt),
155 					    led_info->toggle_args->start_opt))
156 			return RTW_PHL_STATUS_FAILURE;
157 
158 		return RTW_PHL_STATUS_SUCCESS;
159 	}
160 
161 	(led_info->toggle_start_delay_counter)++;
162 
163 	return RTW_PHL_STATUS_SUCCESS;
164 }
165 
166 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)167 _phl_led_ctrl_interval_hdlr(void *hal, struct phl_led_info_t *led_info,
168 			    enum rtw_led_id led_id,
169 			    struct rtw_led_intervals_t *intervals)
170 {
171 	u32 interval = 0;
172 	enum rtw_led_opt opt = RTW_LED_OPT_UNKNOWN;
173 
174 	if (intervals == NULL) {
175 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: intervals == NULL\n",
176 			  __func__);
177 		return RTW_PHL_STATUS_FAILURE;
178 	}
179 
180 	if (intervals->interval_arr == NULL) {
181 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
182 			  "%s: interval_arr == NULL\n", __func__);
183 		return RTW_PHL_STATUS_FAILURE;
184 	}
185 
186 	if (led_info->toggle_curr_interval_idx >= intervals->len) {
187 		PHL_TRACE(
188 		    COMP_PHL_LED, _PHL_INFO_,
189 		    "%s: curr_interval_idx ( %d ) >= intervals' len ( %d )\n",
190 		    __func__, led_info->toggle_curr_interval_idx,
191 		    intervals->len);
192 		return RTW_PHL_STATUS_FAILURE;
193 	}
194 
195 	interval = intervals->interval_arr[led_info->toggle_curr_interval_idx];
196 
197 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
198 		  "%s: curr_interval_idx == %d, interval == %d, "
199 		  "interval_counter == %d\n",
200 		  __func__, led_info->toggle_curr_interval_idx, interval,
201 		  led_info->toggle_interval_counter);
202 
203 	if (interval > ++(led_info->toggle_interval_counter))
204 		/* it is not time to toggle */
205 		return RTW_PHL_STATUS_SUCCESS;
206 
207 	led_info->toggle_interval_counter = 0;
208 
209 	/* set curr_interval_idx to next */
210 	if (++(led_info->toggle_curr_interval_idx) >= intervals->len) {
211 		led_info->toggle_curr_interval_idx = 0;
212 		if (led_info->toggle_args->loop > 0)
213 			(led_info->toggle_loop_counter)++;
214 	}
215 
216 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: toggle led_id: %d\n", __func__,
217 		  led_id);
218 
219 	if (led_info->curr_opt == RTW_LED_OPT_LOW)
220 		opt = RTW_LED_OPT_HIGH;
221 
222 	else if (led_info->curr_opt == RTW_LED_OPT_HIGH)
223 		opt = RTW_LED_OPT_LOW;
224 
225 	else {
226 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
227 			  "%s: incorrect curr_opt ( %d ). led_id: %d\n",
228 			  __func__, led_info->curr_opt, led_id);
229 		return RTW_PHL_STATUS_FAILURE;
230 	}
231 
232 	if (RTW_PHL_STATUS_SUCCESS !=
233 	    _phl_led_ctrl_write_opt(hal, led_id, &(led_info->curr_opt), opt))
234 		return RTW_PHL_STATUS_FAILURE;
235 
236 	return RTW_PHL_STATUS_SUCCESS;
237 }
238 
239 static enum rtw_phl_status
_phl_led_ctrl_toggle_hdlr(struct phl_led_timer_args_t * timer_args)240 _phl_led_ctrl_toggle_hdlr(struct phl_led_timer_args_t *timer_args)
241 {
242 	enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
243 	void *drv_priv = phl_to_drvpriv(timer_args->phl_info);
244 
245 	enum rtw_led_id led_id = 0;
246 	struct phl_led_ctrl_t *led_ctrl =
247 	    (struct phl_led_ctrl_t *)(timer_args->phl_info->led_ctrl);
248 	struct phl_led_info_t *led_info = NULL;
249 
250 	u8 intervals_idx = 0;
251 
252 	for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
253 		if ((timer_args->led_manage_mask & BIT(led_id)) == 0)
254 			continue;
255 
256 		led_info = &(led_ctrl->led_info_arr[led_id]);
257 
258 		/* start_delay handling */
259 		if (!led_info->toggle_start_delay_over) {
260 			if (RTW_PHL_STATUS_SUCCESS !=
261 			    _phl_led_ctrl_start_delay_hdlr(
262 				timer_args->phl_info->hal, led_info, led_id)) {
263 
264 				status = RTW_PHL_STATUS_FAILURE;
265 			}
266 			continue;
267 		}
268 
269 		/* start_delay is over, handle intervals */
270 		intervals_idx = led_info->toggle_args->intervals_idx;
271 
272 		if (RTW_PHL_STATUS_SUCCESS !=
273 		    _phl_led_ctrl_interval_hdlr(
274 			timer_args->phl_info->hal, led_info, led_id,
275 			&(led_ctrl->intervals_arr[intervals_idx]))) {
276 
277 			PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
278 				  "%s: intervals handling failed. led_id: %d\n",
279 				  __func__, led_id);
280 			status = RTW_PHL_STATUS_FAILURE;
281 		}
282 
283 		if (led_info->toggle_args->loop > 0 &&
284 		    led_info->toggle_args->loop ==
285 			led_info->toggle_loop_counter) {
286 
287 			_phl_led_remove_from_timer(led_info, led_id);
288 		}
289 	}
290 
291 	if (timer_args->timer_alive)
292 		_os_set_timer(drv_priv, &(timer_args->timer),
293 			      timer_args->delay_unit);
294 
295 	return status;
296 }
297 
298 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)299 _phl_led_ctrl_action_hdlr(struct phl_info_t *phl_info, enum rtw_led_id led_id,
300 			  enum rtw_led_action action,
301 			  struct rtw_led_toggle_args_t *toggle_args,
302 			  struct phl_led_timer_args_t **timer_args_ptr)
303 {
304 	enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
305 
306 	struct phl_led_ctrl_t *led_ctrl =
307 	    (struct phl_led_ctrl_t *)(phl_info->led_ctrl);
308 	struct phl_led_info_t *led_info = &(led_ctrl->led_info_arr[led_id]);
309 	enum rtw_led_ctrl_mode target_ctrl_mode;
310 	u8 i = 0;
311 
312 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
313 		  "%s: led_id == %d, action == 0X%X\n", __func__, led_id,
314 		  action);
315 
316 	/* Set ctrl mode*/
317 	switch (action) {
318 	case RTW_LED_ACTION_LOW:
319 	case RTW_LED_ACTION_HIGH:
320 	case RTW_LED_ACTION_TOGGLE:
321 		target_ctrl_mode = led_info->reg_ctrl_mode;
322 		break;
323 	case RTW_LED_ACTION_HW_TRX:
324 		target_ctrl_mode = RTW_LED_CTRL_HW_TRX_MODE;
325 		break;
326 	default:
327 		target_ctrl_mode = led_info->ctrl_mode;
328 		break;
329 	}
330 	if(led_info->ctrl_mode != target_ctrl_mode){
331 		if (rtw_hal_led_set_ctrl_mode(phl_info->hal, led_id,
332 						target_ctrl_mode)){
333 			status = RTW_PHL_STATUS_FAILURE;
334 			return status;
335 		}
336 		led_info->ctrl_mode = target_ctrl_mode;
337 	}
338 
339 	/* Sw action */
340 	switch (action) {
341 	case RTW_LED_ACTION_LOW:
342 		if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
343 	    	   led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
344 		       break;
345 
346 		_phl_led_remove_from_timer(led_info, led_id);
347 		if (RTW_PHL_STATUS_SUCCESS !=
348 		    _phl_led_ctrl_write_opt(phl_info->hal, led_id,
349 					    &(led_info->curr_opt),
350 					    RTW_LED_OPT_LOW))
351 			status = RTW_PHL_STATUS_FAILURE;
352 
353 		break;
354 
355 	case RTW_LED_ACTION_HIGH:
356 		if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
357 	    	   led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
358 		       break;
359 
360 		_phl_led_remove_from_timer(led_info, led_id);
361 		if (RTW_PHL_STATUS_SUCCESS !=
362 		    _phl_led_ctrl_write_opt(phl_info->hal, led_id,
363 					    &(led_info->curr_opt),
364 					    RTW_LED_OPT_HIGH))
365 			status = RTW_PHL_STATUS_FAILURE;
366 
367 		break;
368 
369 	case RTW_LED_ACTION_HW_TRX:
370 		_phl_led_remove_from_timer(led_info, led_id);
371 		break;
372 
373 	case RTW_LED_ACTION_TOGGLE:
374 		if(led_info->ctrl_mode != RTW_LED_CTRL_SW_PP_MODE &&
375 	    	   led_info->ctrl_mode != RTW_LED_CTRL_SW_OD_MODE)
376 		       break;
377 
378 		_phl_led_remove_from_timer(led_info, led_id);
379 
380 		led_info->toggle_args = toggle_args;
381 
382 		led_info->toggle_interval_counter = 0;
383 		led_info->toggle_start_delay_counter = toggle_args->start_delay;
384 		led_info->toggle_start_delay_over = false;
385 		led_info->toggle_loop_counter = 0;
386 		led_info->toggle_curr_interval_idx = 0;
387 
388 		if (*timer_args_ptr == NULL) {
389 			for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
390 				if (led_ctrl->toggle_timer_args[i] == NULL)
391 					continue;
392 				if (led_ctrl->toggle_timer_args[i]->is_avail ==
393 									true) {
394 					*timer_args_ptr =
395 						led_ctrl->toggle_timer_args[i];
396 					(*timer_args_ptr)->is_avail = false;
397 					break;
398 				}
399 			}
400 
401 			if (*timer_args_ptr == NULL) {
402 				PHL_ERR("%s: get available timer failed!\n", __func__);
403 				break;
404 			}
405 
406 			(*timer_args_ptr)->phl_info = phl_info;
407 			(*timer_args_ptr)->led_manage_mask = 0;
408 			(*timer_args_ptr)->timer_alive = true;
409 			(*timer_args_ptr)->delay_unit = 0;
410 		}
411 
412 		(*timer_args_ptr)->led_manage_mask |= BIT(led_id);
413 		led_info->toggle_timer_args = *timer_args_ptr;
414 
415 		break;
416 
417 	default:
418 		status = RTW_PHL_STATUS_FAILURE;
419 		break;
420 	}
421 
422 	return status;
423 }
424 
_phl_led_ctrl_event_hdlr(struct phl_info_t * phl_info,enum rtw_led_event event)425 static enum rtw_phl_status _phl_led_ctrl_event_hdlr(struct phl_info_t *phl_info,
426 						    enum rtw_led_event event)
427 {
428 	enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
429 	struct phl_led_event_args_t *event_args = NULL;
430 	struct phl_led_ctrl_t *led_ctrl =
431 	    (struct phl_led_ctrl_t *)(phl_info->led_ctrl);
432 
433 	u8 args_idx;
434 	enum rtw_led_id led_id;
435 	struct phl_led_info_t *led_info = NULL;
436 	struct rtw_led_action_args_t *action_args = NULL;
437 	struct phl_led_timer_args_t *timer_args = NULL;
438 
439 	if(event >= RTW_LED_EVENT_LENGTH){
440 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: invalid event(0X%X) >= RTW_LED_EVENT_LENGTH(0X%X).\n",
441 			  __func__, event, RTW_LED_EVENT_LENGTH);
442 		return RTW_PHL_STATUS_FAILURE;
443 	}
444 
445 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: event == 0X%X\n", __func__,
446 		  event);
447 
448 	/* set state */
449 	switch (event) {
450 	case RTW_LED_EVENT_SW_RF_ON:
451 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: set state sw rf on\n",
452 			  __func__);
453 		led_ctrl->state |= RTW_LED_STATE_SW_RF_ON;
454 		break;
455 
456 	case RTW_LED_EVENT_SW_RF_OFF:
457 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: set state sw rf off\n",
458 			  __func__);
459 		led_ctrl->state &= ~RTW_LED_STATE_SW_RF_ON;
460 		break;
461 
462 	default:
463 		break;
464 	}
465 
466 	/* handle event */
467 	event_args =
468 	    led_ctrl->event_args_list_arr[event]; /* event_args = list head */
469 	for (; event_args != NULL; event_args = event_args->next) {
470 		if (!(event_args->state_condition &
471 		      (led_ctrl->state | RTW_LED_STATE_IGNORE)))
472 			continue;
473 
474 		timer_args = NULL;
475 
476 		for (args_idx = 0; args_idx < event_args->action_args_arr_len;
477 		     args_idx++) {
478 
479 			action_args = &(event_args->action_args_arr[args_idx]);
480 			led_id = action_args->led_id;
481 			led_info = &(led_ctrl->led_info_arr[led_id]);
482 			if (RTW_PHL_STATUS_SUCCESS !=
483 			    _phl_led_ctrl_action_hdlr(
484 				phl_info, led_id, action_args->led_action,
485 				&(action_args->toggle_args), &timer_args)) {
486 
487 				status = RTW_PHL_STATUS_FAILURE;
488 			}
489 		}
490 
491 		if (timer_args == NULL)
492 			continue;
493 
494 		timer_args->delay_unit = event_args->toggle_delay_unit;
495 
496 		if (RTW_PHL_STATUS_SUCCESS !=
497 		    _phl_led_ctrl_toggle_hdlr(timer_args))
498 			status = RTW_PHL_STATUS_FAILURE;
499 	}
500 
501 	return status;
502 }
503 
_phl_led_module_init(void * phl,void * dispr,void ** priv)504 static enum phl_mdl_ret_code _phl_led_module_init(void *phl, void *dispr,
505 						  void **priv)
506 {
507 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
508 	void *drv_priv = phl_to_drvpriv(phl_info);
509 	struct phl_led_ctrl_t *led_ctrl = NULL;
510 
511 	enum rtw_led_id led_id = 0;
512 	enum rtw_led_event event_id = 0;
513 
514 	struct phl_led_info_t *led_info = NULL;
515 
516 	struct rtw_led_intervals_t *intervals = NULL;
517 	u8 intervals_idx = 0, i = 0;
518 
519 	struct phl_led_timer_args_t *timer_args = NULL;
520 
521 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_init()\n");
522 
523 	if (NULL == (led_ctrl = _os_mem_alloc(drv_priv,
524 					      sizeof(struct phl_led_ctrl_t)))) {
525 
526 		PHL_ERR("%s: alloc buffer failed!\n", __func__);
527 		phl_info->led_ctrl = NULL;
528 		return MDL_RET_FAIL;
529 	}
530 
531 	*priv = phl;
532 	phl_info->led_ctrl = led_ctrl;
533 
534 	/* set default value in led_ctrl */
535 	led_ctrl->state = 0;
536 
537 	for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
538 		led_info = &(led_ctrl->led_info_arr[led_id]);
539 
540 		led_info->ctrl_mode = RTW_LED_CTRL_NOT_SUPPORT;
541 		led_info->reg_ctrl_mode = RTW_LED_CTRL_NOT_SUPPORT;
542 		led_info->curr_opt = RTW_LED_OPT_UNKNOWN;
543 		led_info->toggle_interval_counter = 0;
544 		led_info->toggle_start_delay_counter = 0;
545 		led_info->toggle_start_delay_over = false;
546 		led_info->toggle_loop_counter = 0;
547 		led_info->toggle_curr_interval_idx = 0;
548 		led_info->toggle_timer_args = NULL;
549 		led_info->toggle_args = NULL;
550 	}
551 
552 	for (event_id = 0; event_id < RTW_LED_EVENT_LENGTH; event_id++) {
553 		led_ctrl->event_args_list_arr[event_id] = NULL;
554 	}
555 
556 	for (intervals_idx = 0; intervals_idx < PHL_LED_INTERVALS_ARR_LEN_MAX;
557 	     intervals_idx++) {
558 
559 		intervals = &(led_ctrl->intervals_arr[intervals_idx]);
560 
561 		intervals->interval_arr = NULL;
562 		intervals->len = 0;
563 	}
564 
565 	for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
566 		if (NULL == (timer_args = _os_mem_alloc( drv_priv,
567 				sizeof(struct phl_led_timer_args_t)))) {
568 
569 			PHL_ERR("%s: alloc #%d timer buffer failed!\n", __func__, i);
570 			led_ctrl->toggle_timer_args[i] = NULL;
571 			continue;
572 		}
573 
574 		timer_args->phl_info = phl_info;
575 
576 		_os_init_timer(drv_priv, &(timer_args->timer),
577 				_phl_led_timer_cb, timer_args, "phl_led_timer");
578 
579 		timer_args->delay_unit = 0;
580 		timer_args->timer_alive = false;
581 		timer_args->is_avail = true;
582 		timer_args->led_manage_mask = 0;
583 
584 		led_ctrl->toggle_timer_args[i] = timer_args;
585 	}
586 
587 	return MDL_RET_SUCCESS;
588 }
589 
_phl_led_module_deinit(void * dispr,void * priv)590 static void _phl_led_module_deinit(void *dispr, void *priv)
591 {
592 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
593 	void *drv_priv = phl_to_drvpriv(phl_info);
594 	struct phl_led_ctrl_t *led_ctrl =
595 	    (struct phl_led_ctrl_t *)(phl_info->led_ctrl);
596 
597 	enum rtw_led_event event = 0;
598 	struct phl_led_event_args_t *event_args = NULL;
599 	struct phl_led_event_args_t *event_args_next = NULL;
600 
601 	struct rtw_led_intervals_t *intervals = NULL;
602 	u8 intervals_idx = 0, i = 0;
603 
604 	enum rtw_led_id led_id = 0;
605 	struct phl_led_info_t *led_info = NULL;
606 
607 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_deinit()\n");
608 
609 	if (led_ctrl == NULL)
610 		return;
611 
612 	/* free event_args_list_arr */
613 	for (event = 0; event < RTW_LED_EVENT_LENGTH; event++) {
614 		event_args = led_ctrl->event_args_list_arr[event];
615 
616 		if (event_args == NULL)
617 			continue;
618 
619 		while (event_args != NULL) {
620 			event_args_next = event_args->next;
621 
622 			if (event_args->action_args_arr != NULL)
623 				_os_mem_free(
624 				    drv_priv, event_args->action_args_arr,
625 				    event_args->action_args_arr_len *
626 					sizeof(struct rtw_led_action_args_t));
627 
628 			_os_mem_free(drv_priv, event_args,
629 				     sizeof(struct phl_led_event_args_t));
630 
631 			event_args = event_args_next;
632 		}
633 	}
634 
635 	/* free intervals_arr */
636 	for (intervals_idx = 0; intervals_idx < PHL_LED_INTERVALS_ARR_LEN_MAX;
637 	     intervals_idx++) {
638 
639 		intervals = &(led_ctrl->intervals_arr[intervals_idx]);
640 
641 		if (intervals->interval_arr == NULL)
642 			continue;
643 
644 		_os_mem_free(drv_priv, intervals->interval_arr,
645 			     intervals->len * sizeof(u32));
646 	}
647 
648 	/* free all timers */
649 	for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
650 		led_info = &(led_ctrl->led_info_arr[led_id]);
651 		if (led_info->toggle_timer_args == NULL)
652 			continue;
653 
654 		_phl_led_remove_from_timer(led_info, led_id);
655 	}
656 	for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
657 		if (led_ctrl->toggle_timer_args[i] == NULL)
658 			continue;
659 
660 		_phl_led_timer_release(led_ctrl->toggle_timer_args[i]);
661 	}
662 
663 	_os_mem_free(drv_priv, led_ctrl, sizeof(struct phl_led_ctrl_t));
664 
665 	phl_info->led_ctrl = NULL;
666 }
667 
_phl_led_module_start(void * dispr,void * priv)668 static enum phl_mdl_ret_code _phl_led_module_start(void *dispr, void *priv)
669 {
670 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
671 	struct phl_led_ctrl_t *led_ctrl =
672 	    (struct phl_led_ctrl_t *)(phl_info->led_ctrl);
673 
674 	enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
675 	enum rtw_led_id led_id = 0;
676 
677 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_start()\n");
678 
679 	if (led_ctrl == NULL) {
680 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
681 			  __func__);
682 		return MDL_RET_FAIL;
683 	}
684 
685 	for (led_id = 0; led_id < RTW_LED_ID_LENGTH; led_id++) {
686 		if (RTW_HAL_STATUS_SUCCESS !=
687 		    rtw_hal_led_set_ctrl_mode(
688 			phl_info->hal, led_id,
689 			led_ctrl->led_info_arr[led_id].ctrl_mode))
690 			ret = MDL_RET_FAIL;
691 	}
692 
693 	if (RTW_PHL_STATUS_SUCCESS !=
694 	    _phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_PHL_START))
695 		ret = MDL_RET_FAIL;
696 
697 	if (RTW_PHL_STATUS_SUCCESS !=
698 	    _phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_SW_RF_ON))
699 		ret = MDL_RET_FAIL;
700 
701 	return ret;
702 }
703 
_phl_led_module_stop(void * dispr,void * priv)704 static enum phl_mdl_ret_code _phl_led_module_stop(void *dispr, void *priv)
705 {
706 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
707 	void *drv_priv = phl_to_drvpriv(phl_info);
708 	struct phl_led_ctrl_t *led_ctrl =
709 	    (struct phl_led_ctrl_t *)(phl_info->led_ctrl);
710 
711 	enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
712 	u8 i = 0;
713 
714 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> _phl_led_module_stop()\n");
715 
716 	if (led_ctrl == NULL) {
717 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
718 			  __func__);
719 		return MDL_RET_FAIL;
720 	}
721 
722 	if (RTW_PHL_STATUS_SUCCESS !=
723 	    _phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_SW_RF_OFF))
724 		ret = MDL_RET_FAIL;
725 
726 	if (RTW_PHL_STATUS_SUCCESS !=
727 	    _phl_led_ctrl_event_hdlr(phl_info, RTW_LED_EVENT_PHL_STOP))
728 		ret = MDL_RET_FAIL;
729 
730 	for (i = 0; i < RTW_LED_TIMER_LENGTH; i++) {
731 		_os_cancel_timer(drv_priv, &(led_ctrl->toggle_timer_args[i]->timer));
732 		led_ctrl->toggle_timer_args[i]->timer_alive = false;
733 		led_ctrl->toggle_timer_args[i]->is_avail = true;
734 	}
735 
736 	return ret;
737 }
738 
_phl_led_module_msg_hdlr(void * dispr,void * priv,struct phl_msg * msg)739 static enum phl_mdl_ret_code _phl_led_module_msg_hdlr(void *dispr, void *priv,
740 						      struct phl_msg *msg)
741 {
742 	struct phl_info_t *phl_info = (struct phl_info_t *)priv;
743 	struct phl_led_ctrl_t *led_ctrl =
744 	    (struct phl_led_ctrl_t *)(phl_info->led_ctrl);
745 	enum phl_msg_evt_id msg_evt_id = MSG_EVT_ID_FIELD(msg->msg_id);
746 	struct phl_led_timer_args_t *timer_args = NULL;
747 
748 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
749 		  "===> _phl_led_module_msg_hdlr()\n");
750 
751 	if (IS_MSG_IN_PRE_PHASE(msg->msg_id))
752 		return MDL_RET_SUCCESS;
753 
754 	if (MSG_MDL_ID_FIELD(msg->msg_id) != PHL_MDL_LED)
755 		return MDL_RET_IGNORE;
756 
757 	if(IS_MSG_CANNOT_IO(msg->msg_id))
758 		return MDL_RET_FAIL;
759 
760 	if (led_ctrl == NULL) {
761 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
762 			  __func__);
763 		return MDL_RET_FAIL;
764 	}
765 
766 	if(msg_evt_id < MSG_EVT_LED_EVT_START || msg_evt_id > MSG_EVT_LED_EVT_END){
767 		if (msg_evt_id == MSG_EVT_LED_TICK) {
768 			PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: MSG_EVT_LED_TICK\n",
769 				  __func__);
770 			timer_args = (struct phl_led_timer_args_t *)(msg->inbuf);
771 
772 			if (!timer_args->timer_alive)
773 				return MDL_RET_SUCCESS;
774 
775 			if (RTW_PHL_STATUS_SUCCESS !=
776 		    	    _phl_led_ctrl_toggle_hdlr(timer_args))
777 				return MDL_RET_FAIL;
778 
779 			return MDL_RET_SUCCESS;
780 		}
781 	}
782 	else {
783 		if (RTW_PHL_STATUS_SUCCESS !=
784 		    _phl_led_ctrl_event_hdlr(phl_info, msg_evt_id - MSG_EVT_LED_EVT_START))
785 			return MDL_RET_FAIL;
786 	}
787 
788 	return MDL_RET_SUCCESS;
789 }
790 
791 static enum phl_mdl_ret_code
_phl_led_module_set_info(void * dispr,void * priv,struct phl_module_op_info * info)792 _phl_led_module_set_info(void *dispr, void *priv,
793 			 struct phl_module_op_info *info)
794 {
795 	return MDL_RET_SUCCESS;
796 }
797 
798 static enum phl_mdl_ret_code
_phl_led_module_query_info(void * dispr,void * priv,struct phl_module_op_info * info)799 _phl_led_module_query_info(void *dispr, void *priv,
800 			   struct phl_module_op_info *info)
801 {
802 	return MDL_RET_SUCCESS;
803 }
804 
phl_register_led_module(struct phl_info_t * phl_info)805 enum rtw_phl_status phl_register_led_module(struct phl_info_t *phl_info)
806 {
807 #ifdef CONFIG_CMD_DISP
808 	enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
809 
810 	struct phl_bk_module_ops bk_ops;
811 	bk_ops.init = _phl_led_module_init;
812 	bk_ops.deinit = _phl_led_module_deinit;
813 	bk_ops.start = _phl_led_module_start;
814 	bk_ops.stop = _phl_led_module_stop;
815 	bk_ops.msg_hdlr = _phl_led_module_msg_hdlr;
816 	bk_ops.set_info = _phl_led_module_set_info;
817 	bk_ops.query_info = _phl_led_module_query_info;
818 
819 	phl_status = phl_disp_eng_register_module(phl_info, HW_BAND_0,
820 						  PHL_MDL_LED, &bk_ops);
821 
822 	if (phl_status != RTW_PHL_STATUS_SUCCESS) {
823 		PHL_ERR("%s register LED module in cmd disp failed\n",
824 			__func__);
825 		phl_status = RTW_PHL_STATUS_FAILURE;
826 	}
827 
828 	return phl_status;
829 #else
830 	return RTW_PHL_STATUS_FAILURE;
831 #endif
832 }
833 
rtw_phl_led_set_ctrl_mode(void * phl,enum rtw_led_id led_id,enum rtw_led_ctrl_mode ctrl_mode)834 void rtw_phl_led_set_ctrl_mode(void *phl, enum rtw_led_id led_id,
835 			       enum rtw_led_ctrl_mode ctrl_mode)
836 {
837 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
838 	struct phl_led_ctrl_t *led_ctrl =
839 	    (struct phl_led_ctrl_t *)phl_info->led_ctrl;
840 
841 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
842 		  "===> %s()\n", __func__);
843 
844 	if (led_ctrl == NULL) {
845 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
846 			  __func__);
847 		return;
848 	}
849 
850 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
851 		  "%s: led_id == %d, ctrl_mode == %d\n", __func__, led_id,
852 		  ctrl_mode);
853 
854 	led_ctrl->led_info_arr[led_id].ctrl_mode = ctrl_mode;
855 	led_ctrl->led_info_arr[led_id].reg_ctrl_mode = ctrl_mode;
856 }
857 
rtw_phl_led_set_toggle_intervals(void * phl,u8 intervals_idx,u32 * interval_arr,u8 intervals_len)858 void rtw_phl_led_set_toggle_intervals(void *phl, u8 intervals_idx,
859 				      u32 *interval_arr, u8 intervals_len)
860 {
861 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
862 	struct phl_led_ctrl_t *led_ctrl =
863 	    (struct phl_led_ctrl_t *)phl_info->led_ctrl;
864 	void *drv_priv = phl_to_drvpriv(phl_info);
865 
866 	struct rtw_led_intervals_t *intervals = NULL;
867 
868 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
869 		  "===> rtw_phl_led_set_toggle_intervals()\n");
870 
871 	if (led_ctrl == NULL) {
872 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
873 			  __func__);
874 		return;
875 	}
876 
877 	if (intervals_idx >= PHL_LED_INTERVALS_ARR_LEN_MAX) {
878 		PHL_TRACE(
879 		    COMP_PHL_LED, _PHL_INFO_,
880 		    "%s: intervals_idx >= PHL_LED_INTERVALS_ARR_LEN_MAX\n",
881 		    __func__);
882 		return;
883 	}
884 
885 	intervals = &(led_ctrl->intervals_arr[intervals_idx]);
886 
887 	/* check if the target intervals_arr has already been set */
888 	if (intervals->interval_arr != NULL) {
889 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
890 			  "%s: intervals_arr[%d] has already been set. "
891 			  "The new one is going to replace the old one!\n",
892 			  __func__, intervals_idx);
893 
894 		_os_mem_free(drv_priv, intervals->interval_arr,
895 			     intervals->len * sizeof(u32));
896 
897 		intervals->interval_arr = NULL;
898 		intervals->len = 0;
899 	}
900 
901 	if (NULL == (intervals->interval_arr = _os_mem_alloc(
902 			 drv_priv, intervals_len * sizeof(u32)))) {
903 
904 		PHL_ERR("%s: alloc buffer failed!\n", __func__);
905 		return;
906 	}
907 
908 	_os_mem_cpy(drv_priv, intervals->interval_arr, interval_arr,
909 		    intervals_len * sizeof(u32));
910 	intervals->len = intervals_len;
911 
912 	return;
913 }
914 
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)915 void rtw_phl_led_set_action(void *phl, enum rtw_led_event event,
916 			    enum rtw_led_state state_condition,
917 			    struct rtw_led_action_args_t *action_args_arr,
918 			    u8 action_args_arr_len, u32 toggle_delay_unit)
919 {
920 	struct phl_info_t *phl_info = (struct phl_info_t *)phl;
921 	struct phl_led_ctrl_t *led_ctrl =
922 	    (struct phl_led_ctrl_t *)phl_info->led_ctrl;
923 	void *drv_priv = phl_to_drvpriv(phl_info);
924 
925 	struct phl_led_event_args_t *event_args = NULL;
926 	struct phl_led_event_args_t *event_args_prev = NULL;
927 
928 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> %s()\n", __func__);
929 
930 	if (led_ctrl == NULL) {
931 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "%s: led_ctrl == NULL\n",
932 			  __func__);
933 		return;
934 	}
935 
936 	if (action_args_arr == NULL) {
937 		PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
938 			  "%s: input -- action_args_arr == NULL\n", __func__);
939 		return;
940 	}
941 
942 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_,
943 		  "%s: event == %d, state_condition == %d\n", __func__, event,
944 		  state_condition);
945 
946 	event_args =
947 	    led_ctrl->event_args_list_arr[event]; /* event_args = list head */
948 
949 	while (event_args != NULL) {
950 		if (event_args->state_condition == state_condition) {
951 			PHL_TRACE(
952 			    COMP_PHL_LED, _PHL_INFO_,
953 			    "%s: the event_args_list of event 0x%x already has "
954 			    "a node with state_condition == 0x%x\n",
955 			    __func__, event, state_condition);
956 			return;
957 		}
958 
959 		event_args_prev = event_args;
960 		event_args = event_args->next;
961 	}
962 
963 	if (NULL == (event_args = _os_mem_alloc(
964 			 drv_priv, sizeof(struct phl_led_event_args_t)))) {
965 
966 		PHL_ERR("%s: alloc buffer failed!\n", __func__);
967 		return;
968 	}
969 
970 	if (NULL == (event_args->action_args_arr = _os_mem_alloc(
971 			 drv_priv, action_args_arr_len *
972 				       sizeof(struct rtw_led_action_args_t)))) {
973 
974 		PHL_ERR("%s: alloc buffer failed!\n", __func__);
975 		_os_mem_free(drv_priv, event_args,
976 			     sizeof(struct phl_led_event_args_t));
977 		return;
978 	}
979 
980 	event_args->action_args_arr_len = action_args_arr_len;
981 	event_args->state_condition = state_condition;
982 	event_args->toggle_delay_unit = toggle_delay_unit;
983 
984 	_os_mem_cpy(drv_priv, event_args->action_args_arr, action_args_arr,
985 		    action_args_arr_len * sizeof(struct rtw_led_action_args_t));
986 
987 	event_args->next = NULL;
988 
989 	if (event_args_prev == NULL)
990 		/* the event_args_list was empty */
991 		led_ctrl->event_args_list_arr[event] = event_args;
992 	else
993 		event_args_prev->next = event_args;
994 }
995 
phl_led_control(struct phl_info_t * phl_info,enum rtw_led_event led_event)996 void phl_led_control(struct phl_info_t *phl_info, enum rtw_led_event led_event)
997 {
998 #ifdef CONFIG_CMD_DISP
999 	struct phl_msg msg = {0};
1000 	struct phl_msg_attribute attr = {0};
1001 
1002 	PHL_TRACE(COMP_PHL_LED, _PHL_INFO_, "===> rtw_phl_led_control()\n");
1003 
1004 	SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_LED);
1005 
1006 	/*
1007 	 * led_event here is passed via the msg_evt_id field instead of
1008 	 * msg_evt_id due to the following reason:
1009 	 *
1010 	 * (a) led_event is used for mapping LED events with LED actions, and
1011 	 *     the mapping can be configured in core layer according to the
1012 	 *     customized LED table.
1013 	 *
1014 	 * (b) LED module inside uses led_event as the index of led action
1015 	 *     arrays, and hence it would be inappropriate to directly replace
1016 	 *     led_event with msg_evt_id which is not continuous and does not
1017 	 *     start from zero.
1018 	 *
1019 	 * (c) It is not worth it to use inbuf with the overhead of dynamic
1020 	 *     allocation and completion callback only for a number.
1021 	 */
1022 	SET_MSG_EVT_ID_FIELD(msg.msg_id, led_event + MSG_EVT_LED_EVT_START);
1023 	msg.band_idx = HW_BAND_0;
1024 	phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
1025 #else
1026 	PHL_ERR("phl_fsm not support %s\n", __func__);
1027 #endif
1028 }
1029 
rtw_phl_led_control(void * phl,enum rtw_led_event led_event)1030 void rtw_phl_led_control(void *phl, enum rtw_led_event led_event)
1031 {
1032 	phl_led_control((struct phl_info_t *)phl, led_event);
1033 }
1034