1 /* 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2004 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $FreeBSD$ 18 */ 19 #include "opt_ah.h" 20 21 #include "ah.h" 22 #include "ah_internal.h" 23 24 #include "ar5210/ar5210.h" 25 #include "ar5210/ar5210reg.h" 26 27 /* 28 * Notify Power Mgt is disabled in self-generated frames. 29 * If requested, set Power Mode of chip to auto/normal. 30 */ 31 static void 32 ar5210SetPowerModeAuto(struct ath_hal *ah, int setChip) 33 { 34 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV); 35 if (setChip) 36 OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_ALLOW); 37 } 38 39 /* 40 * Notify Power Mgt is enabled in self-generated frames. 41 * If requested, force chip awake. 42 * 43 * Returns A_OK if chip is awake or successfully forced awake. 44 * 45 * WARNING WARNING WARNING 46 * There is a problem with the chip where sometimes it will not wake up. 47 */ 48 static HAL_BOOL 49 ar5210SetPowerModeAwake(struct ath_hal *ah, int setChip) 50 { 51 #define POWER_UP_TIME 2000 52 uint32_t val; 53 int i; 54 55 if (setChip) { 56 OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE); 57 OS_DELAY(2000); /* Give chip the chance to awake */ 58 59 for (i = POWER_UP_TIME / 200; i != 0; i--) { 60 val = OS_REG_READ(ah, AR_PCICFG); 61 if ((val & AR_PCICFG_SPWR_DN) == 0) 62 break; 63 OS_DELAY(200); 64 OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, 65 AR_SCR_SLE_WAKE); 66 } 67 if (i == 0) { 68 #ifdef AH_DEBUG 69 ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", 70 __func__, POWER_UP_TIME/20); 71 #endif 72 return AH_FALSE; 73 } 74 } 75 76 OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV); 77 return AH_TRUE; 78 #undef POWER_UP_TIME 79 } 80 81 /* 82 * Notify Power Mgt is disabled in self-generated frames. 83 * If requested, force chip to sleep. 84 */ 85 static void 86 ar5210SetPowerModeSleep(struct ath_hal *ah, int setChip) 87 { 88 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV); 89 if (setChip) 90 OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP); 91 } 92 93 HAL_BOOL 94 ar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) 95 { 96 struct ath_hal_5210 *ahp = AH5210(ah); 97 #ifdef AH_DEBUG 98 static const char* modes[] = { 99 "AWAKE", 100 "FULL-SLEEP", 101 "NETWORK SLEEP", 102 "UNDEFINED" 103 }; 104 #endif 105 int status = AH_TRUE; 106 107 HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, 108 modes[ahp->ah_powerMode], modes[mode], 109 setChip ? "set chip " : ""); 110 switch (mode) { 111 case HAL_PM_AWAKE: 112 status = ar5210SetPowerModeAwake(ah, setChip); 113 break; 114 case HAL_PM_FULL_SLEEP: 115 ar5210SetPowerModeSleep(ah, setChip); 116 break; 117 case HAL_PM_NETWORK_SLEEP: 118 ar5210SetPowerModeAuto(ah, setChip); 119 break; 120 default: 121 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", 122 __func__, mode); 123 return AH_FALSE; 124 } 125 ahp->ah_powerMode = mode; 126 return status; 127 } 128 129 HAL_POWER_MODE 130 ar5210GetPowerMode(struct ath_hal *ah) 131 { 132 /* Just so happens the h/w maps directly to the abstracted value */ 133 return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE); 134 } 135