ath5k: Update reset code
authorNick Kossifidis <mick@madwifi-project.org>
Mon, 9 Feb 2009 04:12:58 +0000 (06:12 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 13 Feb 2009 18:44:49 +0000 (13:44 -0500)
 * Update reset and sync with HALs

 * Clean up eeprom settings and tweaking of initvals and
   put them on separate functions

 * Set/Restore 32KHz ref clk operation

 * Add some more documentation

 TODO: Spur mitigation, tpc, half/quarter rate, compression etc

 v2: Address comments from Bob and Felix and fix RSSI threshold bug
 introduced on the first version of the patch

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath5k/ath5k.h
drivers/net/wireless/ath5k/attach.c
drivers/net/wireless/ath5k/eeprom.c
drivers/net/wireless/ath5k/eeprom.h
drivers/net/wireless/ath5k/reg.h
drivers/net/wireless/ath5k/reset.c

index 5b2e0da..b9af2b8 100644 (file)
 #endif
 
 /* Initial values */
+#define        AR5K_INIT_CYCRSSI_THR1                  2
 #define AR5K_INIT_TX_LATENCY                   502
 #define AR5K_INIT_USEC                         39
 #define AR5K_INIT_USEC_TURBO                   79
@@ -313,7 +314,7 @@ struct ath5k_srev_name {
 #define AR5K_SREV_AR5424       0x90 /* Condor */
 #define AR5K_SREV_AR5413       0xa4 /* Eagle lite */
 #define AR5K_SREV_AR5414       0xa0 /* Eagle */
-#define AR5K_SREV_AR2415       0xb0 /* Cobra */
+#define AR5K_SREV_AR2415       0xb0 /* Talon */
 #define AR5K_SREV_AR5416       0xc0 /* PCI-E */
 #define AR5K_SREV_AR5418       0xca /* PCI-E */
 #define AR5K_SREV_AR2425       0xe0 /* Swan */
@@ -331,7 +332,7 @@ struct ath5k_srev_name {
 #define        AR5K_SREV_RAD_2112B     0x46
 #define AR5K_SREV_RAD_2413     0x50
 #define AR5K_SREV_RAD_5413     0x60
-#define AR5K_SREV_RAD_2316     0x70
+#define AR5K_SREV_RAD_2316     0x70 /* Cobra SoC */
 #define AR5K_SREV_RAD_2317     0x80
 #define AR5K_SREV_RAD_5424     0xa0 /* Mostly same as 5413 */
 #define AR5K_SREV_RAD_2425     0xa2
@@ -340,7 +341,7 @@ struct ath5k_srev_name {
 #define AR5K_SREV_PHY_5211     0x30
 #define AR5K_SREV_PHY_5212     0x41
 #define        AR5K_SREV_PHY_5212A     0x42
-#define AR5K_SREV_PHY_2112B    0x43
+#define AR5K_SREV_PHY_5212B    0x43
 #define AR5K_SREV_PHY_2413     0x45
 #define AR5K_SREV_PHY_5413     0x61
 #define AR5K_SREV_PHY_2425     0x70
@@ -1030,7 +1031,6 @@ struct ath5k_hw {
        u16                     ah_phy_revision;
        u16                     ah_radio_5ghz_revision;
        u16                     ah_radio_2ghz_revision;
-       u32                     ah_phy_spending;
 
        enum ath5k_version      ah_version;
        enum ath5k_radio        ah_radio;
@@ -1156,6 +1156,7 @@ extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_l
 /* EEPROM access functions */
 extern int ath5k_eeprom_init(struct ath5k_hw *ah);
 extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
+extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
 
 /* Protocol Control Unit Functions */
 extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
@@ -1258,6 +1259,7 @@ extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power);
 
 /*
  * Translate usec to hw clock units
+ * TODO: Half/quarter rate
  */
 static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
 {
@@ -1266,6 +1268,7 @@ static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
 
 /*
  * Translate hw clock units to usec
+ * TODO: Half/quarter rate
  */
 static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
 {
index a3f07a4..05bc5cb 100644 (file)
@@ -169,7 +169,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
                ah->ah_single_chip = false;
                ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
                                                        CHANNEL_2GHZ);
-               ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
                break;
        case AR5K_SREV_RAD_5112:
        case AR5K_SREV_RAD_2112:
@@ -177,38 +176,31 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
                ah->ah_single_chip = false;
                ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
                                                        CHANNEL_2GHZ);
-               ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
                break;
        case AR5K_SREV_RAD_2413:
                ah->ah_radio = AR5K_RF2413;
                ah->ah_single_chip = true;
-               ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
                break;
        case AR5K_SREV_RAD_5413:
                ah->ah_radio = AR5K_RF5413;
                ah->ah_single_chip = true;
-               ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
                break;
        case AR5K_SREV_RAD_2316:
                ah->ah_radio = AR5K_RF2316;
                ah->ah_single_chip = true;
-               ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316;
                break;
        case AR5K_SREV_RAD_2317:
                ah->ah_radio = AR5K_RF2317;
                ah->ah_single_chip = true;
-               ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2317;
                break;
        case AR5K_SREV_RAD_5424:
                if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
                ah->ah_mac_version == AR5K_SREV_AR2417){
                        ah->ah_radio = AR5K_RF2425;
                        ah->ah_single_chip = true;
-                       ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
                } else {
                        ah->ah_radio = AR5K_RF5413;
                        ah->ah_single_chip = true;
-                       ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
                }
                break;
        default:
@@ -227,29 +219,25 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
                        ah->ah_radio = AR5K_RF2425;
                        ah->ah_single_chip = true;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
-                       ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
                } else if (srev == AR5K_SREV_AR5213A &&
-               ah->ah_phy_revision == AR5K_SREV_PHY_2112B) {
+               ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
                        ah->ah_radio = AR5K_RF5112;
                        ah->ah_single_chip = false;
-                       ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2112B;
+                       ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
                } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
                        ah->ah_radio = AR5K_RF2316;
                        ah->ah_single_chip = true;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
-                       ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316;
                } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
                ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
                        ah->ah_radio = AR5K_RF5413;
                        ah->ah_single_chip = true;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
-                       ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
                } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
                ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
                        ah->ah_radio = AR5K_RF2413;
                        ah->ah_single_chip = true;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
-                       ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
                } else {
                        ATH5K_ERR(sc, "Couldn't identify radio revision.\n");
                        ret = -ENODEV;
index b4ec539..21b9334 100644 (file)
@@ -204,7 +204,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
 
        /* Get antenna modes */
        ah->ah_antenna[mode][0] =
-           (ee->ee_ant_control[mode][0] << 4) | 0x1;
+           (ee->ee_ant_control[mode][0] << 4);
        ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
             ee->ee_ant_control[mode][1]        |
            (ee->ee_ant_control[mode][2] << 6)  |
@@ -1412,6 +1412,7 @@ ath5k_eeprom_init(struct ath5k_hw *ah)
 
        return 0;
 }
