~ubuntu-branches/ubuntu/natty/linux-backports-modules-2.6.38/natty-updates

« back to all changes in this revision

Viewing changes to updates/compat-wireless-2.6.37/drivers/staging/ath6kl/os/linux/ar6000_pm.c

  • Committer: Bazaar Package Importer
  • Author(s): Tim Gardner, Tim Gardner
  • Date: 2011-06-08 10:44:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110608104409-fnl8carkdo15bwsz
Tags: 2.6.38-10.6
[ Tim Gardner ]

Shorten compat-wireless package name to cw to accomodate
CDROM file name length restrictions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
}