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