162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
362306a36Sopenharmony_ci * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
462306a36Sopenharmony_ci * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
562306a36Sopenharmony_ci * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
662306a36Sopenharmony_ci * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
962306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
1062306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1362306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1462306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1562306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1662306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1762306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1862306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/****************************\
2362306a36Sopenharmony_ci  Reset function and helpers
2462306a36Sopenharmony_ci\****************************/
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <asm/unaligned.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <linux/pci.h>		/* To determine if a card is pci-e */
3162306a36Sopenharmony_ci#include <linux/log2.h>
3262306a36Sopenharmony_ci#include <linux/platform_device.h>
3362306a36Sopenharmony_ci#include "ath5k.h"
3462306a36Sopenharmony_ci#include "reg.h"
3562306a36Sopenharmony_ci#include "debug.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/**
3962306a36Sopenharmony_ci * DOC: Reset function and helpers
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * Here we implement the main reset routine, used to bring the card
4262306a36Sopenharmony_ci * to a working state and ready to receive. We also handle routines
4362306a36Sopenharmony_ci * that don't fit on other places such as clock, sleep and power control
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/******************\
4862306a36Sopenharmony_ci* Helper functions *
4962306a36Sopenharmony_ci\******************/
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/**
5262306a36Sopenharmony_ci * ath5k_hw_register_timeout() - Poll a register for a flag/field change
5362306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
5462306a36Sopenharmony_ci * @reg: The register to read
5562306a36Sopenharmony_ci * @flag: The flag/field to check on the register
5662306a36Sopenharmony_ci * @val: The field value we expect (if we check a field)
5762306a36Sopenharmony_ci * @is_set: Instead of checking if the flag got cleared, check if it got set
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Some registers contain flags that indicate that an operation is
6062306a36Sopenharmony_ci * running. We use this function to poll these registers and check
6162306a36Sopenharmony_ci * if these flags get cleared. We also use it to poll a register
6262306a36Sopenharmony_ci * field (containing multiple flags) until it gets a specific value.
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * Returns -EAGAIN if we exceeded AR5K_TUNE_REGISTER_TIMEOUT * 15us or 0
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ciint
6762306a36Sopenharmony_ciath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
6862306a36Sopenharmony_ci			      bool is_set)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	int i;
7162306a36Sopenharmony_ci	u32 data;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
7462306a36Sopenharmony_ci		data = ath5k_hw_reg_read(ah, reg);
7562306a36Sopenharmony_ci		if (is_set && (data & flag))
7662306a36Sopenharmony_ci			break;
7762306a36Sopenharmony_ci		else if ((data & flag) == val)
7862306a36Sopenharmony_ci			break;
7962306a36Sopenharmony_ci		udelay(15);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return (i <= 0) ? -EAGAIN : 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/*************************\
8762306a36Sopenharmony_ci* Clock related functions *
8862306a36Sopenharmony_ci\*************************/
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * ath5k_hw_htoclock() - Translate usec to hw clock units
9262306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
9362306a36Sopenharmony_ci * @usec: value in microseconds
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Translate usecs to hw clock units based on the current
9662306a36Sopenharmony_ci * hw clock rate.
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * Returns number of clock units
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_ciunsigned int
10162306a36Sopenharmony_ciath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct ath_common *common = ath5k_hw_common(ah);
10462306a36Sopenharmony_ci	return usec * common->clockrate;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/**
10862306a36Sopenharmony_ci * ath5k_hw_clocktoh() - Translate hw clock units to usec
10962306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
11062306a36Sopenharmony_ci * @clock: value in hw clock units
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * Translate hw clock units to usecs based on the current
11362306a36Sopenharmony_ci * hw clock rate.
11462306a36Sopenharmony_ci *
11562306a36Sopenharmony_ci * Returns number of usecs
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_ciunsigned int
11862306a36Sopenharmony_ciath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	struct ath_common *common = ath5k_hw_common(ah);
12162306a36Sopenharmony_ci	return clock / common->clockrate;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/**
12562306a36Sopenharmony_ci * ath5k_hw_init_core_clock() - Initialize core clock
12662306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * Initialize core clock parameters (usec, usec32, latencies etc),
12962306a36Sopenharmony_ci * based on current bwmode and chipset properties.
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cistatic void
13262306a36Sopenharmony_ciath5k_hw_init_core_clock(struct ath5k_hw *ah)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct ieee80211_channel *channel = ah->ah_current_channel;
13562306a36Sopenharmony_ci	struct ath_common *common = ath5k_hw_common(ah);
13662306a36Sopenharmony_ci	u32 usec_reg, txlat, rxlat, usec, clock, sclock, txf2txs;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/*
13962306a36Sopenharmony_ci	 * Set core clock frequency
14062306a36Sopenharmony_ci	 */
14162306a36Sopenharmony_ci	switch (channel->hw_value) {
14262306a36Sopenharmony_ci	case AR5K_MODE_11A:
14362306a36Sopenharmony_ci		clock = 40;
14462306a36Sopenharmony_ci		break;
14562306a36Sopenharmony_ci	case AR5K_MODE_11B:
14662306a36Sopenharmony_ci		clock = 22;
14762306a36Sopenharmony_ci		break;
14862306a36Sopenharmony_ci	case AR5K_MODE_11G:
14962306a36Sopenharmony_ci	default:
15062306a36Sopenharmony_ci		clock = 44;
15162306a36Sopenharmony_ci		break;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* Use clock multiplier for non-default
15562306a36Sopenharmony_ci	 * bwmode */
15662306a36Sopenharmony_ci	switch (ah->ah_bwmode) {
15762306a36Sopenharmony_ci	case AR5K_BWMODE_40MHZ:
15862306a36Sopenharmony_ci		clock *= 2;
15962306a36Sopenharmony_ci		break;
16062306a36Sopenharmony_ci	case AR5K_BWMODE_10MHZ:
16162306a36Sopenharmony_ci		clock /= 2;
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci	case AR5K_BWMODE_5MHZ:
16462306a36Sopenharmony_ci		clock /= 4;
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	default:
16762306a36Sopenharmony_ci		break;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	common->clockrate = clock;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/*
17362306a36Sopenharmony_ci	 * Set USEC parameters
17462306a36Sopenharmony_ci	 */
17562306a36Sopenharmony_ci	/* Set USEC counter on PCU*/
17662306a36Sopenharmony_ci	usec = clock - 1;
17762306a36Sopenharmony_ci	usec = AR5K_REG_SM(usec, AR5K_USEC_1);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Set usec duration on DCU */
18062306a36Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210)
18162306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
18262306a36Sopenharmony_ci					AR5K_DCU_GBL_IFS_MISC_USEC_DUR,
18362306a36Sopenharmony_ci					clock);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Set 32MHz USEC counter */
18662306a36Sopenharmony_ci	if ((ah->ah_radio == AR5K_RF5112) ||
18762306a36Sopenharmony_ci	    (ah->ah_radio == AR5K_RF2413) ||
18862306a36Sopenharmony_ci	    (ah->ah_radio == AR5K_RF5413) ||
18962306a36Sopenharmony_ci	    (ah->ah_radio == AR5K_RF2316) ||
19062306a36Sopenharmony_ci	    (ah->ah_radio == AR5K_RF2317))
19162306a36Sopenharmony_ci		/* Remain on 40MHz clock ? */
19262306a36Sopenharmony_ci		sclock = 40 - 1;
19362306a36Sopenharmony_ci	else
19462306a36Sopenharmony_ci		sclock = 32 - 1;
19562306a36Sopenharmony_ci	sclock = AR5K_REG_SM(sclock, AR5K_USEC_32);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/*
19862306a36Sopenharmony_ci	 * Set tx/rx latencies
19962306a36Sopenharmony_ci	 */
20062306a36Sopenharmony_ci	usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
20162306a36Sopenharmony_ci	txlat = AR5K_REG_MS(usec_reg, AR5K_USEC_TX_LATENCY_5211);
20262306a36Sopenharmony_ci	rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/*
20562306a36Sopenharmony_ci	 * Set default Tx frame to Tx data start delay
20662306a36Sopenharmony_ci	 */
20762306a36Sopenharmony_ci	txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/*
21062306a36Sopenharmony_ci	 * 5210 initvals don't include usec settings
21162306a36Sopenharmony_ci	 * so we need to use magic values here for
21262306a36Sopenharmony_ci	 * tx/rx latencies
21362306a36Sopenharmony_ci	 */
21462306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
21562306a36Sopenharmony_ci		/* same for turbo */
21662306a36Sopenharmony_ci		txlat = AR5K_INIT_TX_LATENCY_5210;
21762306a36Sopenharmony_ci		rxlat = AR5K_INIT_RX_LATENCY_5210;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
22162306a36Sopenharmony_ci		/* 5311 has different tx/rx latency masks
22262306a36Sopenharmony_ci		 * from 5211, since we deal 5311 the same
22362306a36Sopenharmony_ci		 * as 5211 when setting initvals, shift
22462306a36Sopenharmony_ci		 * values here to their proper locations
22562306a36Sopenharmony_ci		 *
22662306a36Sopenharmony_ci		 * Note: Initvals indicate tx/rx/ latencies
22762306a36Sopenharmony_ci		 * are the same for turbo mode */
22862306a36Sopenharmony_ci		txlat = AR5K_REG_SM(txlat, AR5K_USEC_TX_LATENCY_5210);
22962306a36Sopenharmony_ci		rxlat = AR5K_REG_SM(rxlat, AR5K_USEC_RX_LATENCY_5210);
23062306a36Sopenharmony_ci	} else
23162306a36Sopenharmony_ci	switch (ah->ah_bwmode) {
23262306a36Sopenharmony_ci	case AR5K_BWMODE_10MHZ:
23362306a36Sopenharmony_ci		txlat = AR5K_REG_SM(txlat * 2,
23462306a36Sopenharmony_ci				AR5K_USEC_TX_LATENCY_5211);
23562306a36Sopenharmony_ci		rxlat = AR5K_REG_SM(AR5K_INIT_RX_LAT_MAX,
23662306a36Sopenharmony_ci				AR5K_USEC_RX_LATENCY_5211);
23762306a36Sopenharmony_ci		txf2txs = AR5K_INIT_TXF2TXD_START_DELAY_10MHZ;
23862306a36Sopenharmony_ci		break;
23962306a36Sopenharmony_ci	case AR5K_BWMODE_5MHZ:
24062306a36Sopenharmony_ci		txlat = AR5K_REG_SM(txlat * 4,
24162306a36Sopenharmony_ci				AR5K_USEC_TX_LATENCY_5211);
24262306a36Sopenharmony_ci		rxlat = AR5K_REG_SM(AR5K_INIT_RX_LAT_MAX,
24362306a36Sopenharmony_ci				AR5K_USEC_RX_LATENCY_5211);
24462306a36Sopenharmony_ci		txf2txs = AR5K_INIT_TXF2TXD_START_DELAY_5MHZ;
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	case AR5K_BWMODE_40MHZ:
24762306a36Sopenharmony_ci		txlat = AR5K_INIT_TX_LAT_MIN;
24862306a36Sopenharmony_ci		rxlat = AR5K_REG_SM(rxlat / 2,
24962306a36Sopenharmony_ci				AR5K_USEC_RX_LATENCY_5211);
25062306a36Sopenharmony_ci		txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT;
25162306a36Sopenharmony_ci		break;
25262306a36Sopenharmony_ci	default:
25362306a36Sopenharmony_ci		break;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	usec_reg = (usec | sclock | txlat | rxlat);
25762306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, usec_reg, AR5K_USEC);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* On 5112 set tx frame to tx data start delay */
26062306a36Sopenharmony_ci	if (ah->ah_radio == AR5K_RF5112) {
26162306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL2,
26262306a36Sopenharmony_ci					AR5K_PHY_RF_CTL2_TXF2TXD_START,
26362306a36Sopenharmony_ci					txf2txs);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/**
26862306a36Sopenharmony_ci * ath5k_hw_set_sleep_clock() - Setup sleep clock operation
26962306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
27062306a36Sopenharmony_ci * @enable: Enable sleep clock operation (false to disable)
27162306a36Sopenharmony_ci *
27262306a36Sopenharmony_ci * If there is an external 32KHz crystal available, use it
27362306a36Sopenharmony_ci * as ref. clock instead of 32/40MHz clock and baseband clocks
27462306a36Sopenharmony_ci * to save power during sleep or restore normal 32/40MHz
27562306a36Sopenharmony_ci * operation.
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * NOTE: When operating on 32KHz certain PHY registers (27 - 31,
27862306a36Sopenharmony_ci * 123 - 127) require delay on access.
27962306a36Sopenharmony_ci */
28062306a36Sopenharmony_cistatic void
28162306a36Sopenharmony_ciath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
28462306a36Sopenharmony_ci	u32 scal, spending, sclock;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Only set 32KHz settings if we have an external
28762306a36Sopenharmony_ci	 * 32KHz crystal present */
28862306a36Sopenharmony_ci	if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) ||
28962306a36Sopenharmony_ci	AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) &&
29062306a36Sopenharmony_ci	enable) {
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		/* 1 usec/cycle */
29362306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1);
29462306a36Sopenharmony_ci		/* Set up tsf increment on each cycle */
29562306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		/* Set baseband sleep control registers
29862306a36Sopenharmony_ci		 * and sleep control rate */
29962306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		if ((ah->ah_radio == AR5K_RF5112) ||
30262306a36Sopenharmony_ci		(ah->ah_radio == AR5K_RF5413) ||
30362306a36Sopenharmony_ci		(ah->ah_radio == AR5K_RF2316) ||
30462306a36Sopenharmony_ci		(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
30562306a36Sopenharmony_ci			spending = 0x14;
30662306a36Sopenharmony_ci		else
30762306a36Sopenharmony_ci			spending = 0x18;
30862306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		if ((ah->ah_radio == AR5K_RF5112) ||
31162306a36Sopenharmony_ci		(ah->ah_radio == AR5K_RF5413) ||
31262306a36Sopenharmony_ci		(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
31362306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
31462306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
31562306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
31662306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
31762306a36Sopenharmony_ci			AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
31862306a36Sopenharmony_ci				AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
31962306a36Sopenharmony_ci		} else {
32062306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT);
32162306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL);
32262306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK);
32362306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY);
32462306a36Sopenharmony_ci			AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
32562306a36Sopenharmony_ci				AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03);
32662306a36Sopenharmony_ci		}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		/* Enable sleep clock operation */
32962306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
33062306a36Sopenharmony_ci				AR5K_PCICFG_SLEEP_CLOCK_EN);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	} else {
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		/* Disable sleep clock operation and
33562306a36Sopenharmony_ci		 * restore default parameters */
33662306a36Sopenharmony_ci		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
33762306a36Sopenharmony_ci				AR5K_PCICFG_SLEEP_CLOCK_EN);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
34062306a36Sopenharmony_ci				AR5K_PCICFG_SLEEP_CLOCK_RATE, 0);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		/* Set DAC/ADC delays */
34362306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
34462306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
34762306a36Sopenharmony_ci			scal = AR5K_PHY_SCAL_32MHZ_2417;
34862306a36Sopenharmony_ci		else if (ee->ee_is_hb63)
34962306a36Sopenharmony_ci			scal = AR5K_PHY_SCAL_32MHZ_HB63;
35062306a36Sopenharmony_ci		else
35162306a36Sopenharmony_ci			scal = AR5K_PHY_SCAL_32MHZ;
35262306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
35562306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		if ((ah->ah_radio == AR5K_RF5112) ||
35862306a36Sopenharmony_ci		(ah->ah_radio == AR5K_RF5413) ||
35962306a36Sopenharmony_ci		(ah->ah_radio == AR5K_RF2316) ||
36062306a36Sopenharmony_ci		(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
36162306a36Sopenharmony_ci			spending = 0x14;
36262306a36Sopenharmony_ci		else
36362306a36Sopenharmony_ci			spending = 0x18;
36462306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		/* Set up tsf increment on each cycle */
36762306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		if ((ah->ah_radio == AR5K_RF5112) ||
37062306a36Sopenharmony_ci			(ah->ah_radio == AR5K_RF5413) ||
37162306a36Sopenharmony_ci			(ah->ah_radio == AR5K_RF2316) ||
37262306a36Sopenharmony_ci			(ah->ah_radio == AR5K_RF2317))
37362306a36Sopenharmony_ci			sclock = 40 - 1;
37462306a36Sopenharmony_ci		else
37562306a36Sopenharmony_ci			sclock = 32 - 1;
37662306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, sclock);
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci/*********************\
38262306a36Sopenharmony_ci* Reset/Sleep control *
38362306a36Sopenharmony_ci\*********************/
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci/**
38662306a36Sopenharmony_ci * ath5k_hw_nic_reset() - Reset the various chipset units
38762306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
38862306a36Sopenharmony_ci * @val: Mask to indicate what units to reset
38962306a36Sopenharmony_ci *
39062306a36Sopenharmony_ci * To reset the various chipset units we need to write
39162306a36Sopenharmony_ci * the mask to AR5K_RESET_CTL and poll the register until
39262306a36Sopenharmony_ci * all flags are cleared.
39362306a36Sopenharmony_ci *
39462306a36Sopenharmony_ci * Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout)
39562306a36Sopenharmony_ci */
39662306a36Sopenharmony_cistatic int
39762306a36Sopenharmony_ciath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	int ret;
40062306a36Sopenharmony_ci	u32 mask = val ? val : ~0U;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Read-and-clear RX Descriptor Pointer*/
40362306a36Sopenharmony_ci	ath5k_hw_reg_read(ah, AR5K_RXDP);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/*
40662306a36Sopenharmony_ci	 * Reset the device and wait until success
40762306a36Sopenharmony_ci	 */
40862306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* Wait at least 128 PCI clocks */
41162306a36Sopenharmony_ci	usleep_range(15, 20);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
41462306a36Sopenharmony_ci		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
41562306a36Sopenharmony_ci			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
41662306a36Sopenharmony_ci		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
41762306a36Sopenharmony_ci			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
41862306a36Sopenharmony_ci	} else {
41962306a36Sopenharmony_ci		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
42062306a36Sopenharmony_ci		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/*
42662306a36Sopenharmony_ci	 * Reset configuration register (for hw byte-swap). Note that this
42762306a36Sopenharmony_ci	 * is only set for big endian. We do the necessary magic in
42862306a36Sopenharmony_ci	 * AR5K_INIT_CFG.
42962306a36Sopenharmony_ci	 */
43062306a36Sopenharmony_ci	if ((val & AR5K_RESET_CTL_PCU) == 0)
43162306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return ret;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/**
43762306a36Sopenharmony_ci * ath5k_hw_wisoc_reset() -  Reset AHB chipset
43862306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
43962306a36Sopenharmony_ci * @flags: Mask to indicate what units to reset
44062306a36Sopenharmony_ci *
44162306a36Sopenharmony_ci * Same as ath5k_hw_nic_reset but for AHB based devices
44262306a36Sopenharmony_ci *
44362306a36Sopenharmony_ci * Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout)
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_cistatic int
44662306a36Sopenharmony_ciath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	u32 mask = flags ? flags : ~0U;
44962306a36Sopenharmony_ci	u32 __iomem *reg;
45062306a36Sopenharmony_ci	u32 regval;
45162306a36Sopenharmony_ci	u32 val = 0;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/* ah->ah_mac_srev is not available at this point yet */
45462306a36Sopenharmony_ci	if (ah->devid >= AR5K_SREV_AR2315_R6) {
45562306a36Sopenharmony_ci		reg = (u32 __iomem *) AR5K_AR2315_RESET;
45662306a36Sopenharmony_ci		if (mask & AR5K_RESET_CTL_PCU)
45762306a36Sopenharmony_ci			val |= AR5K_AR2315_RESET_WMAC;
45862306a36Sopenharmony_ci		if (mask & AR5K_RESET_CTL_BASEBAND)
45962306a36Sopenharmony_ci			val |= AR5K_AR2315_RESET_BB_WARM;
46062306a36Sopenharmony_ci	} else {
46162306a36Sopenharmony_ci		reg = (u32 __iomem *) AR5K_AR5312_RESET;
46262306a36Sopenharmony_ci		if (to_platform_device(ah->dev)->id == 0) {
46362306a36Sopenharmony_ci			if (mask & AR5K_RESET_CTL_PCU)
46462306a36Sopenharmony_ci				val |= AR5K_AR5312_RESET_WMAC0;
46562306a36Sopenharmony_ci			if (mask & AR5K_RESET_CTL_BASEBAND)
46662306a36Sopenharmony_ci				val |= AR5K_AR5312_RESET_BB0_COLD |
46762306a36Sopenharmony_ci				       AR5K_AR5312_RESET_BB0_WARM;
46862306a36Sopenharmony_ci		} else {
46962306a36Sopenharmony_ci			if (mask & AR5K_RESET_CTL_PCU)
47062306a36Sopenharmony_ci				val |= AR5K_AR5312_RESET_WMAC1;
47162306a36Sopenharmony_ci			if (mask & AR5K_RESET_CTL_BASEBAND)
47262306a36Sopenharmony_ci				val |= AR5K_AR5312_RESET_BB1_COLD |
47362306a36Sopenharmony_ci				       AR5K_AR5312_RESET_BB1_WARM;
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* Put BB/MAC into reset */
47862306a36Sopenharmony_ci	regval = ioread32(reg);
47962306a36Sopenharmony_ci	iowrite32(regval | val, reg);
48062306a36Sopenharmony_ci	regval = ioread32(reg);
48162306a36Sopenharmony_ci	udelay(100);	/* NB: should be atomic */
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* Bring BB/MAC out of reset */
48462306a36Sopenharmony_ci	iowrite32(regval & ~val, reg);
48562306a36Sopenharmony_ci	regval = ioread32(reg);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	/*
48862306a36Sopenharmony_ci	 * Reset configuration register (for hw byte-swap). Note that this
48962306a36Sopenharmony_ci	 * is only set for big endian. We do the necessary magic in
49062306a36Sopenharmony_ci	 * AR5K_INIT_CFG.
49162306a36Sopenharmony_ci	 */
49262306a36Sopenharmony_ci	if ((flags & AR5K_RESET_CTL_PCU) == 0)
49362306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	return 0;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci/**
49962306a36Sopenharmony_ci * ath5k_hw_set_power_mode() - Set power mode
50062306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
50162306a36Sopenharmony_ci * @mode: One of enum ath5k_power_mode
50262306a36Sopenharmony_ci * @set_chip: Set to true to write sleep control register
50362306a36Sopenharmony_ci * @sleep_duration: How much time the device is allowed to sleep
50462306a36Sopenharmony_ci * when sleep logic is enabled (in 128 microsecond increments).
50562306a36Sopenharmony_ci *
50662306a36Sopenharmony_ci * This function is used to configure sleep policy and allowed
50762306a36Sopenharmony_ci * sleep modes. For more information check out the sleep control
50862306a36Sopenharmony_ci * register on reg.h and STA_ID1.
50962306a36Sopenharmony_ci *
51062306a36Sopenharmony_ci * Returns 0 on success, -EIO if chip didn't wake up or -EINVAL if an invalid
51162306a36Sopenharmony_ci * mode is requested.
51262306a36Sopenharmony_ci */
51362306a36Sopenharmony_cistatic int
51462306a36Sopenharmony_ciath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode,
51562306a36Sopenharmony_ci			      bool set_chip, u16 sleep_duration)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	unsigned int i;
51862306a36Sopenharmony_ci	u32 staid, data;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	switch (mode) {
52362306a36Sopenharmony_ci	case AR5K_PM_AUTO:
52462306a36Sopenharmony_ci		staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
52562306a36Sopenharmony_ci		fallthrough;
52662306a36Sopenharmony_ci	case AR5K_PM_NETWORK_SLEEP:
52762306a36Sopenharmony_ci		if (set_chip)
52862306a36Sopenharmony_ci			ath5k_hw_reg_write(ah,
52962306a36Sopenharmony_ci				AR5K_SLEEP_CTL_SLE_ALLOW |
53062306a36Sopenharmony_ci				sleep_duration,
53162306a36Sopenharmony_ci				AR5K_SLEEP_CTL);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		staid |= AR5K_STA_ID1_PWR_SV;
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	case AR5K_PM_FULL_SLEEP:
53762306a36Sopenharmony_ci		if (set_chip)
53862306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
53962306a36Sopenharmony_ci				AR5K_SLEEP_CTL);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci		staid |= AR5K_STA_ID1_PWR_SV;
54262306a36Sopenharmony_ci		break;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	case AR5K_PM_AWAKE:
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		staid &= ~AR5K_STA_ID1_PWR_SV;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		if (!set_chip)
54962306a36Sopenharmony_ci			goto commit;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		/* If card is down we 'll get 0xffff... so we
55462306a36Sopenharmony_ci		 * need to clean this up before we write the register
55562306a36Sopenharmony_ci		 */
55662306a36Sopenharmony_ci		if (data & 0xffc00000)
55762306a36Sopenharmony_ci			data = 0;
55862306a36Sopenharmony_ci		else
55962306a36Sopenharmony_ci			/* Preserve sleep duration etc */
56062306a36Sopenharmony_ci			data = data & ~AR5K_SLEEP_CTL_SLE;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
56362306a36Sopenharmony_ci							AR5K_SLEEP_CTL);
56462306a36Sopenharmony_ci		usleep_range(15, 20);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		for (i = 200; i > 0; i--) {
56762306a36Sopenharmony_ci			/* Check if the chip did wake up */
56862306a36Sopenharmony_ci			if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
56962306a36Sopenharmony_ci					AR5K_PCICFG_SPWR_DN) == 0)
57062306a36Sopenharmony_ci				break;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci			/* Wait a bit and retry */
57362306a36Sopenharmony_ci			usleep_range(50, 75);
57462306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
57562306a36Sopenharmony_ci							AR5K_SLEEP_CTL);
57662306a36Sopenharmony_ci		}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		/* Fail if the chip didn't wake up */
57962306a36Sopenharmony_ci		if (i == 0)
58062306a36Sopenharmony_ci			return -EIO;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci		break;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	default:
58562306a36Sopenharmony_ci		return -EINVAL;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cicommit:
58962306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	return 0;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/**
59562306a36Sopenharmony_ci * ath5k_hw_on_hold() - Put device on hold
59662306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
59762306a36Sopenharmony_ci *
59862306a36Sopenharmony_ci * Put MAC and Baseband on warm reset and keep that state
59962306a36Sopenharmony_ci * (don't clean sleep control register). After this MAC
60062306a36Sopenharmony_ci * and Baseband are disabled and a full reset is needed
60162306a36Sopenharmony_ci * to come back. This way we save as much power as possible
60262306a36Sopenharmony_ci * without putting the card on full sleep.
60362306a36Sopenharmony_ci *
60462306a36Sopenharmony_ci * Returns 0 on success or -EIO on error
60562306a36Sopenharmony_ci */
60662306a36Sopenharmony_ciint
60762306a36Sopenharmony_ciath5k_hw_on_hold(struct ath5k_hw *ah)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	struct pci_dev *pdev = ah->pdev;
61062306a36Sopenharmony_ci	u32 bus_flags;
61162306a36Sopenharmony_ci	int ret;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (ath5k_get_bus_type(ah) == ATH_AHB)
61462306a36Sopenharmony_ci		return 0;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* Make sure device is awake */
61762306a36Sopenharmony_ci	ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
61862306a36Sopenharmony_ci	if (ret) {
61962306a36Sopenharmony_ci		ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n");
62062306a36Sopenharmony_ci		return ret;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/*
62462306a36Sopenharmony_ci	 * Put chipset on warm reset...
62562306a36Sopenharmony_ci	 *
62662306a36Sopenharmony_ci	 * Note: putting PCI core on warm reset on PCI-E cards
62762306a36Sopenharmony_ci	 * results card to hang and always return 0xffff... so
62862306a36Sopenharmony_ci	 * we ignore that flag for PCI-E cards. On PCI cards
62962306a36Sopenharmony_ci	 * this flag gets cleared after 64 PCI clocks.
63062306a36Sopenharmony_ci	 */
63162306a36Sopenharmony_ci	bus_flags = (pdev && pci_is_pcie(pdev)) ? 0 : AR5K_RESET_CTL_PCI;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
63462306a36Sopenharmony_ci		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
63562306a36Sopenharmony_ci			AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
63662306a36Sopenharmony_ci			AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
63762306a36Sopenharmony_ci		usleep_range(2000, 2500);
63862306a36Sopenharmony_ci	} else {
63962306a36Sopenharmony_ci		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
64062306a36Sopenharmony_ci			AR5K_RESET_CTL_BASEBAND | bus_flags);
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (ret) {
64462306a36Sopenharmony_ci		ATH5K_ERR(ah, "failed to put device on warm reset\n");
64562306a36Sopenharmony_ci		return -EIO;
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* ...wakeup again!*/
64962306a36Sopenharmony_ci	ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
65062306a36Sopenharmony_ci	if (ret) {
65162306a36Sopenharmony_ci		ATH5K_ERR(ah, "failed to put device on hold\n");
65262306a36Sopenharmony_ci		return ret;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	return ret;
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci/**
65962306a36Sopenharmony_ci * ath5k_hw_nic_wakeup() - Force card out of sleep
66062306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
66162306a36Sopenharmony_ci * @channel: The &struct ieee80211_channel
66262306a36Sopenharmony_ci *
66362306a36Sopenharmony_ci * Bring up MAC + PHY Chips and program PLL
66462306a36Sopenharmony_ci * NOTE: Channel is NULL for the initial wakeup.
66562306a36Sopenharmony_ci *
66662306a36Sopenharmony_ci * Returns 0 on success, -EIO on hw failure or -EINVAL for false channel infos
66762306a36Sopenharmony_ci */
66862306a36Sopenharmony_ciint
66962306a36Sopenharmony_ciath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct pci_dev *pdev = ah->pdev;
67262306a36Sopenharmony_ci	u32 turbo, mode, clock, bus_flags;
67362306a36Sopenharmony_ci	int ret;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	turbo = 0;
67662306a36Sopenharmony_ci	mode = 0;
67762306a36Sopenharmony_ci	clock = 0;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) {
68062306a36Sopenharmony_ci		/* Wakeup the device */
68162306a36Sopenharmony_ci		ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
68262306a36Sopenharmony_ci		if (ret) {
68362306a36Sopenharmony_ci			ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n");
68462306a36Sopenharmony_ci			return ret;
68562306a36Sopenharmony_ci		}
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/*
68962306a36Sopenharmony_ci	 * Put chipset on warm reset...
69062306a36Sopenharmony_ci	 *
69162306a36Sopenharmony_ci	 * Note: putting PCI core on warm reset on PCI-E cards
69262306a36Sopenharmony_ci	 * results card to hang and always return 0xffff... so
69362306a36Sopenharmony_ci	 * we ignore that flag for PCI-E cards. On PCI cards
69462306a36Sopenharmony_ci	 * this flag gets cleared after 64 PCI clocks.
69562306a36Sopenharmony_ci	 */
69662306a36Sopenharmony_ci	bus_flags = (pdev && pci_is_pcie(pdev)) ? 0 : AR5K_RESET_CTL_PCI;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
69962306a36Sopenharmony_ci		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
70062306a36Sopenharmony_ci			AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
70162306a36Sopenharmony_ci			AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
70262306a36Sopenharmony_ci		usleep_range(2000, 2500);
70362306a36Sopenharmony_ci	} else {
70462306a36Sopenharmony_ci		if (ath5k_get_bus_type(ah) == ATH_AHB)
70562306a36Sopenharmony_ci			ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU |
70662306a36Sopenharmony_ci				AR5K_RESET_CTL_BASEBAND);
70762306a36Sopenharmony_ci		else
70862306a36Sopenharmony_ci			ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
70962306a36Sopenharmony_ci				AR5K_RESET_CTL_BASEBAND | bus_flags);
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (ret) {
71362306a36Sopenharmony_ci		ATH5K_ERR(ah, "failed to reset the MAC Chip\n");
71462306a36Sopenharmony_ci		return -EIO;
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* ...wakeup again!...*/
71862306a36Sopenharmony_ci	ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
71962306a36Sopenharmony_ci	if (ret) {
72062306a36Sopenharmony_ci		ATH5K_ERR(ah, "failed to resume the MAC Chip\n");
72162306a36Sopenharmony_ci		return ret;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* ...reset configuration register on Wisoc ...
72562306a36Sopenharmony_ci	 * ...clear reset control register and pull device out of
72662306a36Sopenharmony_ci	 * warm reset on others */
72762306a36Sopenharmony_ci	if (ath5k_get_bus_type(ah) == ATH_AHB)
72862306a36Sopenharmony_ci		ret = ath5k_hw_wisoc_reset(ah, 0);
72962306a36Sopenharmony_ci	else
73062306a36Sopenharmony_ci		ret = ath5k_hw_nic_reset(ah, 0);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (ret) {
73362306a36Sopenharmony_ci		ATH5K_ERR(ah, "failed to warm reset the MAC Chip\n");
73462306a36Sopenharmony_ci		return -EIO;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	/* On initialization skip PLL programming since we don't have
73862306a36Sopenharmony_ci	 * a channel / mode set yet */
73962306a36Sopenharmony_ci	if (!channel)
74062306a36Sopenharmony_ci		return 0;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210) {
74362306a36Sopenharmony_ci		/*
74462306a36Sopenharmony_ci		 * Get channel mode flags
74562306a36Sopenharmony_ci		 */
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		if (ah->ah_radio >= AR5K_RF5112) {
74862306a36Sopenharmony_ci			mode = AR5K_PHY_MODE_RAD_RF5112;
74962306a36Sopenharmony_ci			clock = AR5K_PHY_PLL_RF5112;
75062306a36Sopenharmony_ci		} else {
75162306a36Sopenharmony_ci			mode = AR5K_PHY_MODE_RAD_RF5111;	/*Zero*/
75262306a36Sopenharmony_ci			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
75362306a36Sopenharmony_ci		}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		if (channel->band == NL80211_BAND_2GHZ) {
75662306a36Sopenharmony_ci			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
75762306a36Sopenharmony_ci			clock |= AR5K_PHY_PLL_44MHZ;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci			if (channel->hw_value == AR5K_MODE_11B) {
76062306a36Sopenharmony_ci				mode |= AR5K_PHY_MODE_MOD_CCK;
76162306a36Sopenharmony_ci			} else {
76262306a36Sopenharmony_ci				/* XXX Dynamic OFDM/CCK is not supported by the
76362306a36Sopenharmony_ci				 * AR5211 so we set MOD_OFDM for plain g (no
76462306a36Sopenharmony_ci				 * CCK headers) operation. We need to test
76562306a36Sopenharmony_ci				 * this, 5211 might support ofdm-only g after
76662306a36Sopenharmony_ci				 * all, there are also initial register values
76762306a36Sopenharmony_ci				 * in the code for g mode (see initvals.c).
76862306a36Sopenharmony_ci				 */
76962306a36Sopenharmony_ci				if (ah->ah_version == AR5K_AR5211)
77062306a36Sopenharmony_ci					mode |= AR5K_PHY_MODE_MOD_OFDM;
77162306a36Sopenharmony_ci				else
77262306a36Sopenharmony_ci					mode |= AR5K_PHY_MODE_MOD_DYN;
77362306a36Sopenharmony_ci			}
77462306a36Sopenharmony_ci		} else if (channel->band == NL80211_BAND_5GHZ) {
77562306a36Sopenharmony_ci			mode |= (AR5K_PHY_MODE_FREQ_5GHZ |
77662306a36Sopenharmony_ci				 AR5K_PHY_MODE_MOD_OFDM);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci			/* Different PLL setting for 5413 */
77962306a36Sopenharmony_ci			if (ah->ah_radio == AR5K_RF5413)
78062306a36Sopenharmony_ci				clock = AR5K_PHY_PLL_40MHZ_5413;
78162306a36Sopenharmony_ci			else
78262306a36Sopenharmony_ci				clock |= AR5K_PHY_PLL_40MHZ;
78362306a36Sopenharmony_ci		} else {
78462306a36Sopenharmony_ci			ATH5K_ERR(ah, "invalid radio frequency mode\n");
78562306a36Sopenharmony_ci			return -EINVAL;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci		/*XXX: Can bwmode be used with dynamic mode ?
78962306a36Sopenharmony_ci		 * (I don't think it supports 44MHz) */
79062306a36Sopenharmony_ci		/* On 2425 initvals TURBO_SHORT is not present */
79162306a36Sopenharmony_ci		if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
79262306a36Sopenharmony_ci			turbo = AR5K_PHY_TURBO_MODE;
79362306a36Sopenharmony_ci			if (ah->ah_radio != AR5K_RF2425)
79462306a36Sopenharmony_ci				turbo |= AR5K_PHY_TURBO_SHORT;
79562306a36Sopenharmony_ci		} else if (ah->ah_bwmode != AR5K_BWMODE_DEFAULT) {
79662306a36Sopenharmony_ci			if (ah->ah_radio == AR5K_RF5413) {
79762306a36Sopenharmony_ci				mode |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ?
79862306a36Sopenharmony_ci					AR5K_PHY_MODE_HALF_RATE :
79962306a36Sopenharmony_ci					AR5K_PHY_MODE_QUARTER_RATE;
80062306a36Sopenharmony_ci			} else if (ah->ah_version == AR5K_AR5212) {
80162306a36Sopenharmony_ci				clock |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ?
80262306a36Sopenharmony_ci					AR5K_PHY_PLL_HALF_RATE :
80362306a36Sopenharmony_ci					AR5K_PHY_PLL_QUARTER_RATE;
80462306a36Sopenharmony_ci			}
80562306a36Sopenharmony_ci		}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	} else { /* Reset the device */
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		/* ...enable Atheros turbo mode if requested */
81062306a36Sopenharmony_ci		if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
81162306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
81262306a36Sopenharmony_ci					AR5K_PHY_TURBO);
81362306a36Sopenharmony_ci	}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210) {
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci		/* ...update PLL if needed */
81862306a36Sopenharmony_ci		if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
81962306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
82062306a36Sopenharmony_ci			usleep_range(300, 350);
82162306a36Sopenharmony_ci		}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		/* ...set the PHY operating mode */
82462306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
82562306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	return 0;
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci/**************************************\
83362306a36Sopenharmony_ci* Post-initvals register modifications *
83462306a36Sopenharmony_ci\**************************************/
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci/**
83762306a36Sopenharmony_ci * ath5k_hw_tweak_initval_settings() - Tweak initial settings
83862306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
83962306a36Sopenharmony_ci * @channel: The &struct ieee80211_channel
84062306a36Sopenharmony_ci *
84162306a36Sopenharmony_ci * Some settings are not handled on initvals, e.g. bwmode
84262306a36Sopenharmony_ci * settings, some phy settings, workarounds etc that in general
84362306a36Sopenharmony_ci * don't fit anywhere else or are too small to introduce a separate
84462306a36Sopenharmony_ci * function for each one. So we have this function to handle
84562306a36Sopenharmony_ci * them all during reset and complete card's initialization.
84662306a36Sopenharmony_ci */
84762306a36Sopenharmony_cistatic void
84862306a36Sopenharmony_ciath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
84962306a36Sopenharmony_ci				struct ieee80211_channel *channel)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5212 &&
85262306a36Sopenharmony_ci	    ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		/* Setup ADC control */
85562306a36Sopenharmony_ci		ath5k_hw_reg_write(ah,
85662306a36Sopenharmony_ci				(AR5K_REG_SM(2,
85762306a36Sopenharmony_ci				AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) |
85862306a36Sopenharmony_ci				AR5K_REG_SM(2,
85962306a36Sopenharmony_ci				AR5K_PHY_ADC_CTL_INBUFGAIN_ON) |
86062306a36Sopenharmony_ci				AR5K_PHY_ADC_CTL_PWD_DAC_OFF |
86162306a36Sopenharmony_ci				AR5K_PHY_ADC_CTL_PWD_ADC_OFF),
86262306a36Sopenharmony_ci				AR5K_PHY_ADC_CTL);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci		/* Disable barker RSSI threshold */
86762306a36Sopenharmony_ci		AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
86862306a36Sopenharmony_ci				AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
87162306a36Sopenharmony_ci			AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci		/* Set the mute mask */
87462306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */
87862306a36Sopenharmony_ci	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B)
87962306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	/* Enable DCU double buffering */
88262306a36Sopenharmony_ci	if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B)
88362306a36Sopenharmony_ci		AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
88462306a36Sopenharmony_ci				AR5K_TXCFG_DCU_DBL_BUF_DIS);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* Set fast ADC */
88762306a36Sopenharmony_ci	if ((ah->ah_radio == AR5K_RF5413) ||
88862306a36Sopenharmony_ci		(ah->ah_radio == AR5K_RF2317) ||
88962306a36Sopenharmony_ci		(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
89062306a36Sopenharmony_ci		u32 fast_adc = true;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci		if (channel->center_freq == 2462 ||
89362306a36Sopenharmony_ci		channel->center_freq == 2467)
89462306a36Sopenharmony_ci			fast_adc = 0;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		/* Only update if needed */
89762306a36Sopenharmony_ci		if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc)
89862306a36Sopenharmony_ci				ath5k_hw_reg_write(ah, fast_adc,
89962306a36Sopenharmony_ci						AR5K_PHY_FAST_ADC);
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	/* Fix for first revision of the RF5112 RF chipset */
90362306a36Sopenharmony_ci	if (ah->ah_radio == AR5K_RF5112 &&
90462306a36Sopenharmony_ci			ah->ah_radio_5ghz_revision <
90562306a36Sopenharmony_ci			AR5K_SREV_RAD_5112A) {
90662306a36Sopenharmony_ci		u32 data;
90762306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
90862306a36Sopenharmony_ci				AR5K_PHY_CCKTXCTL);
90962306a36Sopenharmony_ci		if (channel->band == NL80211_BAND_5GHZ)
91062306a36Sopenharmony_ci			data = 0xffb81020;
91162306a36Sopenharmony_ci		else
91262306a36Sopenharmony_ci			data = 0xffb80d20;
91362306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
91762306a36Sopenharmony_ci		/* Clear QCU/DCU clock gating register */
91862306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
91962306a36Sopenharmony_ci		/* Set DAC/ADC delays */
92062306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ_5311,
92162306a36Sopenharmony_ci						AR5K_PHY_SCAL);
92262306a36Sopenharmony_ci		/* Enable PCU FIFO corruption ECO */
92362306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
92462306a36Sopenharmony_ci					AR5K_DIAG_SW_ECO_ENABLE);
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	if (ah->ah_bwmode) {
92862306a36Sopenharmony_ci		/* Increase PHY switch and AGC settling time
92962306a36Sopenharmony_ci		 * on turbo mode (ath5k_hw_commit_eeprom_settings
93062306a36Sopenharmony_ci		 * will override settling time if available) */
93162306a36Sopenharmony_ci		if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
93462306a36Sopenharmony_ci						AR5K_PHY_SETTLING_AGC,
93562306a36Sopenharmony_ci						AR5K_AGC_SETTLING_TURBO);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci			/* XXX: Initvals indicate we only increase
93862306a36Sopenharmony_ci			 * switch time on AR5212, 5211 and 5210
93962306a36Sopenharmony_ci			 * only change agc time (bug?) */
94062306a36Sopenharmony_ci			if (ah->ah_version == AR5K_AR5212)
94162306a36Sopenharmony_ci				AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
94262306a36Sopenharmony_ci						AR5K_PHY_SETTLING_SWITCH,
94362306a36Sopenharmony_ci						AR5K_SWITCH_SETTLING_TURBO);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci			if (ah->ah_version == AR5K_AR5210) {
94662306a36Sopenharmony_ci				/* Set Frame Control Register */
94762306a36Sopenharmony_ci				ath5k_hw_reg_write(ah,
94862306a36Sopenharmony_ci					(AR5K_PHY_FRAME_CTL_INI |
94962306a36Sopenharmony_ci					AR5K_PHY_TURBO_MODE |
95062306a36Sopenharmony_ci					AR5K_PHY_TURBO_SHORT | 0x2020),
95162306a36Sopenharmony_ci					AR5K_PHY_FRAME_CTL_5210);
95262306a36Sopenharmony_ci			}
95362306a36Sopenharmony_ci		/* On 5413 PHY force window length for half/quarter rate*/
95462306a36Sopenharmony_ci		} else if ((ah->ah_mac_srev >= AR5K_SREV_AR5424) &&
95562306a36Sopenharmony_ci		(ah->ah_mac_srev <= AR5K_SREV_AR5414)) {
95662306a36Sopenharmony_ci			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL_5211,
95762306a36Sopenharmony_ci						AR5K_PHY_FRAME_CTL_WIN_LEN,
95862306a36Sopenharmony_ci						3);
95962306a36Sopenharmony_ci		}
96062306a36Sopenharmony_ci	} else if (ah->ah_version == AR5K_AR5210) {
96162306a36Sopenharmony_ci		/* Set Frame Control Register for normal operation */
96262306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, (AR5K_PHY_FRAME_CTL_INI | 0x1020),
96362306a36Sopenharmony_ci						AR5K_PHY_FRAME_CTL_5210);
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci/**
96862306a36Sopenharmony_ci * ath5k_hw_commit_eeprom_settings() - Commit settings from EEPROM
96962306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
97062306a36Sopenharmony_ci * @channel: The &struct ieee80211_channel
97162306a36Sopenharmony_ci *
97262306a36Sopenharmony_ci * Use settings stored on EEPROM to properly initialize the card
97362306a36Sopenharmony_ci * based on various infos and per-mode calibration data.
97462306a36Sopenharmony_ci */
97562306a36Sopenharmony_cistatic void
97662306a36Sopenharmony_ciath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
97762306a36Sopenharmony_ci		struct ieee80211_channel *channel)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
98062306a36Sopenharmony_ci	s16 cck_ofdm_pwr_delta;
98162306a36Sopenharmony_ci	u8 ee_mode;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/* TODO: Add support for AR5210 EEPROM */
98462306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210)
98562306a36Sopenharmony_ci		return;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	ee_mode = ath5k_eeprom_mode_from_channel(ah, channel);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/* Adjust power delta for channel 14 */
99062306a36Sopenharmony_ci	if (channel->center_freq == 2484)
99162306a36Sopenharmony_ci		cck_ofdm_pwr_delta =
99262306a36Sopenharmony_ci			((ee->ee_cck_ofdm_power_delta -
99362306a36Sopenharmony_ci			ee->ee_scaled_cck_delta) * 2) / 10;
99462306a36Sopenharmony_ci	else
99562306a36Sopenharmony_ci		cck_ofdm_pwr_delta =
99662306a36Sopenharmony_ci			(ee->ee_cck_ofdm_power_delta * 2) / 10;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	/* Set CCK to OFDM power delta on tx power
99962306a36Sopenharmony_ci	 * adjustment register */
100062306a36Sopenharmony_ci	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
100162306a36Sopenharmony_ci		if (channel->hw_value == AR5K_MODE_11G)
100262306a36Sopenharmony_ci			ath5k_hw_reg_write(ah,
100362306a36Sopenharmony_ci			AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1),
100462306a36Sopenharmony_ci				AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
100562306a36Sopenharmony_ci			AR5K_REG_SM((cck_ofdm_pwr_delta * -1),
100662306a36Sopenharmony_ci				AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX),
100762306a36Sopenharmony_ci				AR5K_PHY_TX_PWR_ADJ);
100862306a36Sopenharmony_ci		else
100962306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ);
101062306a36Sopenharmony_ci	} else {
101162306a36Sopenharmony_ci		/* For older revs we scale power on sw during tx power
101262306a36Sopenharmony_ci		 * setup */
101362306a36Sopenharmony_ci		ah->ah_txpower.txp_cck_ofdm_pwr_delta = cck_ofdm_pwr_delta;
101462306a36Sopenharmony_ci		ah->ah_txpower.txp_cck_ofdm_gainf_delta =
101562306a36Sopenharmony_ci						ee->ee_cck_ofdm_gain_delta;
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* XXX: necessary here? is called from ath5k_hw_set_antenna_mode()
101962306a36Sopenharmony_ci	 * too */
102062306a36Sopenharmony_ci	ath5k_hw_set_antenna_switch(ah, ee_mode);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* Noise floor threshold */
102362306a36Sopenharmony_ci	ath5k_hw_reg_write(ah,
102462306a36Sopenharmony_ci		AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
102562306a36Sopenharmony_ci		AR5K_PHY_NFTHRES);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if ((ah->ah_bwmode == AR5K_BWMODE_40MHZ) &&
102862306a36Sopenharmony_ci	(ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
102962306a36Sopenharmony_ci		/* Switch settling time (Turbo) */
103062306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
103162306a36Sopenharmony_ci				AR5K_PHY_SETTLING_SWITCH,
103262306a36Sopenharmony_ci				ee->ee_switch_settling_turbo[ee_mode]);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci		/* Tx/Rx attenuation (Turbo) */
103562306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
103662306a36Sopenharmony_ci				AR5K_PHY_GAIN_TXRX_ATTEN,
103762306a36Sopenharmony_ci				ee->ee_atn_tx_rx_turbo[ee_mode]);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci		/* ADC/PGA desired size (Turbo) */
104062306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
104162306a36Sopenharmony_ci				AR5K_PHY_DESIRED_SIZE_ADC,
104262306a36Sopenharmony_ci				ee->ee_adc_desired_size_turbo[ee_mode]);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
104562306a36Sopenharmony_ci				AR5K_PHY_DESIRED_SIZE_PGA,
104662306a36Sopenharmony_ci				ee->ee_pga_desired_size_turbo[ee_mode]);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		/* Tx/Rx margin (Turbo) */
104962306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
105062306a36Sopenharmony_ci				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
105162306a36Sopenharmony_ci				ee->ee_margin_tx_rx_turbo[ee_mode]);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	} else {
105462306a36Sopenharmony_ci		/* Switch settling time */
105562306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
105662306a36Sopenharmony_ci				AR5K_PHY_SETTLING_SWITCH,
105762306a36Sopenharmony_ci				ee->ee_switch_settling[ee_mode]);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci		/* Tx/Rx attenuation */
106062306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
106162306a36Sopenharmony_ci				AR5K_PHY_GAIN_TXRX_ATTEN,
106262306a36Sopenharmony_ci				ee->ee_atn_tx_rx[ee_mode]);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci		/* ADC/PGA desired size */
106562306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
106662306a36Sopenharmony_ci				AR5K_PHY_DESIRED_SIZE_ADC,
106762306a36Sopenharmony_ci				ee->ee_adc_desired_size[ee_mode]);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
107062306a36Sopenharmony_ci				AR5K_PHY_DESIRED_SIZE_PGA,
107162306a36Sopenharmony_ci				ee->ee_pga_desired_size[ee_mode]);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci		/* Tx/Rx margin */
107462306a36Sopenharmony_ci		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
107562306a36Sopenharmony_ci			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
107662306a36Sopenharmony_ci				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
107762306a36Sopenharmony_ci				ee->ee_margin_tx_rx[ee_mode]);
107862306a36Sopenharmony_ci	}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	/* XPA delays */
108162306a36Sopenharmony_ci	ath5k_hw_reg_write(ah,
108262306a36Sopenharmony_ci		(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
108362306a36Sopenharmony_ci		(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
108462306a36Sopenharmony_ci		(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
108562306a36Sopenharmony_ci		(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	/* XLNA delay */
108862306a36Sopenharmony_ci	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3,
108962306a36Sopenharmony_ci			AR5K_PHY_RF_CTL3_TXE2XLNA_ON,
109062306a36Sopenharmony_ci			ee->ee_tx_end2xlna_enable[ee_mode]);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	/* Thresh64 (ANI) */
109362306a36Sopenharmony_ci	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF,
109462306a36Sopenharmony_ci			AR5K_PHY_NF_THRESH62,
109562306a36Sopenharmony_ci			ee->ee_thr_62[ee_mode]);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	/* False detect backoff for channels
109862306a36Sopenharmony_ci	 * that have spur noise. Write the new
109962306a36Sopenharmony_ci	 * cyclic power RSSI threshold. */
110062306a36Sopenharmony_ci	if (ath5k_hw_chan_has_spur_noise(ah, channel))
110162306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
110262306a36Sopenharmony_ci				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
110362306a36Sopenharmony_ci				AR5K_INIT_CYCRSSI_THR1 +
110462306a36Sopenharmony_ci				ee->ee_false_detect[ee_mode]);
110562306a36Sopenharmony_ci	else
110662306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
110762306a36Sopenharmony_ci				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
110862306a36Sopenharmony_ci				AR5K_INIT_CYCRSSI_THR1);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	/* I/Q correction (set enable bit last to match HAL sources) */
111162306a36Sopenharmony_ci	/* TODO: Per channel i/q infos ? */
111262306a36Sopenharmony_ci	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
111362306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF,
111462306a36Sopenharmony_ci			    ee->ee_i_cal[ee_mode]);
111562306a36Sopenharmony_ci		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF,
111662306a36Sopenharmony_ci			    ee->ee_q_cal[ee_mode]);
111762306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE);
111862306a36Sopenharmony_ci	}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	/* Heavy clipping -disable for now */
112162306a36Sopenharmony_ci	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
112262306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
112362306a36Sopenharmony_ci}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci/*********************\
112762306a36Sopenharmony_ci* Main reset function *
112862306a36Sopenharmony_ci\*********************/
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci/**
113162306a36Sopenharmony_ci * ath5k_hw_reset() - The main reset function
113262306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
113362306a36Sopenharmony_ci * @op_mode: One of enum nl80211_iftype
113462306a36Sopenharmony_ci * @channel: The &struct ieee80211_channel
113562306a36Sopenharmony_ci * @fast: Enable fast channel switching
113662306a36Sopenharmony_ci * @skip_pcu: Skip pcu initialization
113762306a36Sopenharmony_ci *
113862306a36Sopenharmony_ci * This is the function we call each time we want to (re)initialize the
113962306a36Sopenharmony_ci * card and pass new settings to hw. We also call it when hw runs into
114062306a36Sopenharmony_ci * trouble to make it come back to a working state.
114162306a36Sopenharmony_ci *
114262306a36Sopenharmony_ci * Returns 0 on success, -EINVAL on false op_mode or channel infos, or -EIO
114362306a36Sopenharmony_ci * on failure.
114462306a36Sopenharmony_ci */
114562306a36Sopenharmony_ciint
114662306a36Sopenharmony_ciath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
114762306a36Sopenharmony_ci		struct ieee80211_channel *channel, bool fast, bool skip_pcu)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	u32 s_seq[10], s_led[3], tsf_up, tsf_lo;
115062306a36Sopenharmony_ci	u8 mode;
115162306a36Sopenharmony_ci	int i, ret;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	tsf_up = 0;
115462306a36Sopenharmony_ci	tsf_lo = 0;
115562306a36Sopenharmony_ci	mode = 0;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	/*
115862306a36Sopenharmony_ci	 * Sanity check for fast flag
115962306a36Sopenharmony_ci	 * Fast channel change only available
116062306a36Sopenharmony_ci	 * on AR2413/AR5413.
116162306a36Sopenharmony_ci	 */
116262306a36Sopenharmony_ci	if (fast && (ah->ah_radio != AR5K_RF2413) &&
116362306a36Sopenharmony_ci	(ah->ah_radio != AR5K_RF5413))
116462306a36Sopenharmony_ci		fast = false;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	/* Disable sleep clock operation
116762306a36Sopenharmony_ci	 * to avoid register access delay on certain
116862306a36Sopenharmony_ci	 * PHY registers */
116962306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5212)
117062306a36Sopenharmony_ci		ath5k_hw_set_sleep_clock(ah, false);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	mode = channel->hw_value;
117362306a36Sopenharmony_ci	switch (mode) {
117462306a36Sopenharmony_ci	case AR5K_MODE_11A:
117562306a36Sopenharmony_ci		break;
117662306a36Sopenharmony_ci	case AR5K_MODE_11G:
117762306a36Sopenharmony_ci		if (ah->ah_version <= AR5K_AR5211) {
117862306a36Sopenharmony_ci			ATH5K_ERR(ah,
117962306a36Sopenharmony_ci				"G mode not available on 5210/5211");
118062306a36Sopenharmony_ci			return -EINVAL;
118162306a36Sopenharmony_ci		}
118262306a36Sopenharmony_ci		break;
118362306a36Sopenharmony_ci	case AR5K_MODE_11B:
118462306a36Sopenharmony_ci		if (ah->ah_version < AR5K_AR5211) {
118562306a36Sopenharmony_ci			ATH5K_ERR(ah,
118662306a36Sopenharmony_ci				"B mode not available on 5210");
118762306a36Sopenharmony_ci			return -EINVAL;
118862306a36Sopenharmony_ci		}
118962306a36Sopenharmony_ci		break;
119062306a36Sopenharmony_ci	default:
119162306a36Sopenharmony_ci		ATH5K_ERR(ah,
119262306a36Sopenharmony_ci			"invalid channel: %d\n", channel->center_freq);
119362306a36Sopenharmony_ci		return -EINVAL;
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	/*
119762306a36Sopenharmony_ci	 * If driver requested fast channel change and DMA has stopped
119862306a36Sopenharmony_ci	 * go on. If it fails continue with a normal reset.
119962306a36Sopenharmony_ci	 */
120062306a36Sopenharmony_ci	if (fast) {
120162306a36Sopenharmony_ci		ret = ath5k_hw_phy_init(ah, channel, mode, true);
120262306a36Sopenharmony_ci		if (ret) {
120362306a36Sopenharmony_ci			ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
120462306a36Sopenharmony_ci				"fast chan change failed, falling back to normal reset\n");
120562306a36Sopenharmony_ci			/* Non fatal, can happen eg.
120662306a36Sopenharmony_ci			 * on mode change */
120762306a36Sopenharmony_ci			ret = 0;
120862306a36Sopenharmony_ci		} else {
120962306a36Sopenharmony_ci			ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
121062306a36Sopenharmony_ci				"fast chan change successful\n");
121162306a36Sopenharmony_ci			return 0;
121262306a36Sopenharmony_ci		}
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	/*
121662306a36Sopenharmony_ci	 * Save some registers before a reset
121762306a36Sopenharmony_ci	 */
121862306a36Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210) {
121962306a36Sopenharmony_ci		/*
122062306a36Sopenharmony_ci		 * Save frame sequence count
122162306a36Sopenharmony_ci		 * For revs. after Oahu, only save
122262306a36Sopenharmony_ci		 * seq num for DCU 0 (Global seq num)
122362306a36Sopenharmony_ci		 */
122462306a36Sopenharmony_ci		if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci			for (i = 0; i < 10; i++)
122762306a36Sopenharmony_ci				s_seq[i] = ath5k_hw_reg_read(ah,
122862306a36Sopenharmony_ci					AR5K_QUEUE_DCU_SEQNUM(i));
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci		} else {
123162306a36Sopenharmony_ci			s_seq[0] = ath5k_hw_reg_read(ah,
123262306a36Sopenharmony_ci					AR5K_QUEUE_DCU_SEQNUM(0));
123362306a36Sopenharmony_ci		}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		/* TSF accelerates on AR5211 during reset
123662306a36Sopenharmony_ci		 * As a workaround save it here and restore
123762306a36Sopenharmony_ci		 * it later so that it's back in time after
123862306a36Sopenharmony_ci		 * reset. This way it'll get re-synced on the
123962306a36Sopenharmony_ci		 * next beacon without breaking ad-hoc.
124062306a36Sopenharmony_ci		 *
124162306a36Sopenharmony_ci		 * On AR5212 TSF is almost preserved across a
124262306a36Sopenharmony_ci		 * reset so it stays back in time anyway and
124362306a36Sopenharmony_ci		 * we don't have to save/restore it.
124462306a36Sopenharmony_ci		 *
124562306a36Sopenharmony_ci		 * XXX: Since this breaks power saving we have
124662306a36Sopenharmony_ci		 * to disable power saving until we receive the
124762306a36Sopenharmony_ci		 * next beacon, so we can resync beacon timers */
124862306a36Sopenharmony_ci		if (ah->ah_version == AR5K_AR5211) {
124962306a36Sopenharmony_ci			tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
125062306a36Sopenharmony_ci			tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
125162306a36Sopenharmony_ci		}
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/*GPIOs*/
125662306a36Sopenharmony_ci	s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) &
125762306a36Sopenharmony_ci					AR5K_PCICFG_LEDSTATE;
125862306a36Sopenharmony_ci	s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
125962306a36Sopenharmony_ci	s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/*
126362306a36Sopenharmony_ci	 * Since we are going to write rf buffer
126462306a36Sopenharmony_ci	 * check if we have any pending gain_F
126562306a36Sopenharmony_ci	 * optimization settings
126662306a36Sopenharmony_ci	 */
126762306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5212 &&
126862306a36Sopenharmony_ci	(ah->ah_radio <= AR5K_RF5112)) {
126962306a36Sopenharmony_ci		if (!fast && ah->ah_rf_banks != NULL)
127062306a36Sopenharmony_ci				ath5k_hw_gainf_calibrate(ah);
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	/* Wakeup the device */
127462306a36Sopenharmony_ci	ret = ath5k_hw_nic_wakeup(ah, channel);
127562306a36Sopenharmony_ci	if (ret)
127662306a36Sopenharmony_ci		return ret;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	/* PHY access enable */
127962306a36Sopenharmony_ci	if (ah->ah_mac_srev >= AR5K_SREV_AR5211)
128062306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
128162306a36Sopenharmony_ci	else
128262306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40,
128362306a36Sopenharmony_ci							AR5K_PHY(0));
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	/* Write initial settings */
128662306a36Sopenharmony_ci	ret = ath5k_hw_write_initvals(ah, mode, skip_pcu);
128762306a36Sopenharmony_ci	if (ret)
128862306a36Sopenharmony_ci		return ret;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/* Initialize core clock settings */
129162306a36Sopenharmony_ci	ath5k_hw_init_core_clock(ah);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	/*
129462306a36Sopenharmony_ci	 * Tweak initval settings for revised
129562306a36Sopenharmony_ci	 * chipsets and add some more config
129662306a36Sopenharmony_ci	 * bits
129762306a36Sopenharmony_ci	 */
129862306a36Sopenharmony_ci	ath5k_hw_tweak_initval_settings(ah, channel);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	/* Commit values from EEPROM */
130162306a36Sopenharmony_ci	ath5k_hw_commit_eeprom_settings(ah, channel);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/*
130562306a36Sopenharmony_ci	 * Restore saved values
130662306a36Sopenharmony_ci	 */
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	/* Seqnum, TSF */
130962306a36Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210) {
131062306a36Sopenharmony_ci		if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
131162306a36Sopenharmony_ci			for (i = 0; i < 10; i++)
131262306a36Sopenharmony_ci				ath5k_hw_reg_write(ah, s_seq[i],
131362306a36Sopenharmony_ci					AR5K_QUEUE_DCU_SEQNUM(i));
131462306a36Sopenharmony_ci		} else {
131562306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, s_seq[0],
131662306a36Sopenharmony_ci				AR5K_QUEUE_DCU_SEQNUM(0));
131762306a36Sopenharmony_ci		}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci		if (ah->ah_version == AR5K_AR5211) {
132062306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32);
132162306a36Sopenharmony_ci			ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
132262306a36Sopenharmony_ci		}
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	/* Ledstate */
132662306a36Sopenharmony_ci	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	/* Gpio settings */
132962306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
133062306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/*
133362306a36Sopenharmony_ci	 * Initialize PCU
133462306a36Sopenharmony_ci	 */
133562306a36Sopenharmony_ci	ath5k_hw_pcu_init(ah, op_mode);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	/*
133862306a36Sopenharmony_ci	 * Initialize PHY
133962306a36Sopenharmony_ci	 */
134062306a36Sopenharmony_ci	ret = ath5k_hw_phy_init(ah, channel, mode, false);
134162306a36Sopenharmony_ci	if (ret) {
134262306a36Sopenharmony_ci		ATH5K_ERR(ah,
134362306a36Sopenharmony_ci			"failed to initialize PHY (%i) !\n", ret);
134462306a36Sopenharmony_ci		return ret;
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	/*
134862306a36Sopenharmony_ci	 * Configure QCUs/DCUs
134962306a36Sopenharmony_ci	 */
135062306a36Sopenharmony_ci	ret = ath5k_hw_init_queues(ah);
135162306a36Sopenharmony_ci	if (ret)
135262306a36Sopenharmony_ci		return ret;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	/*
135662306a36Sopenharmony_ci	 * Initialize DMA/Interrupts
135762306a36Sopenharmony_ci	 */
135862306a36Sopenharmony_ci	ath5k_hw_dma_init(ah);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	/*
136262306a36Sopenharmony_ci	 * Enable 32KHz clock function for AR5212+ chips
136362306a36Sopenharmony_ci	 * Set clocks to 32KHz operation and use an
136462306a36Sopenharmony_ci	 * external 32KHz crystal when sleeping if one
136562306a36Sopenharmony_ci	 * exists.
136662306a36Sopenharmony_ci	 * Disabled by default because it is also disabled in
136762306a36Sopenharmony_ci	 * other drivers and it is known to cause stability
136862306a36Sopenharmony_ci	 * issues on some devices
136962306a36Sopenharmony_ci	 */
137062306a36Sopenharmony_ci	if (ah->ah_use_32khz_clock && ah->ah_version == AR5K_AR5212 &&
137162306a36Sopenharmony_ci	    op_mode != NL80211_IFTYPE_AP)
137262306a36Sopenharmony_ci		ath5k_hw_set_sleep_clock(ah, true);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	/*
137562306a36Sopenharmony_ci	 * Disable beacons and reset the TSF
137662306a36Sopenharmony_ci	 */
137762306a36Sopenharmony_ci	AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
137862306a36Sopenharmony_ci	ath5k_hw_reset_tsf(ah);
137962306a36Sopenharmony_ci	return 0;
138062306a36Sopenharmony_ci}
1381