+
 /*
  * Read the MAC address from eeprom
  */
@@ -1448,3 +1449,14 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
        return 0;
 }
 
+bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah)
+{
+       u16 data;
+
+       ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data);
+
+       if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data)
+               return true;
+       else
+               return false;
+}
index 09eb7d0..1deebc0 100644 (file)
@@ -25,6 +25,7 @@
 #define AR5K_EEPROM_MAGIC_5211         0x0000145b /* 5211 */
 #define AR5K_EEPROM_MAGIC_5210         0x0000145a /* 5210 */
 
+#define        AR5K_EEPROM_IS_HB63             0x000b  /* Talon detect */
 #define AR5K_EEPROM_REG_DOMAIN         0x00bf  /* EEPROM regdom */
 #define AR5K_EEPROM_CHECKSUM           0x00c0  /* EEPROM checksum */
 #define AR5K_EEPROM_INFO_BASE          0x00c0  /* EEPROM header */
index 84f4669..2dc008e 100644 (file)
 #define AR5K_TXCFG_FRMPAD_DIS          0x00002000      /* [5211+] */
 #define AR5K_TXCFG_RDY_CBR_DIS         0x00004000      /* Ready time CBR disable [5211+] */
 #define AR5K_TXCFG_JUMBO_FRM_MODE      0x00008000      /* Jumbo frame mode [5211+] */
+#define        AR5K_TXCFG_DCU_DBL_BUF_DIS      0x00008000      /* Disable double buffering on DCU */
 #define AR5K_TXCFG_DCU_CACHING_DIS     0x00010000      /* Disable DCU caching */
 
 /*
  */
 #define AR5K_DCU_SEQNUM_BASE           0x1140
 #define        AR5K_DCU_SEQNUM_M               0x00000fff
-#define        AR5K_QUEUE_DFS_SEQNUM(_q)       AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
+#define        AR5K_QUEUE_DCU_SEQNUM(_q)       AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
 
 /*
  * DCU global IFS SIFS register
 #define AR5K_ADDAC_TEST_TRIG_PTY       0x00020000      /* Trigger polarity */
 #define AR5K_ADDAC_TEST_RXCONT         0x00040000      /* Continuous capture */
 #define AR5K_ADDAC_TEST_CAPTURE                0x00080000      /* Begin capture */
-#define AR5K_ADDAC_TEST_TST_ARM                0x00100000      /* Test ARM (Adaptive Radio Mode ?) */
+#define AR5K_ADDAC_TEST_TST_ARM                0x00100000      /* ARM rx buffer for capture */
 
 /*
  * Default antenna register [5211+]
  * TSF parameter register
  */
 #define AR5K_TSF_PARM                  0x8104                  /* Register Address */
-#define AR5K_TSF_PARM_INC_M            0x000000ff      /* Mask for TSF increment */
+#define AR5K_TSF_PARM_INC              0x000000ff      /* Mask for TSF increment */
 #define AR5K_TSF_PARM_INC_S            0
 
 /*
 #define AR5K_QOS_NOACK_BIT_OFFSET      0x00000070      /* ??? */
 #define AR5K_QOS_NOACK_BIT_OFFSET_S    4
 #define AR5K_QOS_NOACK_BYTE_OFFSET     0x00000180      /* ??? */
-#define AR5K_QOS_NOACK_BYTE_OFFSET_S   8
+#define AR5K_QOS_NOACK_BYTE_OFFSET_S   7
 
 /*
  * PHY error filter register
  * TST_2 (Misc config parameters)
  */
 #define        AR5K_PHY_TST2                   0x9800                  /* Register Address */
-#define AR5K_PHY_TST2_TRIG_SEL         0x00000001      /* Trigger select (?) (field ?) */
-#define AR5K_PHY_TST2_TRIG             0x00000010      /* Trigger (?) (field ?) */
-#define AR5K_PHY_TST2_CBUS_MODE                0x00000100      /* Cardbus mode (?) */
-/* bit reserved */
+#define AR5K_PHY_TST2_TRIG_SEL         0x00000007      /* Trigger select (?)*/
+#define AR5K_PHY_TST2_TRIG             0x00000010      /* Trigger (?) */
+#define AR5K_PHY_TST2_CBUS_MODE                0x00000060      /* Cardbus mode (?) */
 #define AR5K_PHY_TST2_CLK32            0x00000400      /* CLK_OUT is CLK32 (32Khz external) */
 #define AR5K_PHY_TST2_CHANCOR_DUMP_EN  0x00000800      /* Enable Chancor dump (?) */
 #define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP        0x00001000      /* Even Chancor dump (?) */
 #define AR5K_PHY_TST2_RFSILENT_EN      0x00002000      /* Enable RFSILENT */
-#define AR5K_PHY_TST2_ALT_RFDATA       0x00004000      /* Alternate RFDATA (5-2GHz switch) */
+#define AR5K_PHY_TST2_ALT_RFDATA       0x00004000      /* Alternate RFDATA (5-2GHz switch ?) */
 #define AR5K_PHY_TST2_MINI_OBS_EN      0x00008000      /* Enable mini OBS (?) */
 #define AR5K_PHY_TST2_RX2_IS_RX5_INV   0x00010000      /* 2GHz rx path is the 5GHz path inverted (?) */
 #define AR5K_PHY_TST2_SLOW_CLK160      0x00020000      /* Slow CLK160 (?) */
 #define        AR5K_PHY_RF_CTL2_TXF2TXD_START_S        0
 
 #define AR5K_PHY_RF_CTL3               0x9828                  /* Register Address */
-#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON   0x0000000f      /* TX end to XLNA on */
-#define        AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S  0
+#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON   0x0000ff00      /* TX end to XLNA on */
+#define        AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S  8
 
 #define        AR5K_PHY_ADC_CTL                        0x982c
 #define        AR5K_PHY_ADC_CTL_INBUFGAIN_OFF          0x00000003
 #define        AR5K_PHY_SETTLING_AGC           0x0000007f      /* AGC settling time */
 #define        AR5K_PHY_SETTLING_AGC_S         0
 #define        AR5K_PHY_SETTLING_SWITCH        0x00003f80      /* Switch settlig time */
-#define        AR5K_PHY_SETTLINK_SWITCH_S      7
+#define        AR5K_PHY_SETTLING_SWITCH_S      7
 
 /*
  * PHY Gain registers
  * PHY sleep registers [5112+]
  */
 #define AR5K_PHY_SCR                   0x9870
