1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2007 - 2012 Realtek Corporation. */
4 #include "../include/drv_types.h"
5 #include "../include/rtw_led.h"
6 #include "../include/rtl8188e_spec.h"
8 #define LED_BLINK_NO_LINK_INTVL msecs_to_jiffies(1000)
9 #define LED_BLINK_LINK_INTVL msecs_to_jiffies(500)
10 #define LED_BLINK_SCAN_INTVL msecs_to_jiffies(180)
11 #define LED_BLINK_FASTER_INTVL msecs_to_jiffies(50)
12 #define LED_BLINK_WPS_SUCESS_INTVL msecs_to_jiffies(5000)
14 #define IS_LED_WPS_BLINKING(l) \
15 ((l)->CurrLedState == LED_BLINK_WPS || \
16 (l)->CurrLedState == LED_BLINK_WPS_STOP || \
17 (l)->bLedWPSBlinkInProgress)
19 static void ResetLedStatus(struct LED_871x *pLed)
21 pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */
22 pLed->bLedOn = false; /* true if LED is ON, false if LED is OFF. */
24 pLed->bLedBlinkInProgress = false; /* true if it is blinking, false o.w.. */
25 pLed->bLedWPSBlinkInProgress = false;
27 pLed->BlinkTimes = 0; /* Number of times to toggle led state for blinking. */
28 pLed->BlinkingLedState = LED_UNKNOWN; /* Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
30 pLed->bLedNoLinkBlinkInProgress = false;
31 pLed->bLedLinkBlinkInProgress = false;
32 pLed->bLedScanBlinkInProgress = false;
35 static void SwLedOn(struct adapter *padapter, struct LED_871x *pLed)
39 if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
42 LedCfg = rtw_read8(padapter, REG_LEDCFG2);
43 rtw_write8(padapter, REG_LEDCFG2, (LedCfg & 0xf0) | BIT(5) | BIT(6)); /* SW control led0 on. */
47 static void SwLedOff(struct adapter *padapter, struct LED_871x *pLed)
51 if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
54 LedCfg = rtw_read8(padapter, REG_LEDCFG2);/* 0x4E */
56 LedCfg &= 0x90; /* Set to software control. */
57 rtw_write8(padapter, REG_LEDCFG2, (LedCfg | BIT(3)));
58 LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG);
60 rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg);
65 static void blink_work(struct work_struct *work)
67 struct delayed_work *dwork = to_delayed_work(work);
68 struct LED_871x *pLed = container_of(dwork, struct LED_871x, blink_work);
69 struct adapter *padapter = pLed->padapter;
70 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
72 if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
75 if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
76 SwLedOff(padapter, pLed);
81 /* Change LED according to BlinkingLedState specified. */
82 if (pLed->BlinkingLedState == RTW_LED_ON)
83 SwLedOn(padapter, pLed);
85 SwLedOff(padapter, pLed);
87 switch (pLed->CurrLedState) {
88 case LED_BLINK_SLOWLY:
90 pLed->BlinkingLedState = RTW_LED_OFF;
92 pLed->BlinkingLedState = RTW_LED_ON;
93 schedule_delayed_work(&pLed->blink_work, LED_BLINK_NO_LINK_INTVL);
95 case LED_BLINK_NORMAL:
97 pLed->BlinkingLedState = RTW_LED_OFF;
99 pLed->BlinkingLedState = RTW_LED_ON;
100 schedule_delayed_work(&pLed->blink_work, LED_BLINK_LINK_INTVL);
104 pLed->BlinkingLedState = RTW_LED_OFF;
106 pLed->BlinkingLedState = RTW_LED_ON;
108 if (pLed->BlinkTimes == 0) {
109 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
110 pLed->bLedLinkBlinkInProgress = true;
111 pLed->CurrLedState = LED_BLINK_NORMAL;
112 schedule_delayed_work(&pLed->blink_work, LED_BLINK_LINK_INTVL);
114 pLed->bLedNoLinkBlinkInProgress = true;
115 pLed->CurrLedState = LED_BLINK_SLOWLY;
116 schedule_delayed_work(&pLed->blink_work, LED_BLINK_NO_LINK_INTVL);
118 pLed->bLedScanBlinkInProgress = false;
120 schedule_delayed_work(&pLed->blink_work, LED_BLINK_SCAN_INTVL);
125 pLed->BlinkingLedState = RTW_LED_OFF;
127 pLed->BlinkingLedState = RTW_LED_ON;
129 if (pLed->BlinkTimes == 0) {
130 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
131 pLed->bLedLinkBlinkInProgress = true;
132 pLed->CurrLedState = LED_BLINK_NORMAL;
133 schedule_delayed_work(&pLed->blink_work, LED_BLINK_LINK_INTVL);
135 pLed->bLedNoLinkBlinkInProgress = true;
136 pLed->CurrLedState = LED_BLINK_SLOWLY;
137 schedule_delayed_work(&pLed->blink_work, LED_BLINK_NO_LINK_INTVL);
139 pLed->bLedBlinkInProgress = false;
141 schedule_delayed_work(&pLed->blink_work, LED_BLINK_FASTER_INTVL);
146 pLed->BlinkingLedState = RTW_LED_OFF;
148 pLed->BlinkingLedState = RTW_LED_ON;
149 schedule_delayed_work(&pLed->blink_work, LED_BLINK_SCAN_INTVL);
151 case LED_BLINK_WPS_STOP: /* WPS success */
152 if (pLed->BlinkingLedState != RTW_LED_ON) {
153 pLed->bLedLinkBlinkInProgress = true;
154 pLed->CurrLedState = LED_BLINK_NORMAL;
156 pLed->BlinkingLedState = RTW_LED_OFF;
158 pLed->BlinkingLedState = RTW_LED_ON;
159 schedule_delayed_work(&pLed->blink_work, LED_BLINK_LINK_INTVL);
161 pLed->bLedWPSBlinkInProgress = false;
163 pLed->BlinkingLedState = RTW_LED_OFF;
164 schedule_delayed_work(&pLed->blink_work, LED_BLINK_WPS_SUCESS_INTVL);
172 void rtl8188eu_InitSwLeds(struct adapter *padapter)
174 struct led_priv *pledpriv = &padapter->ledpriv;
175 struct LED_871x *pLed = &pledpriv->SwLed0;
177 pLed->padapter = padapter;
178 ResetLedStatus(pLed);
179 INIT_DELAYED_WORK(&pLed->blink_work, blink_work);
182 void rtl8188eu_DeInitSwLeds(struct adapter *padapter)
184 struct led_priv *ledpriv = &padapter->ledpriv;
185 struct LED_871x *pLed = &ledpriv->SwLed0;
187 cancel_delayed_work_sync(&pLed->blink_work);
188 ResetLedStatus(pLed);
189 SwLedOff(padapter, pLed);
192 void rtw_led_control(struct adapter *padapter, enum LED_CTL_MODE LedAction)
194 struct led_priv *ledpriv = &padapter->ledpriv;
195 struct registry_priv *registry_par;
196 struct LED_871x *pLed = &ledpriv->SwLed0;
197 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
199 if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) ||
200 (!padapter->hw_init_completed))
203 if (!ledpriv->bRegUseLed)
206 registry_par = &padapter->registrypriv;
207 if (!registry_par->led_enable)
211 case LED_CTL_START_TO_LINK:
212 case LED_CTL_NO_LINK:
213 if (!pLed->bLedNoLinkBlinkInProgress) {
214 if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
216 if (pLed->bLedLinkBlinkInProgress) {
217 cancel_delayed_work(&pLed->blink_work);
218 pLed->bLedLinkBlinkInProgress = false;
220 if (pLed->bLedBlinkInProgress) {
221 cancel_delayed_work(&pLed->blink_work);
222 pLed->bLedBlinkInProgress = false;
225 pLed->bLedNoLinkBlinkInProgress = true;
226 pLed->CurrLedState = LED_BLINK_SLOWLY;
228 pLed->BlinkingLedState = RTW_LED_OFF;
230 pLed->BlinkingLedState = RTW_LED_ON;
231 schedule_delayed_work(&pLed->blink_work, LED_BLINK_NO_LINK_INTVL);
235 if (!pLed->bLedLinkBlinkInProgress) {
236 if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
238 if (pLed->bLedNoLinkBlinkInProgress) {
239 cancel_delayed_work(&pLed->blink_work);
240 pLed->bLedNoLinkBlinkInProgress = false;
242 if (pLed->bLedBlinkInProgress) {
243 cancel_delayed_work(&pLed->blink_work);
244 pLed->bLedBlinkInProgress = false;
246 pLed->bLedLinkBlinkInProgress = true;
247 pLed->CurrLedState = LED_BLINK_NORMAL;
249 pLed->BlinkingLedState = RTW_LED_OFF;
251 pLed->BlinkingLedState = RTW_LED_ON;
252 schedule_delayed_work(&pLed->blink_work, LED_BLINK_LINK_INTVL);
255 case LED_CTL_SITE_SURVEY:
256 if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
258 } else if (!pLed->bLedScanBlinkInProgress) {
259 if (IS_LED_WPS_BLINKING(pLed))
261 if (pLed->bLedNoLinkBlinkInProgress) {
262 cancel_delayed_work(&pLed->blink_work);
263 pLed->bLedNoLinkBlinkInProgress = false;
265 if (pLed->bLedLinkBlinkInProgress) {
266 cancel_delayed_work(&pLed->blink_work);
267 pLed->bLedLinkBlinkInProgress = false;
269 if (pLed->bLedBlinkInProgress) {
270 cancel_delayed_work(&pLed->blink_work);
271 pLed->bLedBlinkInProgress = false;
273 pLed->bLedScanBlinkInProgress = true;
274 pLed->CurrLedState = LED_BLINK_SCAN;
275 pLed->BlinkTimes = 24;
277 pLed->BlinkingLedState = RTW_LED_OFF;
279 pLed->BlinkingLedState = RTW_LED_ON;
280 schedule_delayed_work(&pLed->blink_work, LED_BLINK_SCAN_INTVL);
285 if (!pLed->bLedBlinkInProgress) {
286 if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
288 if (pLed->bLedNoLinkBlinkInProgress) {
289 cancel_delayed_work(&pLed->blink_work);
290 pLed->bLedNoLinkBlinkInProgress = false;
292 if (pLed->bLedLinkBlinkInProgress) {
293 cancel_delayed_work(&pLed->blink_work);
294 pLed->bLedLinkBlinkInProgress = false;
296 pLed->bLedBlinkInProgress = true;
297 pLed->CurrLedState = LED_BLINK_TXRX;
298 pLed->BlinkTimes = 2;
300 pLed->BlinkingLedState = RTW_LED_OFF;
302 pLed->BlinkingLedState = RTW_LED_ON;
303 schedule_delayed_work(&pLed->blink_work, LED_BLINK_FASTER_INTVL);
306 case LED_CTL_START_WPS: /* wait until xinpin finish */
307 if (!pLed->bLedWPSBlinkInProgress) {
308 if (pLed->bLedNoLinkBlinkInProgress) {
309 cancel_delayed_work(&pLed->blink_work);
310 pLed->bLedNoLinkBlinkInProgress = false;
312 if (pLed->bLedLinkBlinkInProgress) {
313 cancel_delayed_work(&pLed->blink_work);
314 pLed->bLedLinkBlinkInProgress = false;
316 if (pLed->bLedBlinkInProgress) {
317 cancel_delayed_work(&pLed->blink_work);
318 pLed->bLedBlinkInProgress = false;
320 if (pLed->bLedScanBlinkInProgress) {
321 cancel_delayed_work(&pLed->blink_work);
322 pLed->bLedScanBlinkInProgress = false;
324 pLed->bLedWPSBlinkInProgress = true;
325 pLed->CurrLedState = LED_BLINK_WPS;
327 pLed->BlinkingLedState = RTW_LED_OFF;
329 pLed->BlinkingLedState = RTW_LED_ON;
330 schedule_delayed_work(&pLed->blink_work, LED_BLINK_SCAN_INTVL);
333 case LED_CTL_STOP_WPS:
334 if (pLed->bLedNoLinkBlinkInProgress) {
335 cancel_delayed_work(&pLed->blink_work);
336 pLed->bLedNoLinkBlinkInProgress = false;
338 if (pLed->bLedLinkBlinkInProgress) {
339 cancel_delayed_work(&pLed->blink_work);
340 pLed->bLedLinkBlinkInProgress = false;
342 if (pLed->bLedBlinkInProgress) {
343 cancel_delayed_work(&pLed->blink_work);
344 pLed->bLedBlinkInProgress = false;
346 if (pLed->bLedScanBlinkInProgress) {
347 cancel_delayed_work(&pLed->blink_work);
348 pLed->bLedScanBlinkInProgress = false;
350 if (pLed->bLedWPSBlinkInProgress)
351 cancel_delayed_work(&pLed->blink_work);
353 pLed->bLedWPSBlinkInProgress = true;
354 pLed->CurrLedState = LED_BLINK_WPS_STOP;
356 pLed->BlinkingLedState = RTW_LED_OFF;
357 schedule_delayed_work(&pLed->blink_work, LED_BLINK_WPS_SUCESS_INTVL);
359 pLed->BlinkingLedState = RTW_LED_ON;
360 schedule_delayed_work(&pLed->blink_work, 0);
363 case LED_CTL_STOP_WPS_FAIL:
364 if (pLed->bLedWPSBlinkInProgress) {
365 cancel_delayed_work(&pLed->blink_work);
366 pLed->bLedWPSBlinkInProgress = false;
368 pLed->bLedNoLinkBlinkInProgress = true;
369 pLed->CurrLedState = LED_BLINK_SLOWLY;
371 pLed->BlinkingLedState = RTW_LED_OFF;
373 pLed->BlinkingLedState = RTW_LED_ON;
374 schedule_delayed_work(&pLed->blink_work, LED_BLINK_NO_LINK_INTVL);
376 case LED_CTL_POWER_OFF:
377 pLed->CurrLedState = RTW_LED_OFF;
378 pLed->BlinkingLedState = RTW_LED_OFF;
379 if (pLed->bLedNoLinkBlinkInProgress) {
380 cancel_delayed_work(&pLed->blink_work);
381 pLed->bLedNoLinkBlinkInProgress = false;
383 if (pLed->bLedLinkBlinkInProgress) {
384 cancel_delayed_work(&pLed->blink_work);
385 pLed->bLedLinkBlinkInProgress = false;
387 if (pLed->bLedBlinkInProgress) {
388 cancel_delayed_work(&pLed->blink_work);
389 pLed->bLedBlinkInProgress = false;
391 if (pLed->bLedWPSBlinkInProgress) {
392 cancel_delayed_work(&pLed->blink_work);
393 pLed->bLedWPSBlinkInProgress = false;
395 if (pLed->bLedScanBlinkInProgress) {
396 cancel_delayed_work(&pLed->blink_work);
397 pLed->bLedScanBlinkInProgress = false;
399 SwLedOff(padapter, pLed);