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)
                !(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;
 
        { 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)
 }
 
 /*
- * 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)
 {
                        }
                } 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;
        }
 
        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);
        }
        return 0;
 }
 
+/*
+ * 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;
 
         * Save some registers before a reset
         */
        /*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) {
                        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;
                        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;
         * 5211/5212 Specific
         */
        if (ah->ah_version != AR5K_AR5210) {
+
                /*
                 * Write initial RF gain settings
                 * This should work for both 5111/5112
                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)
                        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 &&
                                    AR5K_TXCFG_B_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
                        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);
        /*
         * 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);
                        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,
                }
        }
 
+
+       /*
+        * 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)) {
        }
 #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