-#define AR5K_PHY_SCR_32MHZ             0x0000001f
 
 #define AR5K_PHY_SLMT                  0x9874
 #define AR5K_PHY_SLMT_32MHZ            0x0000007f
 
 #define AR5K_PHY_SCAL                  0x9878
 #define AR5K_PHY_SCAL_32MHZ            0x0000000e
-
+#define        AR5K_PHY_SCAL_32MHZ_2417        0x0000000a
+#define        AR5K_PHY_SCAL_32MHZ_HB63        0x00000032
 
 /*
  * PHY PLL (Phase Locked Loop) control register
 #define        AR5K_PHY_ANT_CTL_TXRX_EN        0x00000001      /* Enable TX/RX (?) */
 #define        AR5K_PHY_ANT_CTL_SECTORED_ANT   0x00000004      /* Sectored Antenna */
 #define        AR5K_PHY_ANT_CTL_HITUNE5        0x00000008      /* Hitune5 (?) */
-#define        AR5K_PHY_ANT_CTL_SWTABLE_IDLE   0x00000010      /* Switch table idle (?) */
+#define        AR5K_PHY_ANT_CTL_SWTABLE_IDLE   0x000003f0      /* Switch table idle (?) */
+#define        AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S 4
 
 /*
  * PHY receiver delay register [5111+]
 #define        AR5K_PHY_OFDM_SELFCORR                  0x9924                  /* Register Address */
 #define        AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN    0x00000001      /* Enable cyclic RSSI thr 1 */
 #define        AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1       0x000000fe      /* Mask for Cyclic RSSI threshold 1 */
-#define        AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S     0
+#define        AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S     1
 #define        AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3       0x00000100      /* Cyclic RSSI threshold 3 (field) (?) */
 #define        AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN    0x00008000      /* Enable 1A RSSI threshold (?) */
 #define        AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR       0x00010000      /* 1A RSSI threshold (field) (?) */
                        AR5K_PHY_FRAME_CTL_TIMING_ERR
 
 /*
+ * PHY Tx Power adjustment register [5212A+]
+ */
+#define        AR5K_PHY_TX_PWR_ADJ                     0x994c
+#define        AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA      0x00000fc0
+#define        AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S    6
+#define        AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX     0x00fc0000
+#define        AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S   18
+
+/*
  * PHY radar detection register [5111+]
  */
 #define        AR5K_PHY_RADAR                  0x9954
 #define AR5K_PHY_SIGMA_DELTA_FILT2_S   3
 #define AR5K_PHY_SIGMA_DELTA_FILT1     0x00001f00
 #define AR5K_PHY_SIGMA_DELTA_FILT1_S   8
-#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP  0x01ff3000
+#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP  0x01ffe000
 #define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S        13
 
 /*
 #define AR5K_PHY_SDELAY                        0x99f4
 #define AR5K_PHY_SDELAY_32MHZ          0x000000ff
 #define AR5K_PHY_SPENDING              0x99f8
-#define AR5K_PHY_SPENDING_14           0x00000014
-#define AR5K_PHY_SPENDING_18           0x00000018
-#define AR5K_PHY_SPENDING_RF5111       0x00000018
-#define AR5K_PHY_SPENDING_RF5112       0x00000014
-/* #define AR5K_PHY_SPENDING_RF5112A   0x0000000e */
-/* #define AR5K_PHY_SPENDING_RF5424    0x00000012 */
-#define AR5K_PHY_SPENDING_RF5413       0x00000018
-#define AR5K_PHY_SPENDING_RF2413       0x00000018
-#define AR5K_PHY_SPENDING_RF2316       0x00000018
-#define AR5K_PHY_SPENDING_RF2317       0x00000018
-#define AR5K_PHY_SPENDING_RF2425       0x00000014
+
 
 /*
  * PHY PAPD I (power?) table (?)
index 579c64c..1531ccd 100644 (file)
@@ -25,7 +25,8 @@
   Reset functions and helpers
 \*****************************/
 
-#include <linux/pci.h>
+#include <linux/pci.h>                 /* To determine if a card is pci-e */
+#include <linux/bitops.h>      /* For get_bitmask_order */
 #include "ath5k.h"
 #include "reg.h"
 #include "base.h"
  * @ah: the &struct ath5k_hw
  * @channel: the currently set channel upon reset
  *
- * Write the OFDM timings for the AR5212 upon reset. This is a helper for
- * ath5k_hw_reset(). This seems to tune the PLL a specified frequency
- * depending on the bandwidth of the channel.
+ * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
+ * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset().
  *
+ * Since delta slope is floating point we split it on its exponent and
+ * mantissa and provide these values on hw.
+ *
+ * For more infos i think this patent is related
+ * http://www.freepatentsonline.com/7184495.html
  */
 static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
        struct ieee80211_channel *channel)
@@ -53,23 +58,34 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
                !(channel->hw_value & CHANNEL_OFDM))
                BUG();
 
-       /* Seems there are two PLLs, one for baseband sampling and one
-        * for tuning. Tuning basebands are 40 MHz or 80MHz when in
-        * turbo. */
-       clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40;
-       coef_scaled = ((5 * (clock << 24)) / 2) /
-       channel->center_freq;
+       /* Get coefficient
+        * ALGO: coef = (5 * clock * carrier_freq) / 2)
+        * we scale coef by shifting clock value by 24 for
+        * better precision since we use integers */
+       /* TODO: Half/quarter rate */
+       clock =  ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO);
 
-       for (coef_exp = 31; coef_exp > 0; coef_exp--)
-               if ((coef_scaled >> coef_exp) & 0x1)
-                       break;
+       coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
+
+       /* Get exponent
+        * ALGO: coef_exp = 14 - highest set bit position */
+       coef_exp = get_bitmask_order(coef_scaled);
 
+       /* Doesn't make sense if it's zero*/
        if (!coef_exp)
                return -EINVAL;
 
+       /* Note: we've shifted coef_scaled by 24 */
        coef_exp = 14 - (coef_exp - 24);
+
+
+       /* Get mantissa (significant digits)
+        * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
        coef_man = coef_scaled +
                (1 << (24 - coef_exp - 1));
+
+       /* Calculate delta slope coefficient exponent
+        * and mantissa (remove scaling) and set them on hw */
        ds_coef_man = coef_man >> (24 - coef_exp);
        ds_coef_exp = coef_exp - 16;
 
