1107120Sjulian/*
2107120Sjulian * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3139823Simp * Copyright (c) 2002-2004 Atheros Communications, Inc.
4139823Simp *
5139823Simp * Permission to use, copy, modify, and/or distribute this software for any
6107120Sjulian * purpose with or without fee is hereby granted, provided that the above
7107120Sjulian * copyright notice and this permission notice appear in all copies.
8107120Sjulian *
9107120Sjulian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10107120Sjulian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11107120Sjulian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12107120Sjulian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13107120Sjulian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14107120Sjulian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15107120Sjulian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16107120Sjulian *
17107120Sjulian * $FreeBSD: releng/11.0/sys/dev/ath/ath_hal/ar5210/ar5210_power.c 265112 2014-04-30 02:03:13Z adrian $
18107120Sjulian */
19107120Sjulian#include "opt_ah.h"
20107120Sjulian
21107120Sjulian#include "ah.h"
22107120Sjulian#include "ah_internal.h"
23107120Sjulian
24107120Sjulian#include "ar5210/ar5210.h"
25107120Sjulian#include "ar5210/ar5210reg.h"
26107120Sjulian
27107120Sjulian/*
28107120Sjulian * Notify Power Mgt is disabled in self-generated frames.
29107120Sjulian * If requested, set Power Mode of chip to auto/normal.
30121054Semax */
31107120Sjulianstatic void
32107120Sjulianar5210SetPowerModeAuto(struct ath_hal *ah, int setChip)
33107120Sjulian{
34107120Sjulian	OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV);
35122634Semax	if (setChip)
36107120Sjulian		OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_ALLOW);
37107120Sjulian}
38107120Sjulian
39107120Sjulian/*
40107120Sjulian * Notify Power Mgt is enabled in self-generated frames.
41107120Sjulian * If requested, force chip awake.
42107120Sjulian *
43107120Sjulian * Returns A_OK if chip is awake or successfully forced awake.
44114878Sjulian *
45114878Sjulian * WARNING WARNING WARNING
46107120Sjulian * There is a problem with the chip where sometimes it will not wake up.
47107120Sjulian */
48107120Sjulianstatic HAL_BOOL
49107120Sjulianar5210SetPowerModeAwake(struct ath_hal *ah, int setChip)
50107120Sjulian{
51107120Sjulian#define	POWER_UP_TIME	2000
52107120Sjulian	uint32_t val;
53107120Sjulian	int i;
54107120Sjulian
55107120Sjulian	if (setChip) {
56107120Sjulian		OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_WAKE);
57107120Sjulian		OS_DELAY(2000);	/* Give chip the chance to awake */
58107120Sjulian
59107120Sjulian		for (i = POWER_UP_TIME / 200; i != 0; i--) {
60107120Sjulian			val = OS_REG_READ(ah, AR_PCICFG);
61107120Sjulian			if ((val & AR_PCICFG_SPWR_DN) == 0)
62107120Sjulian				break;
63107120Sjulian			OS_DELAY(200);
64107120Sjulian			OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE,
65114878Sjulian				AR_SCR_SLE_WAKE);
66107120Sjulian		}
67107120Sjulian		if (i == 0) {
68107120Sjulian#ifdef AH_DEBUG
69107120Sjulian			ath_hal_printf(ah, "%s: Failed to wakeup in %ums\n",
70107120Sjulian				__func__, POWER_UP_TIME/20);
71114878Sjulian#endif
72107120Sjulian			return AH_FALSE;
73107120Sjulian		}
74107120Sjulian	}
75107120Sjulian
76149355Spjd	OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV);
77107120Sjulian	return AH_TRUE;
78107120Sjulian#undef POWER_UP_TIME
79184205Sdes}
80107120Sjulian
81107120Sjulian/*
82107120Sjulian * Notify Power Mgt is disabled in self-generated frames.
83107120Sjulian * If requested, force chip to sleep.
84107120Sjulian */
85107120Sjulianstatic void
86107120Sjulianar5210SetPowerModeSleep(struct ath_hal *ah, int setChip)
87107120Sjulian{
88107120Sjulian	OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SV);
89107120Sjulian	if (setChip)
90107120Sjulian		OS_REG_RMW_FIELD(ah, AR_SCR, AR_SCR_SLE, AR_SCR_SLE_SLP);
91121054Semax}
92121054Semax
93121054SemaxHAL_BOOL
94121054Semaxar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
95121054Semax{
96121054Semax#ifdef AH_DEBUG
97107120Sjulian	static const char* modes[] = {
98107120Sjulian		"AWAKE",
99107120Sjulian		"FULL-SLEEP",
100107120Sjulian		"NETWORK SLEEP",
101107120Sjulian		"UNDEFINED"
102107120Sjulian	};
103107120Sjulian#endif
104107120Sjulian	int status = AH_TRUE;
105107120Sjulian
106107120Sjulian	HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
107		modes[ah->ah_powerMode], modes[mode],
108		setChip ? "set chip " : "");
109	switch (mode) {
110	case HAL_PM_AWAKE:
111		if (setChip)
112			ah->ah_powerMode = mode;
113		status = ar5210SetPowerModeAwake(ah, setChip);
114		break;
115	case HAL_PM_FULL_SLEEP:
116		ar5210SetPowerModeSleep(ah, setChip);
117		if (setChip)
118			ah->ah_powerMode = mode;
119		break;
120	case HAL_PM_NETWORK_SLEEP:
121		ar5210SetPowerModeAuto(ah, setChip);
122		if (setChip)
123			ah->ah_powerMode = mode;
124		break;
125	default:
126		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n",
127		    __func__, mode);
128		return AH_FALSE;
129	}
130	return status;
131}
132
133HAL_POWER_MODE
134ar5210GetPowerMode(struct ath_hal *ah)
135{
136	/* Just so happens the h/w maps directly to the abstracted value */
137	return MS(OS_REG_READ(ah, AR_SCR), AR_SCR_SLE);
138}
139