Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
[pandora-kernel.git] / drivers / staging / ath6kl / os / linux / ar6000_pm.c
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 #undef ATH_MODULE_NAME
40 #define ATH_MODULE_NAME pm
41 #define  ATH_DEBUG_PM       ATH_DEBUG_MAKE_MODULE_MASK(0)
42
43 #ifdef DEBUG
44 static struct ath_debug_mask_description pm_debug_desc[] = {
45     { ATH_DEBUG_PM     , "System power management"},
46 };
47
48 ATH_DEBUG_INSTANTIATE_MODULE_VAR(pm,
49                                  "pm",
50                                  "System Power Management",
51                                  ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_PM,
52                                  ATH_DEBUG_DESCRIPTION_COUNT(pm_debug_desc),
53                                  pm_debug_desc);
54
55 #endif /* DEBUG */
56
57 int ar6000_exit_cut_power_state(struct ar6_softc *ar);
58
59 #ifdef CONFIG_PM
60 static void ar6k_send_asleep_event_to_app(struct ar6_softc *ar, bool asleep)
61 {
62     char buf[128];
63     union iwreq_data wrqu;
64
65     snprintf(buf, sizeof(buf), "HOST_ASLEEP=%s", asleep ? "asleep" : "awake");
66     A_MEMZERO(&wrqu, sizeof(wrqu));
67     wrqu.data.length = strlen(buf);
68     wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
69 }
70
71 static void ar6000_wow_resume(struct ar6_softc *ar)
72 {
73     if (ar->arWowState!= WLAN_WOW_STATE_NONE) {
74         u16 fg_start_period = (ar->scParams.fg_start_period==0) ? 1 : ar->scParams.fg_start_period;
75         u16 bg_period = (ar->scParams.bg_period==0) ? 60 : ar->scParams.bg_period;
76         WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {true, false};
77         ar->arWowState = WLAN_WOW_STATE_NONE;
78         if (wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode)!= 0) {
79             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup restore host awake\n"));
80         }
81 #if WOW_SET_SCAN_PARAMS
82         wmi_scanparams_cmd(ar->arWmi, fg_start_period,
83                                    ar->scParams.fg_end_period,
84                                    bg_period,
85                                    ar->scParams.minact_chdwell_time,
86                                    ar->scParams.maxact_chdwell_time,
87                                    ar->scParams.pas_chdwell_time,
88                                    ar->scParams.shortScanRatio,
89                                    ar->scParams.scanCtrlFlags,
90                                    ar->scParams.max_dfsch_act_time,
91                                    ar->scParams.maxact_scan_per_ssid);
92 #else
93        (void)fg_start_period;
94        (void)bg_period;
95 #endif
96
97
98 #if WOW_ENABLE_MAX_INTERVAL /* we don't do it if the power consumption is already good enough. */
99         if (wmi_listeninterval_cmd(ar->arWmi, ar->arListenIntervalT, ar->arListenIntervalB) == 0) {
100         }
101 #endif
102         ar6k_send_asleep_event_to_app(ar, false);
103         AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Resume WoW successfully\n"));
104     } else {
105         AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WoW does not invoked. skip resume"));
106     }
107     ar->arWlanPowerState = WLAN_POWER_STATE_ON;
108 }
109
110 static void ar6000_wow_suspend(struct ar6_softc *ar)
111 {
112 #define WOW_LIST_ID 1
113     if (ar->arNetworkType != AP_NETWORK) {
114         /* Setup WoW for unicast & Arp request for our own IP
115         disable background scan. Set listen interval into 1000 TUs
116         Enable keepliave for 110 seconds
117         */
118         struct in_ifaddr **ifap = NULL;
119         struct in_ifaddr *ifa = NULL;
120         struct in_device *in_dev;
121         u8 macMask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
122         int status;
123         WMI_ADD_WOW_PATTERN_CMD addWowCmd = { .filter = { 0 } };
124         WMI_DEL_WOW_PATTERN_CMD delWowCmd;
125         WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {false, true};
126         WMI_SET_WOW_MODE_CMD wowMode = {    .enable_wow = true,
127                                             .hostReqDelay = 500 };/*500 ms delay*/
128
129         if (ar->arWowState!= WLAN_WOW_STATE_NONE) {
130             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("System already go into wow mode!\n"));
131             return;
132         }
133
134         ar6000_TxDataCleanup(ar); /* IMPORTANT, otherwise there will be 11mA after listen interval as 1000*/
135
136 #if WOW_ENABLE_MAX_INTERVAL /* we don't do it if the power consumption is already good enough. */
137         if (wmi_listeninterval_cmd(ar->arWmi, A_MAX_WOW_LISTEN_INTERVAL, 0) == 0) {
138         }
139 #endif
140
141 #if WOW_SET_SCAN_PARAMS
142         status = wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0, 0, 0);
143 #endif
144         /* clear up our WoW pattern first */
145         delWowCmd.filter_list_id = WOW_LIST_ID;
146         delWowCmd.filter_id = 0;
147         wmi_del_wow_pattern_cmd(ar->arWmi, &delWowCmd);
148
149         /* setup unicast packet pattern for WoW */
150         if (ar->arNetDev->dev_addr[1]) {
151             addWowCmd.filter_list_id = WOW_LIST_ID;
152             addWowCmd.filter_size = 6; /* MAC address */
153             addWowCmd.filter_offset = 0;
154             status = wmi_add_wow_pattern_cmd(ar->arWmi, &addWowCmd, ar->arNetDev->dev_addr, macMask, addWowCmd.filter_size);
155             if (status) {
156                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to add WoW pattern\n"));
157             }
158         }
159         /* setup ARP request for our own IP */
160         if ((in_dev = __in_dev_get_rtnl(ar->arNetDev)) != NULL) {
161             for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) {
162                 if (!strcmp(ar->arNetDev->name, ifa->ifa_label)) {
163                     break; /* found */
164                 }
165             }
166         }
167         if (ifa && ifa->ifa_local) {
168             WMI_SET_IP_CMD ipCmd;
169             memset(&ipCmd, 0, sizeof(ipCmd));
170             ipCmd.ips[0] = ifa->ifa_local;
171             status = wmi_set_ip_cmd(ar->arWmi, &ipCmd);
172             if (status) {
173                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup IP for ARP agent\n"));
174             }
175         }
176
177 #ifndef ATH6K_CONFIG_OTA_MODE
178         wmi_powermode_cmd(ar->arWmi, REC_POWER);
179 #endif
180
181         status = wmi_set_wow_mode_cmd(ar->arWmi, &wowMode);
182         if (status) {
183             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to enable wow mode\n"));
184         }
185         ar6k_send_asleep_event_to_app(ar, true);
186
187         status = wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode);
188         if (status) {
189             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to set host asleep\n"));
190         }
191
192         ar->arWowState = WLAN_WOW_STATE_SUSPENDING;
193         if (ar->arTxPending[ar->arControlEp]) {
194             u32 timeleft = wait_event_interruptible_timeout(arEvent,
195             ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
196             if (!timeleft || signal_pending(current)) {
197                /* what can I do? wow resume at once */
198                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WoW. Pending wmi control data %d\n", ar->arTxPending[ar->arControlEp]));
199             }
200         }
201
202         status = hifWaitForPendingRecv(ar->arHifDevice);
203
204         ar->arWowState = WLAN_WOW_STATE_SUSPENDED;
205         ar->arWlanPowerState = WLAN_POWER_STATE_WOW;
206     } else {
207         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Not allowed to go to WOW at this moment.\n"));
208     }
209 }
210
211 int ar6000_suspend_ev(void *context)
212 {
213     int status = 0;
214     struct ar6_softc *ar = (struct ar6_softc *)context;
215     s16 pmmode = ar->arSuspendConfig;
216 wow_not_connected:
217     switch (pmmode) {
218     case WLAN_SUSPEND_WOW:
219         if (ar->arWmiReady && ar->arWlanState==WLAN_ENABLED && ar->arConnected) {
220             ar6000_wow_suspend(ar);
221             AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Suspend for wow mode %d\n", __func__, ar->arWlanPowerState));
222         } else {
223             pmmode = ar->arWow2Config;
224             goto wow_not_connected;
225         }
226         break;
227     case WLAN_SUSPEND_CUT_PWR:
228         /* fall through */
229     case WLAN_SUSPEND_CUT_PWR_IF_BT_OFF:
230         /* fall through */
231     case WLAN_SUSPEND_DEEP_SLEEP:
232         /* fall through */
233     default:
234         status = ar6000_update_wlan_pwr_state(ar, WLAN_DISABLED, true);
235         if (ar->arWlanPowerState==WLAN_POWER_STATE_ON ||
236             ar->arWlanPowerState==WLAN_POWER_STATE_WOW) {
237             AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Strange suspend state for not wow mode %d", ar->arWlanPowerState));
238         }
239         AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Suspend for %d mode pwr %d status %d\n", __func__, pmmode, ar->arWlanPowerState, status));
240         status = (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) ? 0 : A_EBUSY;
241         break;
242     }
243
244     ar->scan_triggered = 0;
245     return status;
246 }
247
248 int ar6000_resume_ev(void *context)
249 {
250     struct ar6_softc *ar = (struct ar6_softc *)context;
251     u16 powerState = ar->arWlanPowerState;
252
253     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: enter previous state %d wowState %d\n", __func__, powerState, ar->arWowState));
254     switch (powerState) {
255     case WLAN_POWER_STATE_WOW:
256         ar6000_wow_resume(ar);
257         break;
258     case WLAN_POWER_STATE_CUT_PWR:
259         /* fall through */
260     case WLAN_POWER_STATE_DEEP_SLEEP:
261         ar6000_update_wlan_pwr_state(ar, WLAN_ENABLED, true);
262         AR_DEBUG_PRINTF(ATH_DEBUG_PM,("%s:Resume for %d mode pwr %d\n", __func__, powerState, ar->arWlanPowerState));
263         break;
264     case WLAN_POWER_STATE_ON:
265         break;
266     default:
267         AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange SDIO bus power mode!!\n"));
268         break;
269     }
270     return 0;
271 }
272
273 void ar6000_check_wow_status(struct ar6_softc *ar, struct sk_buff *skb, bool isEvent)
274 {
275     if (ar->arWowState!=WLAN_WOW_STATE_NONE) {
276         if (ar->arWowState==WLAN_WOW_STATE_SUSPENDING) {
277             AR_DEBUG_PRINTF(ATH_DEBUG_PM,("\n%s: Received IRQ while we are wow suspending!!!\n\n", __func__));
278             return;
279         }
280         /* Wow resume from irq interrupt */
281         AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: WoW resume from irq thread status %d\n", __func__, ar->arWlanPowerState));
282         ar6000_wow_resume(ar);
283     }
284 }
285
286 int ar6000_power_change_ev(void *context, u32 config)
287 {
288     struct ar6_softc *ar = (struct ar6_softc *)context;
289     int status = 0;
290
291     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: power change event callback %d \n", __func__, config));
292     switch (config) {
293        case HIF_DEVICE_POWER_UP:
294             ar6000_restart_endpoint(ar->arNetDev);
295             status = 0;
296             break;
297        case HIF_DEVICE_POWER_DOWN:
298        case HIF_DEVICE_POWER_CUT:
299             status = 0;
300             break;
301     }
302     return status;
303 }
304
305 #endif /* CONFIG_PM */
306
307 int
308 ar6000_setup_cut_power_state(struct ar6_softc *ar,  AR6000_WLAN_STATE state)
309 {
310     int                      status = 0;
311     HIF_DEVICE_POWER_CHANGE_TYPE  config;
312
313     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: Cut power %d %d \n", __func__,state, ar->arWlanPowerState));
314 #ifdef CONFIG_PM
315     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Wlan OFF %d BT OFf %d \n", ar->arWlanOff, ar->arBTOff));
316 #endif
317     do {
318         if (state == WLAN_ENABLED) {
319             /* Not in cut power state.. exit */
320             if (ar->arWlanPowerState != WLAN_POWER_STATE_CUT_PWR) {
321                 break;
322             }
323
324             /* Change the state to ON */
325             ar->arWlanPowerState = WLAN_POWER_STATE_ON;
326
327
328             /* Indicate POWER_UP to HIF */
329             config = HIF_DEVICE_POWER_UP;
330             status = HIFConfigureDevice(ar->arHifDevice,
331                                 HIF_DEVICE_POWER_STATE_CHANGE,
332                                 &config,
333                                 sizeof(HIF_DEVICE_POWER_CHANGE_TYPE));
334
335             if (status == A_PENDING) {
336             } else if (status == 0) {
337                 ar6000_restart_endpoint(ar->arNetDev);
338                 status = 0;
339             }
340         } else if (state == WLAN_DISABLED) {
341
342
343             /* Already in cut power state.. exit */
344             if (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) {
345                 break;
346             }
347             ar6000_stop_endpoint(ar->arNetDev, true, false);
348
349             config = HIF_DEVICE_POWER_CUT;
350             status = HIFConfigureDevice(ar->arHifDevice,
351                                 HIF_DEVICE_POWER_STATE_CHANGE,
352                                 &config,
353                                 sizeof(HIF_DEVICE_POWER_CHANGE_TYPE));
354
355             ar->arWlanPowerState = WLAN_POWER_STATE_CUT_PWR;
356         }
357     } while (0);
358
359     return status;
360 }
361
362 int
363 ar6000_setup_deep_sleep_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
364 {
365     int status = 0;
366
367     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: Deep sleep %d %d \n", __func__,state, ar->arWlanPowerState));
368 #ifdef CONFIG_PM
369     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Wlan OFF %d BT OFf %d \n", ar->arWlanOff, ar->arBTOff));
370 #endif
371     do {
372         WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode;
373
374         if (state == WLAN_ENABLED) {
375             u16 fg_start_period;
376
377             /* Not in deep sleep state.. exit */
378             if (ar->arWlanPowerState != WLAN_POWER_STATE_DEEP_SLEEP) {
379                 if (ar->arWlanPowerState != WLAN_POWER_STATE_ON) {
380                     AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange state when we resume from deep sleep %d\n", ar->arWlanPowerState));
381                 }
382                 break;
383             }
384
385             fg_start_period = (ar->scParams.fg_start_period==0) ? 1 : ar->scParams.fg_start_period;
386             hostSleepMode.awake = true;
387             hostSleepMode.asleep = false;
388
389             if ((status=wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode)) != 0) {
390                 break;
391             }
392
393             /* Change the state to ON */
394             ar->arWlanPowerState = WLAN_POWER_STATE_ON;
395
396                 /* Enable foreground scanning */
397                 if ((status=wmi_scanparams_cmd(ar->arWmi, fg_start_period,
398                                         ar->scParams.fg_end_period,
399                                         ar->scParams.bg_period,
400                                         ar->scParams.minact_chdwell_time,
401                                         ar->scParams.maxact_chdwell_time,
402                                         ar->scParams.pas_chdwell_time,
403                                         ar->scParams.shortScanRatio,
404                                         ar->scParams.scanCtrlFlags,
405                                         ar->scParams.max_dfsch_act_time,
406                                         ar->scParams.maxact_scan_per_ssid)) != 0)
407                 {
408                     break;
409                 }
410
411             if (ar->arNetworkType != AP_NETWORK)
412             {
413                 if (ar->arSsidLen) {
414                     if (ar6000_connect_to_ap(ar) != 0) {
415                         /* no need to report error if connection failed */
416                         break;
417                     }
418                 }
419             }
420         } else if (state == WLAN_DISABLED){
421             WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = false };
422
423             /* Already in deep sleep state.. exit */
424             if (ar->arWlanPowerState != WLAN_POWER_STATE_ON) {
425                 if (ar->arWlanPowerState != WLAN_POWER_STATE_DEEP_SLEEP) {
426                     AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange state when we suspend for deep sleep %d\n", ar->arWlanPowerState));
427                 }
428                 break;
429             }
430
431             if (ar->arNetworkType != AP_NETWORK)
432             {
433                 /* Disconnect from the AP and disable foreground scanning */
434                 AR6000_SPIN_LOCK(&ar->arLock, 0);
435                 if (ar->arConnected == true || ar->arConnectPending == true) {
436                     AR6000_SPIN_UNLOCK(&ar->arLock, 0);
437                     wmi_disconnect_cmd(ar->arWmi);
438                 } else {
439                     AR6000_SPIN_UNLOCK(&ar->arLock, 0);
440                 }
441             }
442
443             ar->scan_triggered = 0;
444
445             if ((status=wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0)) != 0) {
446                 break;
447             }
448
449             /* make sure we disable wow for deep sleep */
450             if ((status=wmi_set_wow_mode_cmd(ar->arWmi, &wowMode))!= 0)
451             {
452                 break;
453             }
454
455             ar6000_TxDataCleanup(ar);
456 #ifndef ATH6K_CONFIG_OTA_MODE
457             wmi_powermode_cmd(ar->arWmi, REC_POWER);
458 #endif
459
460             hostSleepMode.awake = false;
461             hostSleepMode.asleep = true;
462             if ((status=wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode))!= 0) {
463                 break;
464             }
465             if (ar->arTxPending[ar->arControlEp]) {
466                 u32 timeleft = wait_event_interruptible_timeout(arEvent,
467                                 ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
468                 if (!timeleft || signal_pending(current)) {
469                     status = A_ERROR;
470                     break;
471                 }
472             }
473             status = hifWaitForPendingRecv(ar->arHifDevice);
474
475             ar->arWlanPowerState = WLAN_POWER_STATE_DEEP_SLEEP;
476         }
477     } while (0);
478
479     if (status) {
480         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to enter/exit deep sleep %d\n", state));
481     }
482
483     return status;
484 }
485
486 int
487 ar6000_update_wlan_pwr_state(struct ar6_softc *ar, AR6000_WLAN_STATE state, bool pmEvent)
488 {
489     int status = 0;
490     u16 powerState, oldPowerState;
491     AR6000_WLAN_STATE oldstate = ar->arWlanState;
492     bool wlanOff = ar->arWlanOff;
493 #ifdef CONFIG_PM
494     bool btOff = ar->arBTOff;
495 #endif /* CONFIG_PM */
496
497     if ((state!=WLAN_DISABLED && state!=WLAN_ENABLED)) {
498         return A_ERROR;
499     }
500
501     if (ar->bIsDestroyProgress) {
502         return A_EBUSY;
503     }
504
505     if (down_interruptible(&ar->arSem)) {
506         return A_ERROR;
507     }
508
509     if (ar->bIsDestroyProgress) {
510         up(&ar->arSem);
511         return A_EBUSY;
512     }
513
514     ar->arWlanState = wlanOff ? WLAN_DISABLED : state;
515     oldPowerState = ar->arWlanPowerState;
516     if (state == WLAN_ENABLED) {
517         powerState = ar->arWlanPowerState;
518         AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WLAN PWR set to ENABLE^^\n"));
519         if (!wlanOff) {
520             if (powerState == WLAN_POWER_STATE_DEEP_SLEEP) {
521                 status = ar6000_setup_deep_sleep_state(ar, WLAN_ENABLED);
522             } else if (powerState == WLAN_POWER_STATE_CUT_PWR) {
523                 status = ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
524             }
525         }
526 #ifdef CONFIG_PM
527         else if (pmEvent && wlanOff) {
528             bool allowCutPwr = ((!ar->arBTSharing) || btOff);
529             if ((powerState==WLAN_POWER_STATE_CUT_PWR) && (!allowCutPwr)) {
530                 /* Come out of cut power */
531                 ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
532                 status = ar6000_setup_deep_sleep_state(ar, WLAN_DISABLED);
533             }
534         }
535 #endif /* CONFIG_PM */
536     } else if (state == WLAN_DISABLED) {
537         AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WLAN PWR set to DISABLED~\n"));
538         powerState = WLAN_POWER_STATE_DEEP_SLEEP;
539 #ifdef CONFIG_PM
540         if (pmEvent) {  /* disable due to suspend */
541             bool suspendCutPwr = (ar->arSuspendConfig == WLAN_SUSPEND_CUT_PWR ||
542                                     (ar->arSuspendConfig == WLAN_SUSPEND_WOW &&
543                                         ar->arWow2Config==WLAN_SUSPEND_CUT_PWR));
544             bool suspendCutIfBtOff = ((ar->arSuspendConfig ==
545                                             WLAN_SUSPEND_CUT_PWR_IF_BT_OFF ||
546                                         (ar->arSuspendConfig == WLAN_SUSPEND_WOW &&
547                                          ar->arWow2Config==WLAN_SUSPEND_CUT_PWR_IF_BT_OFF)) &&
548                                         (!ar->arBTSharing || btOff));
549             if ((suspendCutPwr) ||
550                 (suspendCutIfBtOff) ||
551                 (ar->arWlanState==WLAN_POWER_STATE_CUT_PWR))
552             {
553                 powerState = WLAN_POWER_STATE_CUT_PWR;
554             }
555         } else {
556             if ((wlanOff) &&
557                 (ar->arWlanOffConfig == WLAN_OFF_CUT_PWR) &&
558                 (!ar->arBTSharing || btOff))
559             {
560                 /* For BT clock sharing designs, CUT_POWER depend on BT state */
561                 powerState = WLAN_POWER_STATE_CUT_PWR;
562             }
563         }
564 #endif /* CONFIG_PM */
565
566         if (powerState == WLAN_POWER_STATE_DEEP_SLEEP) {
567             if (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) {
568                 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Load firmware before set to deep sleep\n"));
569                 ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
570             }
571             status = ar6000_setup_deep_sleep_state(ar, WLAN_DISABLED);
572         } else if (powerState == WLAN_POWER_STATE_CUT_PWR) {
573             status = ar6000_setup_cut_power_state(ar, WLAN_DISABLED);
574         }
575
576     }
577
578     if (status) {
579         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WLAN state %d\n", ar->arWlanState));
580         ar->arWlanState = oldstate;
581     } else if (status == 0) {
582         WMI_REPORT_SLEEP_STATE_EVENT  wmiSleepEvent, *pSleepEvent = NULL;
583         if ((ar->arWlanPowerState == WLAN_POWER_STATE_ON) && (oldPowerState != WLAN_POWER_STATE_ON)) {
584             wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_AWAKE;
585             pSleepEvent = &wmiSleepEvent;
586         } else if ((ar->arWlanPowerState != WLAN_POWER_STATE_ON) && (oldPowerState == WLAN_POWER_STATE_ON)) {
587             wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP;
588             pSleepEvent = &wmiSleepEvent;
589         }
590         if (pSleepEvent) {
591             AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("SENT WLAN Sleep Event %d\n", wmiSleepEvent.sleepState));
592         }
593     }
594     up(&ar->arSem);
595     return status;
596 }
597
598 int
599 ar6000_set_bt_hw_state(struct ar6_softc *ar, u32 enable)
600 {
601 #ifdef CONFIG_PM
602     bool off = (enable == 0);
603     int status;
604     if (ar->arBTOff == off) {
605         return 0;
606     }
607     ar->arBTOff = off;
608     status = ar6000_update_wlan_pwr_state(ar, ar->arWlanOff ? WLAN_DISABLED : WLAN_ENABLED, false);
609     return status;
610 #else
611     return 0;
612 #endif
613 }
614
615 int
616 ar6000_set_wlan_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
617 {
618     int status;
619     bool off = (state == WLAN_DISABLED);
620     if (ar->arWlanOff == off) {
621         return 0;
622     }
623     ar->arWlanOff = off;
624     status = ar6000_update_wlan_pwr_state(ar, state, false);
625     return status;
626 }