@@ -90,16 +106,23 @@ static int control_rates[] =
        { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
 
 /**
- * ath5k_hw_write_rate_duration - set rate duration during hw resets
+ * ath5k_hw_write_rate_duration - fill rate code to duration table
  *
  * @ah: the &struct ath5k_hw
  * @mode: one of enum ath5k_driver_mode
  *
- * Write the rate duration table upon hw reset. This is a helper for
- * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout for
- * the hardware for the current mode for each rate. The rates which are capable
- * of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have another
- * register for the short preamble ACK timeout calculation.
+ * Write the rate code to duration table upon hw reset. This is a helper for
+ * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on
+ * the hardware, based on current mode, for each rate. The rates which are
+ * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
+ * different rate code so we write their value twice (one for long preample
+ * and one for short).
+ *
+ * Note: Band doesn't matter here, if we set the values for OFDM it works
+ * on both a and g modes. So all we have to do is set values for all g rates
+ * that include all OFDM and CCK rates. If we operate in turbo or xr/half/
+ * quarter rate mode, we need to use another set of bitrates (that's why we
+ * need the mode parameter) but we don't handle these proprietary modes yet.
  */
 static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
        unsigned int mode)
@@ -275,7 +298,8 @@ commit:
 }
 
 /*
- * Bring up MAC + PHY Chips
+ * Bring up MAC + PHY Chips and program PLL
+ * TODO: Half/Quarter rate support
  */
 int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 {
@@ -333,7 +357,11 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
                        }
                } else if (flags & CHANNEL_5GHZ) {
                        mode |= AR5K_PHY_MODE_FREQ_5GHZ;
-                       clock |= AR5K_PHY_PLL_40MHZ;
+
+                       if (ah->ah_radio == AR5K_RF5413)
+                               clock |= AR5K_PHY_PLL_40MHZ_5413;
+                       else
+                               clock |= AR5K_PHY_PLL_40MHZ;
 
                        if (flags & CHANNEL_OFDM)
                                mode |= AR5K_PHY_MODE_MOD_OFDM;
@@ -391,10 +419,14 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
        }
 
        if (ah->ah_version != AR5K_AR5210) {
-               /* ...set the PHY operating mode */
-               ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
-               udelay(300);
 
+               /* ...update PLL if needed */
+               if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
+                       ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
+                       udelay(300);
+               }
+
+               /* ...set the PHY operating mode */
                ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
                ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
        }
