1 /*
2 *
3 * Copyright (c) 2004-2010 Atheros Communications Inc.
4 * All rights reserved.
5 *
6 *
7 //
8 // Permission to use, copy, modify, and/or distribute this software for any
9 // purpose with or without fee is hereby granted, provided that the above
10 // copyright notice and this permission notice appear in all copies.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 //
20 //
21 *
22 */
23
24 /*
25 * Implementation of system power management
26 */
27
28 #include "ar6000_drv.h"
29 #include <linux/inetdevice.h>
30 #include <linux/platform_device.h>
31 #include "wlan_config.h"
32
33 #define WOW_ENABLE_MAX_INTERVAL 0
34 #define WOW_SET_SCAN_PARAMS 0
35
36 extern unsigned int wmitimeout;
37 extern wait_queue_head_t arEvent;
38
39 #ifdef ANDROID_ENV
40 extern void android_ar6k_check_wow_status(struct ar6_softc *ar, struct sk_buff *skb, bool isEvent);
41 #endif
42 #undef ATH_MODULE_NAME
43 #define ATH_MODULE_NAME pm
44 #define ATH_DEBUG_PM ATH_DEBUG_MAKE_MODULE_MASK(0)
45
46 #ifdef DEBUG
47 static struct ath_debug_mask_description pm_debug_desc[] = {
48 { ATH_DEBUG_PM , "System power management"},
49 };
50
51 ATH_DEBUG_INSTANTIATE_MODULE_VAR(pm,
52 "pm",
53 "System Power Management",
54 ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_PM,
55 ATH_DEBUG_DESCRIPTION_COUNT(pm_debug_desc),
56 pm_debug_desc);
57
58 #endif /* DEBUG */
59
60 int ar6000_exit_cut_power_state(struct ar6_softc *ar);
61
62 #ifdef CONFIG_PM
ar6k_send_asleep_event_to_app(struct ar6_softc * ar,bool asleep)63 static void ar6k_send_asleep_event_to_app(struct ar6_softc *ar, bool asleep)
64 {
65 char buf[128];
66 union iwreq_data wrqu;
67
68 snprintf(buf, sizeof(buf), "HOST_ASLEEP=%s", asleep ? "asleep" : "awake");
69 A_MEMZERO(&wrqu, sizeof(wrqu));
70 wrqu.data.length = strlen(buf);
71 wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
72 }
73
ar6000_wow_resume(struct ar6_softc * ar)74 static void ar6000_wow_resume(struct ar6_softc *ar)
75 {
76 if (ar->arWowState!= WLAN_WOW_STATE_NONE) {
77 u16 fg_start_period = (ar->scParams.fg_start_period==0) ? 1 : ar->scParams.fg_start_period;
78 u16 bg_period = (ar->scParams.bg_period==0) ? 60 : ar->scParams.bg_period;
79 WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {true, false};
80 ar->arWowState = WLAN_WOW_STATE_NONE;
81 if (wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode)!= 0) {
82 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup restore host awake\n"));
83 }
84 #if WOW_SET_SCAN_PARAMS
85 wmi_scanparams_cmd(ar->arWmi, fg_start_period,
86 ar->scParams.fg_end_period,
87 bg_period,
88 ar->scParams.minact_chdwell_time,
89 ar->scParams.maxact_chdwell_time,
90 ar->scParams.pas_chdwell_time,
91 ar->scParams.shortScanRatio,
92 ar->scParams.scanCtrlFlags,
93 ar->scParams.max_dfsch_act_time,
94 ar->scParams.maxact_scan_per_ssid);
95 #else
96 (void)fg_start_period;
97 (void)bg_period;
98 #endif
99
100
101 #if WOW_ENABLE_MAX_INTERVAL /* we don't do it if the power consumption is already good enough. */
102 if (wmi_listeninterval_cmd(ar->arWmi, ar->arListenIntervalT, ar->arListenIntervalB) == 0) {
103 }
104 #endif
105 ar6k_send_asleep_event_to_app(ar, false);
106 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Resume WoW successfully\n"));
107 } else {
108 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WoW does not invoked. skip resume"));
109 }
110 ar->arWlanPowerState = WLAN_POWER_STATE_ON;
111 }
112
ar6000_wow_suspend(struct ar6_softc * ar)113 static void ar6000_wow_suspend(struct ar6_softc *ar)
114 {
115 #define WOW_LIST_ID 1
116 if (ar->arNetworkType != AP_NETWORK) {
117 /* Setup WoW for unicast & Arp request for our own IP
118 disable background scan. Set listen interval into 1000 TUs
119 Enable keepliave for 110 seconds
120 */
121 struct in_ifaddr **ifap = NULL;
122 struct in_ifaddr *ifa = NULL;
123 struct in_device *in_dev;
124 u8 macMask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
125 int status;
126 WMI_ADD_WOW_PATTERN_CMD addWowCmd = { .filter = { 0 } };
127 WMI_DEL_WOW_PATTERN_CMD delWowCmd;
128 WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {false, true};
129 WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = true,
130 .hostReqDelay = 500 };/*500 ms delay*/
131
132 if (ar->arWowState!= WLAN_WOW_STATE_NONE) {
133 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("System already go into wow mode!\n"));
134 return;
135 }
136
137 ar6000_TxDataCleanup(ar); /* IMPORTANT, otherwise there will be 11mA after listen interval as 1000*/
138
139 #if WOW_ENABLE_MAX_INTERVAL /* we don't do it if the power consumption is already good enough. */
140 if (wmi_listeninterval_cmd(ar->arWmi, A_MAX_WOW_LISTEN_INTERVAL, 0) == 0) {
141 }
142 #endif
143
144 #if WOW_SET_SCAN_PARAMS
145 status = wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0, 0, 0);
146 #endif
147 /* clear up our WoW pattern first */
148 delWowCmd.filter_list_id = WOW_LIST_ID;
149 delWowCmd.filter_id = 0;
150 wmi_del_wow_pattern_cmd(ar->arWmi, &delWowCmd);
151
152 /* setup unicast packet pattern for WoW */
153 if (ar->arNetDev->dev_addr[1]) {
154 addWowCmd.filter_list_id = WOW_LIST_ID;
155 addWowCmd.filter_size = 6; /* MAC address */
156 addWowCmd.filter_offset = 0;
157 status = wmi_add_wow_pattern_cmd(ar->arWmi, &addWowCmd, ar->arNetDev->dev_addr, macMask, addWowCmd.filter_size);
158 if (status) {
159 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to add WoW pattern\n"));
160 }
161 }
162 /* setup ARP request for our own IP */
163 if ((in_dev = __in_dev_get_rtnl(ar->arNetDev)) != NULL) {
164 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) {
165 if (!strcmp(ar->arNetDev->name, ifa->ifa_label)) {
166 break; /* found */
167 }
168 }
169 }
170 if (ifa && ifa->ifa_local) {
171 WMI_SET_IP_CMD ipCmd;
172 memset(&ipCmd, 0, sizeof(ipCmd));
173 ipCmd.ips[0] = ifa->ifa_local;
174 status = wmi_set_ip_cmd(ar->arWmi, &ipCmd);
175 if (status) {
176 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup IP for ARP agent\n"));
177 }
178 }
179
180 #ifndef ATH6K_CONFIG_OTA_MODE
181 wmi_powermode_cmd(ar->arWmi, REC_POWER);
182 #endif
183
184 status = wmi_set_wow_mode_cmd(ar->arWmi, &wowMode);
185 if (status) {
186 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to enable wow mode\n"));
187 }
188 ar6k_send_asleep_event_to_app(ar, true);
189
190 status = wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode);
191 if (status) {
192 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to set host asleep\n"));
193 }
194
195 ar->arWowState = WLAN_WOW_STATE_SUSPENDING;
196 if (ar->arTxPending[ar->arControlEp]) {
197 u32 timeleft = wait_event_interruptible_timeout(arEvent,
198 ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
199 if (!timeleft || signal_pending(current)) {
200 /* what can I do? wow resume at once */
201 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WoW. Pending wmi control data %d\n", ar->arTxPending[ar->arControlEp]));
202 }
203 }
204
205 status = hifWaitForPendingRecv(ar->arHifDevice);
206
207 ar->arWowState = WLAN_WOW_STATE_SUSPENDED;
208 ar->arWlanPowerState = WLAN_POWER_STATE_WOW;
209 } else {
210 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Not allowed to go to WOW at this moment.\n"));
211 }
212 }
213
ar6000_suspend_ev(void * context)214 int ar6000_suspend_ev(void *context)
215 {
216 int status = 0;
217 struct ar6_softc *ar = (struct ar6_softc *)context;
218 s16 pmmode = ar->arSuspendConfig;
219 wow_not_connected:
220 switch (pmmode) {
221 case WLAN_SUSPEND_WOW:
222 if (ar->arWmiReady && ar->arWlanState==WLAN_ENABLED && ar->arConnected) {
223 ar6000_wow_suspend(ar);
224 AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Suspend for wow mode %d\n", __func__, ar->arWlanPowerState));
225 } else {
226 pmmode = ar->arWow2Config;
227 goto wow_not_connected;
228 }
229 break;
230 case WLAN_SUSPEND_CUT_PWR:
231 /* fall through */
232 case WLAN_SUSPEND_CUT_PWR_IF_BT_OFF:
233 /* fall through */
234 case WLAN_SUSPEND_DEEP_SLEEP:
235 /* fall through */
236 default:
237 status = ar6000_update_wlan_pwr_state(ar, WLAN_DISABLED, true);
238 if (ar->arWlanPowerState==WLAN_POWER_STATE_ON ||
239 ar->arWlanPowerState==WLAN_POWER_STATE_WOW) {
240 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Strange suspend state for not wow mode %d", ar->arWlanPowerState));
241 }
242 AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Suspend for %d mode pwr %d status %d\n", __func__, pmmode, ar->arWlanPowerState, status));
243 status = (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) ? 0 : A_EBUSY;
244 break;
245 }
246
247 ar->scan_triggered = 0;
248 return status;
249 }
250
ar6000_resume_ev(void * context)251 int ar6000_resume_ev(void *context)
252 {
253 struct ar6_softc *ar = (struct ar6_softc *)context;
254 u16 powerState = ar->arWlanPowerState;
255
256 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: enter previous state %d wowState %d\n", __func__, powerState, ar->arWowState));
257 switch (powerState) {
258 case WLAN_POWER_STATE_WOW:
259 ar6000_wow_resume(ar);
260 break;
261 case WLAN_POWER_STATE_CUT_PWR:
262 /* fall through */
263 case WLAN_POWER_STATE_DEEP_SLEEP:
264 ar6000_update_wlan_pwr_state(ar, WLAN_ENABLED, true);
265 AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Resume for %d mode pwr %d\n", __func__, powerState, ar->arWlanPowerState));
266 break;
267 case WLAN_POWER_STATE_ON:
268 break;
269 default:
270 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange SDIO bus power mode!!\n"));
271 break;
272 }
273 return 0;
274 }
275
ar6000_check_wow_status(struct ar6_softc * ar,struct sk_buff * skb,bool isEvent)276 void ar6000_check_wow_status(struct ar6_softc *ar, struct sk_buff *skb, bool isEvent)
277 {
278 if (ar->arWowState!=WLAN_WOW_STATE_NONE) {
279 if (ar->arWowState==WLAN_WOW_STATE_SUSPENDING) {
280 AR_DEBUG_PRINTF(ATH_DEBUG_PM,("\n%s: Received IRQ while we are wow suspending!!!\n\n", __func__));
281 return;
282 }
283 /* Wow resume from irq interrupt */
284 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: WoW resume from irq thread status %d\n", __func__, ar->arWlanPowerState));
285 ar6000_wow_resume(ar);
286 } else {
287 #ifdef ANDROID_ENV
288 android_ar6k_check_wow_status(ar, skb, isEvent);
289 #endif
290 }
291 }
292
ar6000_power_change_ev(void * context,u32 config)293 int ar6000_power_change_ev(void *context, u32 config)
294 {
295 struct ar6_softc *ar = (struct ar6_softc *)context;
296 int status = 0;
297
298 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: power change event callback %d \n", __func__, config));
299 switch (config) {
300 case HIF_DEVICE_POWER_UP:
301 ar6000_restart_endpoint(ar->arNetDev);
302 status = 0;
303 break;
304 case HIF_DEVICE_POWER_DOWN:
305 case HIF_DEVICE_POWER_CUT:
306 status = 0;
307 break;
308 }
309 return status;
310 }
311
ar6000_pm_probe(struct platform_device * pdev)312 static int ar6000_pm_probe(struct platform_device *pdev)
313 {
314 plat_setup_power(1,1);
315 return 0;
316 }
317
ar6000_pm_remove(struct platform_device * pdev)318 static int ar6000_pm_remove(struct platform_device *pdev)
319 {
320 plat_setup_power(0,1);
321 return 0;
322 }
323
ar6000_pm_suspend(struct platform_device * pdev,pm_message_t state)324 static int ar6000_pm_suspend(struct platform_device *pdev, pm_message_t state)
325 {
326 return 0;
327 }
328
ar6000_pm_resume(struct platform_device * pdev)329 static int ar6000_pm_resume(struct platform_device *pdev)
330 {
331 return 0;
332 }
333
334 static struct platform_driver ar6000_pm_device = {
335 .probe = ar6000_pm_probe,
336 .remove = ar6000_pm_remove,
337 .suspend = ar6000_pm_suspend,
338 .resume = ar6000_pm_resume,
339 .driver = {
340 .name = "wlan_ar6000_pm",
341 },
342 };
343 #endif /* CONFIG_PM */
344
345 int
ar6000_setup_cut_power_state(struct ar6_softc * ar,AR6000_WLAN_STATE state)346 ar6000_setup_cut_power_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
347 {
348 int status = 0;
349 HIF_DEVICE_POWER_CHANGE_TYPE config;
350
351 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: Cut power %d %d \n", __func__,state, ar->arWlanPowerState));
352 #ifdef CONFIG_PM
353 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Wlan OFF %d BT OFf %d \n", ar->arWlanOff, ar->arBTOff));
354 #endif
355 do {
356 if (state == WLAN_ENABLED) {
357 /* Not in cut power state.. exit */
358 if (ar->arWlanPowerState != WLAN_POWER_STATE_CUT_PWR) {
359 break;
360 }
361
362 plat_setup_power(1,0);
363
364 /* Change the state to ON */
365 ar->arWlanPowerState = WLAN_POWER_STATE_ON;
366
367
368 /* Indicate POWER_UP to HIF */
369 config = HIF_DEVICE_POWER_UP;
370 status = HIFConfigureDevice(ar->arHifDevice,
371 HIF_DEVICE_POWER_STATE_CHANGE,
372 &config,
373 sizeof(HIF_DEVICE_POWER_CHANGE_TYPE));
374
375 if (status == A_PENDING) {
376 #ifdef ANDROID_ENV
377 /* Wait for WMI ready event */
378 u32 timeleft = wait_event_interruptible_timeout(arEvent,
379 (ar->arWmiReady == true), wmitimeout * HZ);
380 if (!timeleft || signal_pending(current)) {
381 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000 : Failed to get wmi ready \n"));
382 status = A_ERROR;
383 break;
384 }
385 #endif
386 status = 0;
387 } else if (status == 0) {
388 ar6000_restart_endpoint(ar->arNetDev);
389 status = 0;
390 }
391 } else if (state == WLAN_DISABLED) {
392
393
394 /* Already in cut power state.. exit */
395 if (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) {
396 break;
397 }
398 ar6000_stop_endpoint(ar->arNetDev, true, false);
399
400 config = HIF_DEVICE_POWER_CUT;
401 status = HIFConfigureDevice(ar->arHifDevice,
402 HIF_DEVICE_POWER_STATE_CHANGE,
403 &config,
404 sizeof(HIF_DEVICE_POWER_CHANGE_TYPE));
405
406 plat_setup_power(0,0);
407
408 ar->arWlanPowerState = WLAN_POWER_STATE_CUT_PWR;
409 }
410 } while (0);
411
412 return status;
413 }
414
415 int
ar6000_setup_deep_sleep_state(struct ar6_softc * ar,AR6000_WLAN_STATE state)416 ar6000_setup_deep_sleep_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
417 {
418 int status = 0;
419
420 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: Deep sleep %d %d \n", __func__,state, ar->arWlanPowerState));
421 #ifdef CONFIG_PM
422 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Wlan OFF %d BT OFf %d \n", ar->arWlanOff, ar->arBTOff));
423 #endif
424 do {
425 WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode;
426
427 if (state == WLAN_ENABLED) {
428 u16 fg_start_period;
429
430 /* Not in deep sleep state.. exit */
431 if (ar->arWlanPowerState != WLAN_POWER_STATE_DEEP_SLEEP) {
432 if (ar->arWlanPowerState != WLAN_POWER_STATE_ON) {
433 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange state when we resume from deep sleep %d\n", ar->arWlanPowerState));
434 }
435 break;
436 }
437
438 fg_start_period = (ar->scParams.fg_start_period==0) ? 1 : ar->scParams.fg_start_period;
439 hostSleepMode.awake = true;
440 hostSleepMode.asleep = false;
441
442 if ((status=wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode)) != 0) {
443 break;
444 }
445
446 /* Change the state to ON */
447 ar->arWlanPowerState = WLAN_POWER_STATE_ON;
448
449 /* Enable foreground scanning */
450 if ((status=wmi_scanparams_cmd(ar->arWmi, fg_start_period,
451 ar->scParams.fg_end_period,
452 ar->scParams.bg_period,
453 ar->scParams.minact_chdwell_time,
454 ar->scParams.maxact_chdwell_time,
455 ar->scParams.pas_chdwell_time,
456 ar->scParams.shortScanRatio,
457 ar->scParams.scanCtrlFlags,
458 ar->scParams.max_dfsch_act_time,
459 ar->scParams.maxact_scan_per_ssid)) != 0)
460 {
461 break;
462 }
463
464 if (ar->arNetworkType != AP_NETWORK)
465 {
466 if (ar->arSsidLen) {
467 if (ar6000_connect_to_ap(ar) != 0) {
468 /* no need to report error if connection failed */
469 break;
470 }
471 }
472 }
473 } else if (state == WLAN_DISABLED){
474 WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = false };
475
476 /* Already in deep sleep state.. exit */
477 if (ar->arWlanPowerState != WLAN_POWER_STATE_ON) {
478 if (ar->arWlanPowerState != WLAN_POWER_STATE_DEEP_SLEEP) {
479 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange state when we suspend for deep sleep %d\n", ar->arWlanPowerState));
480 }
481 break;
482 }
483
484 if (ar->arNetworkType != AP_NETWORK)
485 {
486 /* Disconnect from the AP and disable foreground scanning */
487 AR6000_SPIN_LOCK(&ar->arLock, 0);
488 if (ar->arConnected == true || ar->arConnectPending == true) {
489 AR6000_SPIN_UNLOCK(&ar->arLock, 0);
490 wmi_disconnect_cmd(ar->arWmi);
491 } else {
492 AR6000_SPIN_UNLOCK(&ar->arLock, 0);
493 }
494 }
495
496 ar->scan_triggered = 0;
497
498 if ((status=wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0)) != 0) {
499 break;
500 }
501
502 /* make sure we disable wow for deep sleep */
503 if ((status=wmi_set_wow_mode_cmd(ar->arWmi, &wowMode))!= 0)
504 {
505 break;
506 }
507
508 ar6000_TxDataCleanup(ar);
509 #ifndef ATH6K_CONFIG_OTA_MODE
510 wmi_powermode_cmd(ar->arWmi, REC_POWER);
511 #endif
512
513 hostSleepMode.awake = false;
514 hostSleepMode.asleep = true;
515 if ((status=wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode))!= 0) {
516 break;
517 }
518 if (ar->arTxPending[ar->arControlEp]) {
519 u32 timeleft = wait_event_interruptible_timeout(arEvent,
520 ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
521 if (!timeleft || signal_pending(current)) {
522 status = A_ERROR;
523 break;
524 }
525 }
526 status = hifWaitForPendingRecv(ar->arHifDevice);
527
528 ar->arWlanPowerState = WLAN_POWER_STATE_DEEP_SLEEP;
529 }
530 } while (0);
531
532 if (status) {
533 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to enter/exit deep sleep %d\n", state));
534 }
535
536 return status;
537 }
538
539 int
ar6000_update_wlan_pwr_state(struct ar6_softc * ar,AR6000_WLAN_STATE state,bool pmEvent)540 ar6000_update_wlan_pwr_state(struct ar6_softc *ar, AR6000_WLAN_STATE state, bool pmEvent)
541 {
542 int status = 0;
543 u16 powerState, oldPowerState;
544 AR6000_WLAN_STATE oldstate = ar->arWlanState;
545 bool wlanOff = ar->arWlanOff;
546 #ifdef CONFIG_PM
547 bool btOff = ar->arBTOff;
548 #endif /* CONFIG_PM */
549
550 if ((state!=WLAN_DISABLED && state!=WLAN_ENABLED)) {
551 return A_ERROR;
552 }
553
554 if (ar->bIsDestroyProgress) {
555 return A_EBUSY;
556 }
557
558 if (down_interruptible(&ar->arSem)) {
559 return A_ERROR;
560 }
561
562 if (ar->bIsDestroyProgress) {
563 up(&ar->arSem);
564 return A_EBUSY;
565 }
566
567 ar->arWlanState = wlanOff ? WLAN_DISABLED : state;
568 oldPowerState = ar->arWlanPowerState;
569 if (state == WLAN_ENABLED) {
570 powerState = ar->arWlanPowerState;
571 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WLAN PWR set to ENABLE^^\n"));
572 if (!wlanOff) {
573 if (powerState == WLAN_POWER_STATE_DEEP_SLEEP) {
574 status = ar6000_setup_deep_sleep_state(ar, WLAN_ENABLED);
575 } else if (powerState == WLAN_POWER_STATE_CUT_PWR) {
576 status = ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
577 }
578 }
579 #ifdef CONFIG_PM
580 else if (pmEvent && wlanOff) {
581 bool allowCutPwr = ((!ar->arBTSharing) || btOff);
582 if ((powerState==WLAN_POWER_STATE_CUT_PWR) && (!allowCutPwr)) {
583 /* Come out of cut power */
584 ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
585 status = ar6000_setup_deep_sleep_state(ar, WLAN_DISABLED);
586 }
587 }
588 #endif /* CONFIG_PM */
589 } else if (state == WLAN_DISABLED) {
590 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WLAN PWR set to DISABLED~\n"));
591 powerState = WLAN_POWER_STATE_DEEP_SLEEP;
592 #ifdef CONFIG_PM
593 if (pmEvent) { /* disable due to suspend */
594 bool suspendCutPwr = (ar->arSuspendConfig == WLAN_SUSPEND_CUT_PWR ||
595 (ar->arSuspendConfig == WLAN_SUSPEND_WOW &&
596 ar->arWow2Config==WLAN_SUSPEND_CUT_PWR));
597 bool suspendCutIfBtOff = ((ar->arSuspendConfig ==
598 WLAN_SUSPEND_CUT_PWR_IF_BT_OFF ||
599 (ar->arSuspendConfig == WLAN_SUSPEND_WOW &&
600 ar->arWow2Config==WLAN_SUSPEND_CUT_PWR_IF_BT_OFF)) &&
601 (!ar->arBTSharing || btOff));
602 if ((suspendCutPwr) ||
603 (suspendCutIfBtOff) ||
604 (ar->arWlanState==WLAN_POWER_STATE_CUT_PWR))
605 {
606 powerState = WLAN_POWER_STATE_CUT_PWR;
607 }
608 } else {
609 if ((wlanOff) &&
610 (ar->arWlanOffConfig == WLAN_OFF_CUT_PWR) &&
611 (!ar->arBTSharing || btOff))
612 {
613 /* For BT clock sharing designs, CUT_POWER depend on BT state */
614 powerState = WLAN_POWER_STATE_CUT_PWR;
615 }
616 }
617 #endif /* CONFIG_PM */
618
619 if (powerState == WLAN_POWER_STATE_DEEP_SLEEP) {
620 if (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) {
621 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Load firmware before set to deep sleep\n"));
622 ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
623 }
624 status = ar6000_setup_deep_sleep_state(ar, WLAN_DISABLED);
625 } else if (powerState == WLAN_POWER_STATE_CUT_PWR) {
626 status = ar6000_setup_cut_power_state(ar, WLAN_DISABLED);
627 }
628
629 }
630
631 if (status) {
632 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WLAN state %d\n", ar->arWlanState));
633 ar->arWlanState = oldstate;
634 } else if (status == 0) {
635 WMI_REPORT_SLEEP_STATE_EVENT wmiSleepEvent, *pSleepEvent = NULL;
636 if ((ar->arWlanPowerState == WLAN_POWER_STATE_ON) && (oldPowerState != WLAN_POWER_STATE_ON)) {
637 wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_AWAKE;
638 pSleepEvent = &wmiSleepEvent;
639 } else if ((ar->arWlanPowerState != WLAN_POWER_STATE_ON) && (oldPowerState == WLAN_POWER_STATE_ON)) {
640 wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP;
641 pSleepEvent = &wmiSleepEvent;
642 }
643 if (pSleepEvent) {
644 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("SENT WLAN Sleep Event %d\n", wmiSleepEvent.sleepState));
645 ar6000_send_event_to_app(ar, WMI_REPORT_SLEEP_STATE_EVENTID, (u8 *)pSleepEvent,
646 sizeof(WMI_REPORT_SLEEP_STATE_EVENTID));
647 }
648 }
649 up(&ar->arSem);
650 return status;
651 }
652
653 int
ar6000_set_bt_hw_state(struct ar6_softc * ar,u32 enable)654 ar6000_set_bt_hw_state(struct ar6_softc *ar, u32 enable)
655 {
656 #ifdef CONFIG_PM
657 bool off = (enable == 0);
658 int status;
659 if (ar->arBTOff == off) {
660 return 0;
661 }
662 ar->arBTOff = off;
663 status = ar6000_update_wlan_pwr_state(ar, ar->arWlanOff ? WLAN_DISABLED : WLAN_ENABLED, false);
664 return status;
665 #else
666 return 0;
667 #endif
668 }
669
670 int
ar6000_set_wlan_state(struct ar6_softc * ar,AR6000_WLAN_STATE state)671 ar6000_set_wlan_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
672 {
673 int status;
674 bool off = (state == WLAN_DISABLED);
675 if (ar->arWlanOff == off) {
676 return 0;
677 }
678 ar->arWlanOff = off;
679 status = ar6000_update_wlan_pwr_state(ar, state, false);
680 return status;
681 }
682
ar6000_pm_init()683 void ar6000_pm_init()
684 {
685 A_REGISTER_MODULE_DEBUG_INFO(pm);
686 #ifdef CONFIG_PM
687 /*
688 * Register ar6000_pm_device into system.
689 * We should also add platform_device into the first item of array
690 * of devices[] in file arch/xxx/mach-xxx/board-xxxx.c
691 */
692 if (platform_driver_register(&ar6000_pm_device)) {
693 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000: fail to register the power control driver.\n"));
694 }
695 #endif /* CONFIG_PM */
696 }
697
ar6000_pm_exit()698 void ar6000_pm_exit()
699 {
700 #ifdef CONFIG_PM
701 platform_driver_unregister(&ar6000_pm_device);
702 #endif /* CONFIG_PM */
703 }
704