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