@@ -403,22 +435,393 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 }
 
 /*
+ * If there is an external 32KHz crystal available, use it
+ * as ref. clock instead of 32/40MHz clock and baseband clocks
+ * to save power during sleep or restore normal 32/40MHz
+ * operation.
+ *
+ * XXX: When operating on 32KHz certain PHY registers (27 - 31,
+ *     123 - 127) require delay on access.
+ */
+static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
+{
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+       u32 scal, spending, usec32;
+
+       /* Only set 32KHz settings if we have an external
+        * 32KHz crystal present */
+       if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) ||
+       AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) &&
+       enable) {
+
+               /* 1 usec/cycle */
+               AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1);
+               /* Set up tsf increment on each cycle */
+               AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61);
+
+               /* Set baseband sleep control registers
+                * and sleep control rate */
+               ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
+
+               if ((ah->ah_radio == AR5K_RF5112) ||
+               (ah->ah_radio == AR5K_RF5413) ||
+               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+                       spending = 0x14;
+               else
+                       spending = 0x18;
+               ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
+
+               if ((ah->ah_radio == AR5K_RF5112) ||
+               (ah->ah_radio == AR5K_RF5413) ||
+               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+                       ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
+                       ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
+                       ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
+                       ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
+               } else {
+                       ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT);
+                       ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL);
+                       ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK);
+                       ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY);
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03);
+               }
+
+               /* Enable sleep clock operation */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_EN);
+
+       } else {
+
+               /* Disable sleep clock operation and
+                * restore default parameters */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_EN);
+
+               AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0);
+
+               ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
+
+               if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
+                       scal = AR5K_PHY_SCAL_32MHZ_2417;
+               else if (ath5k_eeprom_is_hb63(ah))
+                       scal = AR5K_PHY_SCAL_32MHZ_HB63;
+               else
+                       scal = AR5K_PHY_SCAL_32MHZ;
+               ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
+
+               ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
+
+               if ((ah->ah_radio == AR5K_RF5112) ||
+               (ah->ah_radio == AR5K_RF5413) ||
+               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+                       spending = 0x14;
+               else
+                       spending = 0x18;
+               ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
+
+               if ((ah->ah_radio == AR5K_RF5112) ||
+               (ah->ah_radio == AR5K_RF5413))
+                       usec32 = 39;
+               else
+                       usec32 = 31;
+               AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, usec32);
+
+               AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
+       }
+       return;
+}
+
+static bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
+                               struct ieee80211_channel *channel)
+{
+       u8 refclk_freq;
+
+       if ((ah->ah_radio == AR5K_RF5112) ||
+       (ah->ah_radio == AR5K_RF5413) ||
+       (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+               refclk_freq = 40;
+       else
+               refclk_freq = 32;
+
+       if ((channel->center_freq % refclk_freq != 0) &&
+       ((channel->center_freq % refclk_freq < 10) ||
+       (channel->center_freq % refclk_freq > 22)))
+               return true;
+       else
+               return false;
+}
+
+/* TODO: Half/Quarter rate */
+static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
+                               struct ieee80211_channel *channel)
+{
+       if (ah->ah_version == AR5K_AR5212 &&
+           ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+
+               /* Setup ADC control */
+               ath5k_hw_reg_write(ah,
+                               (AR5K_REG_SM(2,
+                               AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) |
+                               AR5K_REG_SM(2,
+                               AR5K_PHY_ADC_CTL_INBUFGAIN_ON) |
+                               AR5K_PHY_ADC_CTL_PWD_DAC_OFF |
+                               AR5K_PHY_ADC_CTL_PWD_ADC_OFF),
+                               AR5K_PHY_ADC_CTL);
+
+
+
+               /* Disable barker RSSI threshold */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
+                               AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR);
+
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
+                       AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2);
+
+               /* Set the mute mask */
+               ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
+       }
+
+       /* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */
+       if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B)
+               ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH);
+
+       /* Enable DCU double buffering */
+       if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B)
+               AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+                               AR5K_TXCFG_DCU_DBL_BUF_DIS);
+
+       /* Set DAC/ADC delays */
+       if (ah->ah_version == AR5K_AR5212) {
+               u32 scal;
+               if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
+                       scal = AR5K_PHY_SCAL_32MHZ_2417;
+               else if (ath5k_eeprom_is_hb63(ah))
+                       scal = AR5K_PHY_SCAL_32MHZ_HB63;
+               else
+                       scal = AR5K_PHY_SCAL_32MHZ;
+               ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
+       }
+
+       /* Set fast ADC */
+       if ((ah->ah_radio == AR5K_RF5413) ||
+       (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+               u32 fast_adc = true;
+
+               if (channel->center_freq == 2462 ||
+               channel->center_freq == 2467)
+                       fast_adc = 0;
+
+               /* Only update if needed */
+               if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc)
+                               ath5k_hw_reg_write(ah, fast_adc,
+                                               AR5K_PHY_FAST_ADC);
+       }
+
+       /* Fix for first revision of the RF5112 RF chipset */
+       if (ah->ah_radio == AR5K_RF5112 &&
+                       ah->ah_radio_5ghz_revision <
+                       AR5K_SREV_RAD_5112A) {
+               u32 data;
+               ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
+                               AR5K_PHY_CCKTXCTL);
+               if (channel->hw_value & CHANNEL_5GHZ)
+                       data = 0xffb81020;
+               else
+                       data = 0xffb80d20;
+               ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+       }
+
+       if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+               u32 usec_reg;
+               /* 5311 has different tx/rx latency masks
+                * from 5211, since we deal 5311 the same
+                * as 5211 when setting initvals, shift
+                * values here to their proper locations */
+               usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
+               ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 |
+                               AR5K_USEC_32 |
+                               AR5K_USEC_TX_LATENCY_5211 |
+                               AR5K_REG_SM(29,
+                               AR5K_USEC_RX_LATENCY_5210)),
+                               AR5K_USEC_5211);
+               /* Clear QCU/DCU clock gating register */
+               ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
+               /* Set DAC/ADC delays */
+               ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL);
+               /* Enable PCU FIFO corruption ECO */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
+                                       AR5K_DIAG_SW_ECO_ENABLE);
+       }
+}
+
+static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel, u8 *ant, u8 ee_mode)
+{
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+
+       /* Set CCK to OFDM power delta */
+       if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+               int16_t cck_ofdm_pwr_delta;
+
+               /* Adjust power delta for channel 14 */
+               if (channel->center_freq == 2484)
+                       cck_ofdm_pwr_delta =
+                               ((ee->ee_cck_ofdm_power_delta -
+                               ee->ee_scaled_cck_delta) * 2) / 10;
+               else
+                       cck_ofdm_pwr_delta =
+                               (ee->ee_cck_ofdm_power_delta * 2) / 10;
+
+               if (channel->hw_value == CHANNEL_G)
+                       ath5k_hw_reg_write(ah,
+                       AR5K_REG_SM((ee->ee_cck_ofdm_power_delta * -1),
+                               AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
+                       AR5K_REG_SM((cck_ofdm_pwr_delta * -1),
+                               AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX),
+                               AR5K_PHY_TX_PWR_ADJ);
+               else
+                       ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ);
+       }
+
+       /* Set antenna idle switch table */
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
+                       AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
+                       (ah->ah_antenna[ee_mode][0] |
+                       AR5K_PHY_ANT_CTL_TXRX_EN));
+
+       /* Set antenna switch table */
+       ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
+               AR5K_PHY_ANT_SWITCH_TABLE_0);
+       ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
+               AR5K_PHY_ANT_SWITCH_TABLE_1);
+
+       /* Noise floor threshold */
+       ath5k_hw_reg_write(ah,
+               AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
+               AR5K_PHY_NFTHRES);
+
+       if ((channel->hw_value & CHANNEL_TURBO) &&
+       (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
+               /* Switch settling time (Turbo) */
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+                               AR5K_PHY_SETTLING_SWITCH,
+                               ee->ee_switch_settling_turbo[ee_mode]);
+
+               /* Tx/Rx attenuation (Turbo) */
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
+                               AR5K_PHY_GAIN_TXRX_ATTEN,
+                               ee->ee_atn_tx_rx_turbo[ee_mode]);
+
+               /* ADC/PGA desired size (Turbo) */
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+                               AR5K_PHY_DESIRED_SIZE_ADC,
+                               ee->ee_adc_desired_size_turbo[ee_mode]);
+
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+                               AR5K_PHY_DESIRED_SIZE_PGA,
+                               ee->ee_pga_desired_size_turbo[ee_mode]);
+
+               /* Tx/Rx margin (Turbo) */
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+                               AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+                               ee->ee_margin_tx_rx_turbo[ee_mode]);
+
+       } else {
+               /* Switch settling time */
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+                               AR5K_PHY_SETTLING_SWITCH,
+                               ee->ee_switch_settling[ee_mode]);
+
+               /* Tx/Rx attenuation */
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
+                               AR5K_PHY_GAIN_TXRX_ATTEN,
+                               ee->ee_atn_tx_rx[ee_mode]);
+
+               /* ADC/PGA desired size */
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+                               AR5K_PHY_DESIRED_SIZE_ADC,
+                               ee->ee_adc_desired_size[ee_mode]);
+
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+                               AR5K_PHY_DESIRED_SIZE_PGA,
+                               ee->ee_pga_desired_size[ee_mode]);
+
+               /* Tx/Rx margin */
+               if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+                               AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+                               ee->ee_margin_tx_rx[ee_mode]);
+       }
+
+       /* XPA delays */
+       ath5k_hw_reg_write(ah,
+               (ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
+               (ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
+               (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
+               (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
+
+       /* XLNA delay */
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3,
+                       AR5K_PHY_RF_CTL3_TXE2XLNA_ON,
+                       ee->ee_tx_end2xlna_enable[ee_mode]);
+
+       /* Thresh64 (ANI) */
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF,
+                       AR5K_PHY_NF_THRESH62,
+                       ee->ee_thr_62[ee_mode]);
+
+
+       /* False detect backoff for channels
+        * that have spur noise. Write the new
+        * cyclic power RSSI threshold. */
+       if (ath5k_hw_chan_has_spur_noise(ah, channel))
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+                               AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
+                               AR5K_INIT_CYCRSSI_THR1 +
+                               ee->ee_false_detect[ee_mode]);
+       else
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+                               AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
+                               AR5K_INIT_CYCRSSI_THR1);
+
+       /* I/Q correction
+        * TODO: Per channel i/q infos ? */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+               AR5K_PHY_IQ_CORR_ENABLE |
+               (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
+               ee->ee_q_cal[ee_mode]);
+
+       /* Heavy clipping -disable for now */
+       if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
+               ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
+
+       return;
+}
+
+/*
  * Main reset function
  */
 int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        struct ieee80211_channel *channel, bool change_channel)
 {
-       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-       struct pci_dev *pdev = ah->ah_sc->pdev;
-       u32 data, s_seq, s_ant, s_led[3], dma_size;
-       unsigned int i, mode, freq, ee_mode, ant[2];
-       int ret;
+       u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo;
+       u32 phy_tst1;
+       u8 mode, freq, ee_mode, ant[2];
+       int i, ret;
 
        ATH5K_TRACE(ah->ah_sc);
 
-       s_seq = 0;
        s_ant = 0;
        ee_mode = 0;
+       staid1_flags = 0;
+       tsf_up = 0;
+       tsf_lo = 0;
        freq = 0;
        mode = 0;
 
@@ -427,36 +830,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
         */
        /*DCU/Antenna selection not available on 5210*/
        if (ah->ah_version != AR5K_AR5210) {
-               if (change_channel) {
-                       /* Seq number for queue 0 -do this for all queues ? */
-                       s_seq = ath5k_hw_reg_read(ah,
-                                       AR5K_QUEUE_DFS_SEQNUM(0));
-                       /*Default antenna*/
-                       s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
-               }
-       }
-
-       /*GPIOs*/
-       s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE;
-       s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
-       s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
-
-
-       /*Wakeup the device*/
-       ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
-       if (ret)
-               return ret;
-
-       /*
-        * Initialize operating mode
-        */
-       ah->ah_op_mode = op_mode;
-
-       /*
-        * 5111/5112 Settings
-        * 5210 only comes with RF5110
-        */
-       if (ah->ah_version != AR5K_AR5210) {
 
                switch (channel->hw_value & CHANNEL_MODES) {
                case CHANNEL_A:
@@ -479,8 +852,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                        freq = AR5K_INI_RFGAIN_5GHZ;
                        ee_mode = AR5K_EEPROM_MODE_11A;
                        break;
-               /*Is this ok on 5211 too ?*/
                case CHANNEL_TG:
+                       if (ah->ah_version == AR5K_AR5211) {
+                               ATH5K_ERR(ah->ah_sc,
+                                       "TurboG mode not available on 5211");
+                               return -EINVAL;
+                       }
                        mode = AR5K_MODE_11G_TURBO;
                        freq = AR5K_INI_RFGAIN_2GHZ;
                        ee_mode = AR5K_EEPROM_MODE_11G;
@@ -501,11 +878,93 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                        return -EINVAL;
                }
 
+               if (change_channel) {
+                       /*
+                        * Save frame sequence count
+                        * For revs. after Oahu, only save
+                        * seq num for DCU 0 (Global seq num)
+                        */
+                       if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+
+                               for (i = 0; i < 10; i++)
+                                       s_seq[i] = ath5k_hw_reg_read(ah,
+                                               AR5K_QUEUE_DCU_SEQNUM(i));
+
+                       } else {
+                               s_seq[0] = ath5k_hw_reg_read(ah,
+                                               AR5K_QUEUE_DCU_SEQNUM(0));
+                       }
+
+                       /* TSF accelerates on AR5211 durring reset
+                        * As a workaround save it here and restore
+                        * it later so that it's back in time after
+                        * reset. This way it'll get re-synced on the
+                        * next beacon without breaking ad-hoc.
+                        *
+                        * On AR5212 TSF is almost preserved across a
+                        * reset so it stays back in time anyway and
+                        * we don't have to save/restore it.
+                        *
+                        * XXX: Since this breaks power saving we have
+                        * to disable power saving until we receive the
+                        * next beacon, so we can resync beacon timers */
+                       if (ah->ah_version == AR5K_AR5211) {
+                               tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+                               tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
+                       }
+               }
+
+               /* Save default antenna */
+               s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+
+               if (ah->ah_version == AR5K_AR5212) {
+                       /* Restore normal 32/40MHz clock operation
+                        * to avoid register access delay on certain
+                        * PHY registers */
+                       ath5k_hw_set_sleep_clock(ah, false);
+
+                       /* Since we are going to write rf buffer
+                        * check if we have any pending gain_F
+                        * optimization settings */
+                       if (change_channel && ah->ah_rf_banks != NULL)
+                               ath5k_hw_gainf_calibrate(ah);
+               }
        }
 
