ar5416_power.c revision 221163
1/* 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 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: head/sys/dev/ath/ath_hal/ar5416/ar5416_power.c 221163 2011-04-28 12:47:40Z adrian $ 18 */ 19#include "opt_ah.h" 20 21#include "ah.h" 22#include "ah_internal.h" 23 24#include "ar5416/ar5416.h" 25#include "ar5416/ar5416reg.h" 26 27/* 28 * Notify Power Mgt is enabled in self-generated frames. 29 * If requested, force chip awake. 30 * 31 * Returns A_OK if chip is awake or successfully forced awake. 32 * 33 * WARNING WARNING WARNING 34 * There is a problem with the chip where sometimes it will not wake up. 35 */ 36static HAL_BOOL 37ar5416SetPowerModeAwake(struct ath_hal *ah, int setChip) 38{ 39#define POWER_UP_TIME 200000 40 uint32_t val; 41 int i = 0; 42 43 if (setChip) { 44 /* 45 * Do a Power-On-Reset if OWL is shutdown 46 * the NetBSD driver power-cycles the Cardbus slot 47 * as part of the reset procedure. 48 */ 49 if ((OS_REG_READ(ah, AR_RTC_STATUS) 50 & AR_RTC_PM_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { 51 if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) 52 goto bad; 53 } 54 55 if (AR_SREV_HOWL(ah)) 56 OS_REG_SET_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); 57 58 OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 59 OS_DELAY(50); /* Give chip the chance to awake */ 60 61 for (i = POWER_UP_TIME / 50; i != 0; i--) { 62 val = OS_REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; 63 if (val == AR_RTC_STATUS_ON) 64 break; 65 OS_DELAY(50); 66 OS_REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 67 } 68 bad: 69 if (i == 0) { 70#ifdef AH_DEBUG 71 ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n", 72 __func__, POWER_UP_TIME/1000); 73#endif 74 return AH_FALSE; 75 } 76 } 77 78 OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 79 return AH_TRUE; 80#undef POWER_UP_TIME 81} 82 83/* 84 * Notify Power Mgt is disabled in self-generated frames. 85 * If requested, force chip to sleep. 86 */ 87static void 88ar5416SetPowerModeSleep(struct ath_hal *ah, int setChip) 89{ 90 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 91 if (setChip) { 92 /* Clear the RTC force wake bit to allow the mac to sleep */ 93 OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 94 if (! AR_SREV_HOWL(ah)) 95 OS_REG_WRITE(ah, AR_RC, AR_RC_AHB|AR_RC_HOSTIF); 96 /* Shutdown chip. Active low */ 97 OS_REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); 98 } 99} 100 101/* 102 * Notify Power Management is enabled in self-generating 103 * fames. If request, set power mode of chip to 104 * auto/normal. Duration in units of 128us (1/8 TU). 105 */ 106static void 107ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) 108{ 109 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); 110 111 if (setChip) 112 OS_REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); 113} 114 115/* 116 * Set power mgt to the requested mode, and conditionally set 117 * the chip as well 118 */ 119HAL_BOOL 120ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) 121{ 122 struct ath_hal_5212 *ahp = AH5212(ah); 123#ifdef AH_DEBUG 124 static const char* modes[] = { 125 "AWAKE", 126 "FULL-SLEEP", 127 "NETWORK SLEEP", 128 "UNDEFINED" 129 }; 130#endif 131 int status = AH_TRUE; 132 if (!setChip) 133 return AH_TRUE; 134 135 HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, 136 modes[ahp->ah_powerMode], modes[mode], setChip ? "set chip " : ""); 137 switch (mode) { 138 case HAL_PM_AWAKE: 139 status = ar5416SetPowerModeAwake(ah, setChip); 140 break; 141 case HAL_PM_FULL_SLEEP: 142 ar5416SetPowerModeSleep(ah, setChip); 143 break; 144 case HAL_PM_NETWORK_SLEEP: 145 ar5416SetPowerModeNetworkSleep(ah, setChip); 146 break; 147 default: 148 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n", 149 __func__, mode); 150 return AH_FALSE; 151 } 152 ahp->ah_powerMode = mode; 153 return status; 154} 155 156/* 157 * Return the current sleep mode of the chip 158 */ 159HAL_POWER_MODE 160ar5416GetPowerMode(struct ath_hal *ah) 161{ 162 int mode = OS_REG_READ(ah, AR_RTC_STATUS); 163 switch (mode & AR_RTC_PM_STATUS_M) { 164 case AR_RTC_STATUS_ON: 165 case AR_RTC_STATUS_WAKEUP: 166 return HAL_PM_AWAKE; 167 case AR_RTC_STATUS_SLEEP: 168 return HAL_PM_NETWORK_SLEEP; 169 case AR_RTC_STATUS_SHUTDOWN: 170 return HAL_PM_FULL_SLEEP; 171 default: 172 HALDEBUG(ah, HAL_DEBUG_ANY, 173 "%s: unknown power mode, RTC_STATUS 0x%x\n", 174 __func__, mode); 175 return HAL_PM_UNDEFINED; 176 } 177} 178