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