+       /*GPIOs*/
+       s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) &
+                                       AR5K_PCICFG_LEDSTATE;
+       s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
+       s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+       /* AR5K_STA_ID1 flags, only preserve antenna
+        * settings and ack/cts rate mode */
+       staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) &
+                       (AR5K_STA_ID1_DEFAULT_ANTENNA |
+                       AR5K_STA_ID1_DESC_ANTENNA |
+                       AR5K_STA_ID1_RTS_DEF_ANTENNA |
+                       AR5K_STA_ID1_ACKCTS_6MB |
+                       AR5K_STA_ID1_BASE_RATE_11B |
+                       AR5K_STA_ID1_SELFGEN_DEF_ANT);
+
+       /* Wakeup the device */
+       ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
+       if (ret)
+               return ret;
+
+       /*
+        * Initialize operating mode
+        */
+       ah->ah_op_mode = op_mode;
+
        /* PHY access enable */
-       ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+       if (ah->ah_mac_srev >= AR5K_SREV_AR5211)
+               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+       else
+               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40,
+                                                       AR5K_PHY(0));
 
+       /* Write initial settings */
        ret = ath5k_hw_write_initvals(ah, mode, change_channel);
        if (ret)
                return ret;
@@ -514,6 +973,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
         * 5211/5212 Specific
         */
        if (ah->ah_version != AR5K_AR5210) {
+
                /*
                 * Write initial RF gain settings
                 * This should work for both 5111/5112
@@ -525,53 +985,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                mdelay(1);
 
                /*
-                * Write some more initial register settings for revised chips
+                * Tweak initval settings for revised
+                * chipsets and add some more config
+                * bits
                 */
-               if (ah->ah_version == AR5K_AR5212 &&
-                   ah->ah_phy_revision > 0x41) {
-                       ath5k_hw_reg_write(ah, 0x0002a002, 0x982c);
-
-                       if (channel->hw_value == CHANNEL_G)
-                               if (ah->ah_mac_srev < AR5K_SREV_AR2413)
-                                       ath5k_hw_reg_write(ah, 0x00f80d80,
-                                                               0x994c);
-                               else if (ah->ah_mac_srev < AR5K_SREV_AR5424)
-                                       ath5k_hw_reg_write(ah, 0x00380140,
-                                                               0x994c);
-                               else if (ah->ah_mac_srev < AR5K_SREV_AR2425)
-                                       ath5k_hw_reg_write(ah, 0x00fc0ec0,
-                                                               0x994c);
-                               else /* 2425 */
-                                       ath5k_hw_reg_write(ah, 0x00fc0fc0,
-                                                               0x994c);
-                       else
-                               ath5k_hw_reg_write(ah, 0x00000000, 0x994c);
-
-                       /* Got this from legacy-hal */
-                       AR5K_REG_DISABLE_BITS(ah, 0xa228, 0x200);
-
-                       AR5K_REG_MASKED_BITS(ah, 0xa228, 0x800, 0xfffe03ff);
-
-                       /* Just write 0x9b5 ? */
-                       /* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */
-                       ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
-                       ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
-                       ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
-               }
-
-               /* Fix for first revision of the RF5112 RF chipset */
-               if (ah->ah_radio >= AR5K_RF5112 &&
-                               ah->ah_radio_5ghz_revision <
-                               AR5K_SREV_RAD_5112A) {
-                       ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
-                                       AR5K_PHY_CCKTXCTL);
-                       if (channel->hw_value & CHANNEL_5GHZ)
-                               data = 0xffb81020;
-                       else
-                               data = 0xffb80d20;
-                       ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
-                       data = 0;
-               }
+               ath5k_hw_tweak_initval_settings(ah, channel);
 
                /*
                 * Set TX power (FIXME)
@@ -589,15 +1007,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                        ath5k_hw_write_rate_duration(ah, mode);
 
                /*
-                * Write RF registers
+                * Write RF buffer
                 */
                ret = ath5k_hw_rfregs_init(ah, channel, mode);
                if (ret)
                        return ret;
 
