ath6kl: remove SEND_EVENT_TO_APP define
[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 static int ar6000_pm_probe(struct platform_device *pdev)
306 {
307     plat_setup_power(1,1);
308     return 0;
309 }
310
311 static int ar6000_pm_remove(struct platform_device *pdev)
312 {
313     plat_setup_power(0,1);
314     return 0;
315 }
316
317 static int ar6000_pm_suspend(struct platform_device *pdev, pm_message_t state)
318 {
319     return 0;
320 }
321
322 static int ar6000_pm_resume(struct platform_device *pdev)
323 {
324     return 0;
325 }
326
327 static struct platform_driver ar6000_pm_device = {
328     .probe      = ar6000_pm_probe,
329     .remove     = ar6000_pm_remove,
330     .suspend    = ar6000_pm_suspend,
331     .resume     = ar6000_pm_resume,
332     .driver     = {
333         .name = "wlan_ar6000_pm",
334     },
335 };
336 #endif /* CONFIG_PM */
337
338 int
339 ar6000_setup_cut_power_state(struct ar6_softc *ar,  AR6000_WLAN_STATE state)
340 {
341     int                      status = 0;
342     HIF_DEVICE_POWER_CHANGE_TYPE  config;
343
344     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: Cut power %d %d \n", __func__,state, ar->arWlanPowerState));
345 #ifdef CONFIG_PM
346     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Wlan OFF %d BT OFf %d \n", ar->arWlanOff, ar->arBTOff));
347 #endif
348     do {
349         if (state == WLAN_ENABLED) {
350             /* Not in cut power state.. exit */
351             if (ar->arWlanPowerState != WLAN_POWER_STATE_CUT_PWR) {
352                 break;
353             }
354
355             plat_setup_power(1,0);
356
357             /* Change the state to ON */
358             ar->arWlanPowerState = WLAN_POWER_STATE_ON;
359
360
361             /* Indicate POWER_UP to HIF */
362             config = HIF_DEVICE_POWER_UP;
363             status = HIFConfigureDevice(ar->arHifDevice,
364                                 HIF_DEVICE_POWER_STATE_CHANGE,
365                                 &config,
366                                 sizeof(HIF_DEVICE_POWER_CHANGE_TYPE));
367
368             if (status == A_PENDING) {
369             } else if (status == 0) {
370                 ar6000_restart_endpoint(ar->arNetDev);
371                 status = 0;
372             }
373         } else if (state == WLAN_DISABLED) {
374
375
376             /* Already in cut power state.. exit */
377             if (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) {
378                 break;
379             }
380             ar6000_stop_endpoint(ar->arNetDev, true, false);
381
382             config = HIF_DEVICE_POWER_CUT;
383             status = HIFConfigureDevice(ar->arHifDevice,
384                                 HIF_DEVICE_POWER_STATE_CHANGE,
385                                 &config,
386                                 sizeof(HIF_DEVICE_POWER_CHANGE_TYPE));
387
388             plat_setup_power(0,0);
389
390             ar->arWlanPowerState = WLAN_POWER_STATE_CUT_PWR;
391         }
392     } while (0);
393
394     return status;
395 }
396
397 int
398 ar6000_setup_deep_sleep_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
399 {
400     int status = 0;
401
402     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("%s: Deep sleep %d %d \n", __func__,state, ar->arWlanPowerState));
403 #ifdef CONFIG_PM
404     AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Wlan OFF %d BT OFf %d \n", ar->arWlanOff, ar->arBTOff));
405 #endif
406     do {
407         WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode;
408
409         if (state == WLAN_ENABLED) {
410             u16 fg_start_period;
411
412             /* Not in deep sleep state.. exit */
413             if (ar->arWlanPowerState != WLAN_POWER_STATE_DEEP_SLEEP) {
414                 if (ar->arWlanPowerState != WLAN_POWER_STATE_ON) {
415                     AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange state when we resume from deep sleep %d\n", ar->arWlanPowerState));
416                 }
417                 break;
418             }
419
420             fg_start_period = (ar->scParams.fg_start_period==0) ? 1 : ar->scParams.fg_start_period;
421             hostSleepMode.awake = true;
422             hostSleepMode.asleep = false;
423
424             if ((status=wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode)) != 0) {
425                 break;
426             }
427
428             /* Change the state to ON */
429             ar->arWlanPowerState = WLAN_POWER_STATE_ON;
430
431                 /* Enable foreground scanning */
432                 if ((status=wmi_scanparams_cmd(ar->arWmi, fg_start_period,
433                                         ar->scParams.fg_end_period,
434                                         ar->scParams.bg_period,
435                                         ar->scParams.minact_chdwell_time,
436                                         ar->scParams.maxact_chdwell_time,
437                                         ar->scParams.pas_chdwell_time,
438                                         ar->scParams.shortScanRatio,
439                                         ar->scParams.scanCtrlFlags,
440                                         ar->scParams.max_dfsch_act_time,
441                                         ar->scParams.maxact_scan_per_ssid)) != 0)
442                 {
443                     break;
444                 }
445
446             if (ar->arNetworkType != AP_NETWORK)
447             {
448                 if (ar->arSsidLen) {
449                     if (ar6000_connect_to_ap(ar) != 0) {
450                         /* no need to report error if connection failed */
451                         break;
452                     }
453                 }
454             }
455         } else if (state == WLAN_DISABLED){
456             WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = false };
457
458             /* Already in deep sleep state.. exit */
459             if (ar->arWlanPowerState != WLAN_POWER_STATE_ON) {
460                 if (ar->arWlanPowerState != WLAN_POWER_STATE_DEEP_SLEEP) {
461                     AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange state when we suspend for deep sleep %d\n", ar->arWlanPowerState));
462                 }
463                 break;
464             }
465
466             if (ar->arNetworkType != AP_NETWORK)
467             {
468                 /* Disconnect from the AP and disable foreground scanning */
469                 AR6000_SPIN_LOCK(&ar->arLock, 0);
470                 if (ar->arConnected == true || ar->arConnectPending == true) {
471                     AR6000_SPIN_UNLOCK(&ar->arLock, 0);
472                     wmi_disconnect_cmd(ar->arWmi);
473                 } else {
474                     AR6000_SPIN_UNLOCK(&ar->arLock, 0);
475                 }
476             }
477
478             ar->scan_triggered = 0;
479
480             if ((status=wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 0)) != 0) {
481                 break;
482             }
483
484             /* make sure we disable wow for deep sleep */
485             if ((status=wmi_set_wow_mode_cmd(ar->arWmi, &wowMode))!= 0)
486             {
487                 break;
488             }
489
490             ar6000_TxDataCleanup(ar);
491 #ifndef ATH6K_CONFIG_OTA_MODE
492             wmi_powermode_cmd(ar->arWmi, REC_POWER);
493 #endif
494
495             hostSleepMode.awake = false;
496             hostSleepMode.asleep = true;
497             if ((status=wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode))!= 0) {
498                 break;
499             }
500             if (ar->arTxPending[ar->arControlEp]) {
501                 u32 timeleft = wait_event_interruptible_timeout(arEvent,
502                                 ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
503                 if (!timeleft || signal_pending(current)) {
504                     status = A_ERROR;
505                     break;
506                 }
507             }
508             status = hifWaitForPendingRecv(ar->arHifDevice);
509
510             ar->arWlanPowerState = WLAN_POWER_STATE_DEEP_SLEEP;
511         }
512     } while (0);
513
514     if (status) {
515         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to enter/exit deep sleep %d\n", state));
516     }
517
518     return status;
519 }
520
521 int
522 ar6000_update_wlan_pwr_state(struct ar6_softc *ar, AR6000_WLAN_STATE state, bool pmEvent)
523 {
524     int status = 0;
525     u16 powerState, oldPowerState;
526     AR6000_WLAN_STATE oldstate = ar->arWlanState;
527     bool wlanOff = ar->arWlanOff;
528 #ifdef CONFIG_PM
529     bool btOff = ar->arBTOff;
530 #endif /* CONFIG_PM */
531
532     if ((state!=WLAN_DISABLED && state!=WLAN_ENABLED)) {
533         return A_ERROR;
534     }
535
536     if (ar->bIsDestroyProgress) {
537         return A_EBUSY;
538     }
539
540     if (down_interruptible(&ar->arSem)) {
541         return A_ERROR;
542     }
543
544     if (ar->bIsDestroyProgress) {
545         up(&ar->arSem);
546         return A_EBUSY;
547     }
548
549     ar->arWlanState = wlanOff ? WLAN_DISABLED : state;
550     oldPowerState = ar->arWlanPowerState;
551     if (state == WLAN_ENABLED) {
552         powerState = ar->arWlanPowerState;
553         AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WLAN PWR set to ENABLE^^\n"));
554         if (!wlanOff) {
555             if (powerState == WLAN_POWER_STATE_DEEP_SLEEP) {
556                 status = ar6000_setup_deep_sleep_state(ar, WLAN_ENABLED);
557             } else if (powerState == WLAN_POWER_STATE_CUT_PWR) {
558                 status = ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
559             }
560         }
561 #ifdef CONFIG_PM
562         else if (pmEvent && wlanOff) {
563             bool allowCutPwr = ((!ar->arBTSharing) || btOff);
564             if ((powerState==WLAN_POWER_STATE_CUT_PWR) && (!allowCutPwr)) {
565                 /* Come out of cut power */
566                 ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
567                 status = ar6000_setup_deep_sleep_state(ar, WLAN_DISABLED);
568             }
569         }
570 #endif /* CONFIG_PM */
571     } else if (state == WLAN_DISABLED) {
572         AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("WLAN PWR set to DISABLED~\n"));
573         powerState = WLAN_POWER_STATE_DEEP_SLEEP;
574 #ifdef CONFIG_PM
575         if (pmEvent) {  /* disable due to suspend */
576             bool suspendCutPwr = (ar->arSuspendConfig == WLAN_SUSPEND_CUT_PWR ||
577                                     (ar->arSuspendConfig == WLAN_SUSPEND_WOW &&
578                                         ar->arWow2Config==WLAN_SUSPEND_CUT_PWR));
579             bool suspendCutIfBtOff = ((ar->arSuspendConfig ==
580                                             WLAN_SUSPEND_CUT_PWR_IF_BT_OFF ||
581                                         (ar->arSuspendConfig == WLAN_SUSPEND_WOW &&
582                                          ar->arWow2Config==WLAN_SUSPEND_CUT_PWR_IF_BT_OFF)) &&
583                                         (!ar->arBTSharing || btOff));
584             if ((suspendCutPwr) ||
585                 (suspendCutIfBtOff) ||
586                 (ar->arWlanState==WLAN_POWER_STATE_CUT_PWR))
587             {
588                 powerState = WLAN_POWER_STATE_CUT_PWR;
589             }
590         } else {
591             if ((wlanOff) &&
592                 (ar->arWlanOffConfig == WLAN_OFF_CUT_PWR) &&
593                 (!ar->arBTSharing || btOff))
594             {
595                 /* For BT clock sharing designs, CUT_POWER depend on BT state */
596                 powerState = WLAN_POWER_STATE_CUT_PWR;
597             }
598         }
599 #endif /* CONFIG_PM */
600
601         if (powerState == WLAN_POWER_STATE_DEEP_SLEEP) {
602             if (ar->arWlanPowerState == WLAN_POWER_STATE_CUT_PWR) {
603                 AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("Load firmware before set to deep sleep\n"));
604                 ar6000_setup_cut_power_state(ar, WLAN_ENABLED);
605             }
606             status = ar6000_setup_deep_sleep_state(ar, WLAN_DISABLED);
607         } else if (powerState == WLAN_POWER_STATE_CUT_PWR) {
608             status = ar6000_setup_cut_power_state(ar, WLAN_DISABLED);
609         }
610
611     }
612
613     if (status) {
614         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WLAN state %d\n", ar->arWlanState));
615         ar->arWlanState = oldstate;
616     } else if (status == 0) {
617         WMI_REPORT_SLEEP_STATE_EVENT  wmiSleepEvent, *pSleepEvent = NULL;
618         if ((ar->arWlanPowerState == WLAN_POWER_STATE_ON) && (oldPowerState != WLAN_POWER_STATE_ON)) {
619             wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_AWAKE;
620             pSleepEvent = &wmiSleepEvent;
621         } else if ((ar->arWlanPowerState != WLAN_POWER_STATE_ON) && (oldPowerState == WLAN_POWER_STATE_ON)) {
622             wmiSleepEvent.sleepState = WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP;
623             pSleepEvent = &wmiSleepEvent;
624         }
625         if (pSleepEvent) {
626             AR_DEBUG_PRINTF(ATH_DEBUG_PM, ("SENT WLAN Sleep Event %d\n", wmiSleepEvent.sleepState));
627         }
628     }
629     up(&ar->arSem);
630     return status;
631 }
632
633 int
634 ar6000_set_bt_hw_state(struct ar6_softc *ar, u32 enable)
635 {
636 #ifdef CONFIG_PM
637     bool off = (enable == 0);
638     int status;
639     if (ar->arBTOff == off) {
640         return 0;
641     }
642     ar->arBTOff = off;
643     status = ar6000_update_wlan_pwr_state(ar, ar->arWlanOff ? WLAN_DISABLED : WLAN_ENABLED, false);
644     return status;
645 #else
646     return 0;
647 #endif
648 }
649
650 int
651 ar6000_set_wlan_state(struct ar6_softc *ar, AR6000_WLAN_STATE state)
652 {
653     int status;
654     bool off = (state == WLAN_DISABLED);
655     if (ar->arWlanOff == off) {
656         return 0;
657     }
658     ar->arWlanOff = off;
659     status = ar6000_update_wlan_pwr_state(ar, state, false);
660     return status;
661 }
662
663 void ar6000_pm_init()
664 {
665     A_REGISTER_MODULE_DEBUG_INFO(pm);
666 #ifdef CONFIG_PM
667     /*
668      * Register ar6000_pm_device into system.
669      * We should also add platform_device into the first item of array
670      * of devices[] in file arch/xxx/mach-xxx/board-xxxx.c
671      */
672     if (platform_driver_register(&ar6000_pm_device)) {
673         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000: fail to register the power control driver.\n"));
674     }
675 #endif /* CONFIG_PM */
676 }
677
678 void ar6000_pm_exit()
679 {
680 #ifdef CONFIG_PM
681     platform_driver_unregister(&ar6000_pm_device);
682 #endif /* CONFIG_PM */
683 }