linux/drivers/staging/ath6kl/os/linux/ar6000_pm.c
<<
>>
Prefs
   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
  40extern unsigned int wmitimeout;
  41extern wait_queue_head_t arEvent;
  42
  43#ifdef CONFIG_PM
  44#ifdef CONFIG_HAS_WAKELOCK
  45struct wake_lock ar6k_suspend_wake_lock;
  46struct wake_lock ar6k_wow_wake_lock;
  47#endif
  48#endif /* CONFIG_PM */
  49
  50#ifdef ANDROID_ENV
  51extern 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
  58static ATH_DEBUG_MASK_DESCRIPTION pm_debug_desc[] = {
  59    { ATH_DEBUG_PM     , "System power management"},
  60};
  61
  62ATH_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
  71A_STATUS ar6000_exit_cut_power_state(AR_SOFTC_T *ar);
  72
  73#ifdef CONFIG_PM
  74static 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
  85static 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
 127static 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
 228A_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;
 233wow_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
 265A_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
 296void 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
 313A_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
 332static int ar6000_pm_probe(struct platform_device *pdev)
 333{
 334    plat_setup_power(1,1);
 335    return 0;
 336}
 337
 338static int ar6000_pm_remove(struct platform_device *pdev)
 339{
 340    plat_setup_power(0,1);
 341    return 0;
 342}
 343
 344static int ar6000_pm_suspend(struct platform_device *pdev, pm_message_t state)
 345{
 346    return 0;
 347}
 348
 349static int ar6000_pm_resume(struct platform_device *pdev)
 350{
 351    return 0;
 352}
 353
 354static 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
 365A_STATUS
 366ar6000_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
 435A_STATUS
 436ar6000_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
 559A_STATUS
 560ar6000_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
 673A_STATUS
 674ar6000_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
 690A_STATUS
 691ar6000_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
 703void 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
 722void 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}
 732