-               /*
-                * Configure additional registers
-                */
 
                /* Write OFDM timings on 5212*/
                if (ah->ah_version == AR5K_AR5212 &&
@@ -619,17 +1034,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                }
 
                /*
-                * Set channel and calibrate the PHY
-                */
-               ret = ath5k_hw_channel(ah, channel);
-               if (ret)
-                       return ret;
-
-               /* Set antenna mode */
-               AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL,
-                       ah->ah_antenna[ee_mode][0], 0xfffffc06);
-
-               /*
                 * In case a fixed antenna was set as default
                 * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
                 * registers.
@@ -644,54 +1048,16 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                        ant[1] = AR5K_ANT_FIXED_B;
                }
 
-               ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
-                       AR5K_PHY_ANT_SWITCH_TABLE_0);
-               ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
-                       AR5K_PHY_ANT_SWITCH_TABLE_1);
-
                /* Commit values from EEPROM */
-               if (ah->ah_radio == AR5K_RF5111)
-                       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
-                           AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip);
-
-               ath5k_hw_reg_write(ah,
-                       AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
-                       AR5K_PHY_NFTHRES);
-
-               AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING,
-                       (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
-                       0xffffc07f);
-               AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
-                       (ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000,
-                       0xfffc0fff);
-               AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
-                       (ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
-                       ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
-                       0xffff0000);
-
-               ath5k_hw_reg_write(ah,
-                       (ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
-                       (ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
-                       (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
-                       (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
-
-               AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3,
-                       ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
-               AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF,
-                       (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
-               AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01);
-
-               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
-                   AR5K_PHY_IQ_CORR_ENABLE |
-                   (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
-                   ee->ee_q_cal[ee_mode]);
-
-               if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-                       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
-                               AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
-                               ee->ee_margin_tx_rx[ee_mode]);
+               ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode);
 
        } else {
+               /*
+                * For 5210 we do all initialization using
+                * initvals, so we don't have to modify
+                * any settings (5210 also only supports
+                * a/aturbo modes)
+                */
                mdelay(1);
                /* Disable phy and wait */
                ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
@@ -701,100 +1067,154 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        /*
         * Restore saved values
         */
+
        /*DCU/Antenna selection not available on 5210*/
        if (ah->ah_version != AR5K_AR5210) {
-               ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0));
+
+               if (change_channel) {
+                       if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+                               for (i = 0; i < 10; i++)
+                                       ath5k_hw_reg_write(ah, s_seq[i],
+                                               AR5K_QUEUE_DCU_SEQNUM(i));
+                       } else {
+                               ath5k_hw_reg_write(ah, s_seq[0],
+                                       AR5K_QUEUE_DCU_SEQNUM(0));
+                       }
+
+
+                       if (ah->ah_version == AR5K_AR5211) {
+                               ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32);
+                               ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
+                       }
+               }
+
                ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
        }
+
+       /* Ledstate */
        AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
+
+       /* Gpio settings */
        ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
        ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
 
+       /* Restore sta_id flags and preserve our mac address*/
+       ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id),
+                                               AR5K_STA_ID0);
+       ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id),
+                                               AR5K_STA_ID1);
+
+
        /*
-        * Misc
+        * Configure PCU
         */
+
+       /* Restore bssid and bssid mask */
        /* XXX: add ah->aid once mac80211 gives this to us */
        ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
 
+       /* Set PCU config */
        ath5k_hw_set_opmode(ah);
-       /*PISR/SISR Not available on 5210*/
-       if (ah->ah_version != AR5K_AR5210) {
+
+       /* Clear any pending interrupts
+        * PISR/SISR Not available on 5210 */
+       if (ah->ah_version != AR5K_AR5210)
                ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
-               /* If we later allow tuning for this, store into sc structure */
-               data = AR5K_TUNE_RSSI_THRES |
-                       AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S;
-               ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR);
+
+       /* Set RSSI/BRSSI thresholds
+        *
+        * Note: If we decide to set this value
+        * dynamicaly, have in mind that when AR5K_RSSI_THR
+        * register is read it might return 0x40 if we haven't
+        * wrote anything to it plus BMISS RSSI threshold is zeroed.
+        * So doing a save/restore procedure here isn't the right
+        * choice. Instead store it on ath5k_hw */
+       ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
+                               AR5K_TUNE_BMISS_THRES <<
+                               AR5K_RSSI_THR_BMISS_S),
+                               AR5K_RSSI_THR);
+
+       /* MIC QoS support */
+       if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
+               ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
+               ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
+       }
+
+       /* QoS NOACK Policy */
+       if (ah->ah_version == AR5K_AR5212) {
+               ath5k_hw_reg_write(ah,
+                       AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
+                       AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
+                       AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
+                       AR5K_QOS_NOACK);
        }
 
+
        /*
-        * Set Rx/Tx DMA Configuration
-        *
-        * Set maximum DMA size (512) except for PCI-E cards since
-        * it causes rx overruns and tx errors (tested on 5424 but since
-        * rx overruns also occur on 5416/5418 with madwifi we set 128
-        * for all PCI-E cards to be safe).
-        *
-        * In dumps this is 128 for allchips.
-        *
-        * XXX: need to check 5210 for this
-        * TODO: Check out tx triger level, it's always 64 on dumps but I
-        * guess we can tweak it and see how it goes ;-)
+        * Configure PHY
         */
-       dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B;
-       if (ah->ah_version != AR5K_AR5210) {
-               AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
-                       AR5K_TXCFG_SDMAMR, dma_size);
-               AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
-                       AR5K_RXCFG_SDMAMW, dma_size);
-       }
+
+       /* Set channel on PHY */
+       ret = ath5k_hw_channel(ah, channel);
+       if (ret)
+               return ret;
 
        /*
         * Enable the PHY and wait until completion
+        * This includes BaseBand and Synthesizer
+        * activation.
         */
        ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
 
        /*
         * On 5211+ read activation -> rx delay
         * and use it.
+        *
+        * TODO: Half/quarter rate support
         */
        if (ah->ah_version != AR5K_AR5210) {
-               data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+               u32 delay;
+               delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
                        AR5K_PHY_RX_DELAY_M;
-               data = (channel->hw_value & CHANNEL_CCK) ?
-                       ((data << 2) / 22) : (data / 10);
+               delay = (channel->hw_value & CHANNEL_CCK) ?
+                       ((delay << 2) / 22) : (delay / 10);
 
-               udelay(100 + (2 * data));
-               data = 0;
+               udelay(100 + (2 * delay));
        } else {
                mdelay(1);
        }
 
        /*
-        * Perform ADC test (?)
+        * Perform ADC test to see if baseband is ready
+        * Set tx hold and check adc test register
         */
-       data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+       phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
        ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
        for (i = 0; i <= 20; i++) {
                if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
                        break;
                udelay(200);
        }
-       ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1);
-       data = 0;
+       ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
 
        /*
-        * Start automatic gain calibration
+        * Start automatic gain control calibration
         *
         * During AGC calibration RX path is re-routed to
-        * a signal detector so we don't receive anything.
+        * a power detector so we don't receive anything.
         *
         * This method is used to calibrate some static offsets
         * used together with on-the fly I/Q calibration (the
         * one performed via ath5k_hw_phy_calibrate), that doesn't
         * interrupt rx path.
         *
+        * While rx path is re-routed to the power detector we also
+        * start a noise floor calibration, to measure the
+        * card's noise floor (the noise we measure when we are not
+        * transmiting or receiving anything).
+        *
         * If we are in a noisy environment AGC calibration may time
-        * out.
+        * out and/or noise floor calibration might timeout.
         */
        AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
                                AR5K_PHY_AGCCTL_CAL);
@@ -816,30 +1236,37 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                        AR5K_PHY_AGCCTL_CAL, 0, false)) {
                ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
                        channel->center_freq);
-               return -EAGAIN;
        }
 
        /*
-        * Start noise floor calibration
-        *
         * If we run NF calibration before AGC, it always times out.
         * Binary HAL starts NF and AGC calibration at the same time
-        * and only waits for AGC to finish. I believe that's wrong because
-        * during NF calibration, rx path is also routed to a detector, so if
-        * it doesn't finish we won't have RX.
-        *
-        * XXX: Find an interval that's OK for all cards...
+        * and only waits for AGC to finish. Also if AGC or NF cal.
+        * times out, reset doesn't fail on binary HAL. I believe
+        * that's wrong because since rx path is routed to a detector,
+        * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
+        * enables noise floor calibration after offset calibration and if noise
+        * floor calibration fails, reset fails. I believe that's
+        * a better approach, we just need to find a polling interval
+        * that suits best, even if reset continues we need to make
+        * sure that rx path is ready.
         */
        ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 
+
+       /*
+        * Configure QCUs/DCUs
+        */
+
+       /* TODO: HW Compression support for data queues */
+       /* TODO: Burst prefetch for data queues */
+
        /*
         * Reset queues and start beacon timers at the end of the reset routine
+        * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
+        * Note: If we want we can assign multiple qcus on one dcu.
         */
        for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
-               /*No QCU on 5210*/
-               if (ah->ah_version != AR5K_AR5210)
-                       AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i);
-
                ret = ath5k_hw_reset_tx_queue(ah, i);
                if (ret) {
                        ATH5K_ERR(ah->ah_sc,
@@ -848,14 +1275,40 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                }
        }
 
+
+       /*
+        * Configure DMA/Interrupts
+        */
+
+       /*
+        * Set Rx/Tx DMA Configuration
+        *
+        * Set standard DMA size (128). Note that
+        * a DMA size of 512 causes rx overruns and tx errors
+        * on pci-e cards (tested on 5424 but since rx overruns
+        * also occur on 5416/5418 with madwifi we set 128
+        * for all PCI-E cards to be safe).
+        *
+        * XXX: need to check 5210 for this
+        * TODO: Check out tx triger level, it's always 64 on dumps but I
+        * guess we can tweak it and see how it goes ;-)
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+                       AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+               AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+                       AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
+       }
+
        /* Pre-enable interrupts on 5211/5212*/
        if (ah->ah_version != AR5K_AR5210)
                ath5k_hw_set_imr(ah, ah->ah_imr);
 
        /*
-        * Set RF kill flags if supported by the device (read from the EEPROM)
-        * Disable gpio_intr for now since it results system hang.
-        * TODO: Handle this in ath5k_intr
+        * Setup RFKill interrupt if rfkill flag is set on eeprom.
+        * TODO: Use gpio pin and polarity infos from eeprom
+        * TODO: Handle this in ath5k_intr because it'll result
+        *       a nasty interrupt storm.
         */
 #if 0
        if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
@@ -868,33 +1321,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        }
 #endif
 
-       /*
-        * Set the 32MHz reference clock on 5212 phy clock sleep register
-        *
-        * TODO: Find out how to switch to external 32Khz clock to save power
-        */
-       if (ah->ah_version == AR5K_AR5212) {
-               ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
-               ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
-               ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL);
-               ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
-               ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
-               ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
-
-               data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ;
-               data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ?
-                                               0x00000f80 : 0x00001380 ;
-               ath5k_hw_reg_write(ah, data, AR5K_USEC_5211);
-               data = 0;
-       }
-
-       if (ah->ah_version == AR5K_AR5212) {
-               ath5k_hw_reg_write(ah, 0x000100aa, 0x8118);
-               ath5k_hw_reg_write(ah, 0x00003210, 0x811c);
-               ath5k_hw_reg_write(ah, 0x00000052, 0x8108);
-               if (ah->ah_mac_srev >= AR5K_SREV_AR2413)
-                       ath5k_hw_reg_write(ah, 0x00000004, 0x8120);
-       }
+       /* Enable 32KHz clock function for AR5212+ chips
+        * Set clocks to 32KHz operation and use an
+        * external 32KHz crystal when sleeping if one
+        * exists */
+       if (ah->ah_version == AR5K_AR5212)
+                       ath5k_hw_set_sleep_clock(ah, true);
 
        /*
         * Disable beacons and reset the register