ath9k: propagate hw initialization errors
[safe/jmp/linux-2.6] / drivers / net / wireless / ath / ath9k / hw.c
index 9cb85b0..2e09204 100644 (file)
@@ -84,6 +84,38 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
                return ath9k_hw_mac_clks(ah, usecs);
 }
 
+/*
+ * Read and write, they both share the same lock. We do this to serialize
+ * reads and writes on Atheros 802.11n PCI devices only. This is required
+ * as the FIFO on these devices can only accept sanely 2 requests. After
+ * that the device goes bananas. Serializing the reads/writes prevents this
+ * from happening.
+ */
+
+void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val)
+{
+       if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+               unsigned long flags;
+               spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
+               iowrite32(val, ah->ah_sc->mem + reg_offset);
+               spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
+       } else
+               iowrite32(val, ah->ah_sc->mem + reg_offset);
+}
+
+unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset)
+{
+       u32 val;
+       if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+               unsigned long flags;
+               spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
+               val = ioread32(ah->ah_sc->mem + reg_offset);
+               spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
+       } else
+               val = ioread32(ah->ah_sc->mem + reg_offset);
+       return val;
+}
+
 bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
 {
        int i;
@@ -136,7 +168,7 @@ bool ath9k_get_channel_edges(struct ath_hw *ah,
 }
 
 u16 ath9k_hw_computetxtime(struct ath_hw *ah,
-                          struct ath_rate_table *rates,
+                          const struct ath_rate_table *rates,
                           u32 frameLen, u16 rateix,
                           bool shortPreamble)
 {
@@ -348,6 +380,9 @@ static const char *ath9k_hw_devname(u16 devid)
                return "Atheros 9280";
        case AR9285_DEVID_PCIE:
                return "Atheros 9285";
+       case AR5416_DEVID_AR9287_PCI:
+       case AR5416_DEVID_AR9287_PCIE:
+               return "Atheros 9287";
        }
 
        return NULL;
@@ -443,6 +478,8 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
 
        ah->gbeacon_rate = 0;
 
+       ah->power_mode = ATH9K_PM_UNDEFINED;
+
        return ah;
 }
 
@@ -625,10 +662,16 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
                ah->config.serialize_regmode);
 
-       if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) &&
-           (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
-           (ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
-           (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
+       switch (ah->hw_version.macVersion) {
+       case AR_SREV_VERSION_5416_PCI:
+       case AR_SREV_VERSION_5416_PCIE:
+       case AR_SREV_VERSION_9160:
+       case AR_SREV_VERSION_9100:
+       case AR_SREV_VERSION_9280:
+       case AR_SREV_VERSION_9285:
+       case AR_SREV_VERSION_9287:
+               break;
+       default:
                DPRINTF(sc, ATH_DBG_FATAL,
                        "Mac Chip Rev 0x%02x.%x is not supported by "
                        "this driver\n", ah->hw_version.macVersion,
@@ -668,8 +711,37 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        ah->ani_function = ATH9K_ANI_ALL;
        if (AR_SREV_9280_10_OR_LATER(ah))
                ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+       if (AR_SREV_9287_11_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
+                               ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
+                               ARRAY_SIZE(ar9287Common_9287_1_1), 2);
+               if (ah->config.pcie_clock_req)
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_off_L1_9287_1_1,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
+               else
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
+                                       2);
+       } else if (AR_SREV_9287_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
+                               ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
+                               ARRAY_SIZE(ar9287Common_9287_1_0), 2);
+
+               if (ah->config.pcie_clock_req)
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_off_L1_9287_1_0,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
+               else
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
+                                 2);
+       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
 
-       if (AR_SREV_9285_12_OR_LATER(ah)) {
 
                INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
                               ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
@@ -810,7 +882,28 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        if (ecode != 0)
                goto bad;
 
-       if (AR_SREV_9285_12_OR_LATER(ah)) {
+       if (AR_SREV_9287_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+               ar9287Modes_rx_gain_9287_1_1,
+               ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
+       else if (AR_SREV_9287_10(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+               ar9287Modes_rx_gain_9287_1_0,
+               ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
+       else if (AR_SREV_9280_20(ah))
+               ath9k_hw_init_rxgain_ini(ah);
+
+       if (AR_SREV_9287_11(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+               ar9287Modes_tx_gain_9287_1_1,
+               ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
+       } else if (AR_SREV_9287_10(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+               ar9287Modes_tx_gain_9287_1_0,
+               ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
+       } else if (AR_SREV_9280_20(ah)) {
+               ath9k_hw_init_txgain_ini(ah);
+       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
                u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
 
                /* txgain table */
@@ -826,14 +919,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 
        }
 
-       /* rxgain table */
-       if (AR_SREV_9280_20(ah))
-               ath9k_hw_init_rxgain_ini(ah);
-
-       /* txgain table */
-       if (AR_SREV_9280_20(ah))
-               ath9k_hw_init_txgain_ini(ah);
-
        ath9k_hw_fill_cap_info(ah);
 
        if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
@@ -1133,10 +1218,12 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
        case AR9280_DEVID_PCI:
        case AR9280_DEVID_PCIE:
        case AR9285_DEVID_PCIE:
+       case AR5416_DEVID_AR9287_PCI:
+       case AR5416_DEVID_AR9287_PCIE:
                ah = ath9k_hw_do_attach(devid, sc, error);
                break;
        default:
-               *error = -ENXIO;
+               *error = -EOPNOTSUPP;
                break;
        }
 
@@ -1242,7 +1329,6 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
        int i, regWrites = 0;
        struct ieee80211_channel *channel = chan->chan;
        u32 modesIndex, freqIndex;
-       int status;
 
        switch (chan->chanmode) {
        case CHANNEL_A:
@@ -1310,11 +1396,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
                DO_DELAY(regWrites);
        }
 
-       if (AR_SREV_9280(ah))
+       if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
                REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
 
-       if (AR_SREV_9280(ah) || (AR_SREV_9285(ah) &&
-           AR_SREV_9285_12_OR_LATER(ah)))
+       if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
+           AR_SREV_9287_10_OR_LATER(ah))
                REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
 
        for (i = 0; i < ah->iniCommon.ia_rows; i++) {
@@ -1345,17 +1431,12 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
        if (OLC_FOR_AR9280_20_LATER)
                ath9k_olc_init(ah);
 
-       status = ah->eep_ops->set_txpower(ah, chan,
-                                 ath9k_regd_get_ctl(&ah->regulatory, chan),
-                                 channel->max_antenna_gain * 2,
-                                 channel->max_power * 2,
-                                 min((u32) MAX_RATE_POWER,
-                                     (u32) ah->regulatory.power_limit));
-       if (status != 0) {
-               DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-                       "Error initializing transmit power\n");
-               return -EIO;
-       }
+       ah->eep_ops->set_txpower(ah, chan,
+                                ath9k_regd_get_ctl(&ah->regulatory, chan),
+                                channel->max_antenna_gain * 2,
+                                channel->max_power * 2,
+                                min((u32) MAX_RATE_POWER,
+                                (u32) ah->regulatory.power_limit));
 
        if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
                DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
@@ -1586,11 +1667,9 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
        switch (type) {
        case ATH9K_RESET_POWER_ON:
                return ath9k_hw_set_reset_power_on(ah);
-               break;
        case ATH9K_RESET_WARM:
        case ATH9K_RESET_COLD:
                return ath9k_hw_set_reset(ah, type);
-               break;
        default:
                return false;
        }
@@ -1672,11 +1751,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
        ath9k_hw_set_regs(ah, chan, macmode);
 
        if (AR_SREV_9280_10_OR_LATER(ah)) {
-               if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-                               "Failed to set channel\n");
-                       return false;
-               }
+               ath9k_hw_ar9280_set_channel(ah, chan);
        } else {
                if (!(ath9k_hw_set_channel(ah, chan))) {
                        DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
@@ -1685,16 +1760,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
                }
        }
 
-       if (ah->eep_ops->set_txpower(ah, chan,
+       ah->eep_ops->set_txpower(ah, chan,
                             ath9k_regd_get_ctl(&ah->regulatory, chan),
                             channel->max_antenna_gain * 2,
                             channel->max_power * 2,
                             min((u32) MAX_RATE_POWER,
-                                (u32) ah->regulatory.power_limit)) != 0) {
-               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                       "Error initializing transmit power\n");
-               return false;
-       }
+                            (u32) ah->regulatory.power_limit));
 
        synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
        if (IS_CHAN_B(chan))
@@ -2171,6 +2242,18 @@ static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan
        REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
+static void ath9k_enable_rfkill(struct ath_hw *ah)
+{
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+                   AR_GPIO_INPUT_MUX2_RFSILENT);
+
+       ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
+       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                    bool bChannelChange)
 {
@@ -2227,6 +2310,16 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (AR_SREV_9280_10_OR_LATER(ah))
                REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
 
+       if (AR_SREV_9287_10_OR_LATER(ah)) {
+               /* Enable ASYNC FIFO */
+               REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+               REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+               REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+               REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+       }
        r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width);
        if (r)
                return r;
@@ -2282,13 +2375,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
 
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
-               if (!(ath9k_hw_ar9280_set_channel(ah, chan)))
-                       return -EIO;
-       } else {
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               ath9k_hw_ar9280_set_channel(ah, chan);
+       else
                if (!(ath9k_hw_set_channel(ah, chan)))
                        return -EIO;
-       }
 
        for (i = 0; i < AR_NUM_DCU; i++)
                REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
@@ -2300,12 +2391,32 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_init_interrupt_masks(ah, ah->opmode);
        ath9k_hw_init_qos(ah);
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
        if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                ath9k_enable_rfkill(ah);
-#endif
+
        ath9k_hw_init_user_settings(ah);
 
+       if (AR_SREV_9287_10_OR_LATER(ah)) {
+               REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
+                         AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
+                         AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
+                         AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
+
+               REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
+
+               REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
+                           AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
+               REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
+                             AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
+       }
+       if (AR_SREV_9287_10_OR_LATER(ah)) {
+               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+                               AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+       }
+
        REG_WRITE(ah, AR_STA_ID1,
                  REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
 
@@ -2321,7 +2432,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_init_bb(ah, chan);
 
        if (!ath9k_hw_init_cal(ah, chan))
-               return -EIO;;
+               return -EIO;
 
        rx_chainmask = ah->rxchainmask;
        if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -2459,14 +2570,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                }
                break;
        case ATH9K_CIPHER_WEP:
-               if (k->kv_len < LEN_WEP40) {
+               if (k->kv_len < WLAN_KEY_LEN_WEP40) {
                        DPRINTF(ah->ah_sc, ATH_DBG_ANY,
                                "WEP key length %u too small\n", k->kv_len);
                        return false;
                }
-               if (k->kv_len <= LEN_WEP40)
+               if (k->kv_len <= WLAN_KEY_LEN_WEP40)
                        keyType = AR_KEYTABLE_TYPE_40;
-               else if (k->kv_len <= LEN_WEP104)
+               else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
                        keyType = AR_KEYTABLE_TYPE_104;
                else
                        keyType = AR_KEYTABLE_TYPE_128;
@@ -2485,7 +2596,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
        key2 = get_unaligned_le32(k->kv_val + 6);
        key3 = get_unaligned_le16(k->kv_val + 10);
        key4 = get_unaligned_le32(k->kv_val + 12);
-       if (k->kv_len <= LEN_WEP104)
+       if (k->kv_len <= WLAN_KEY_LEN_WEP104)
                key4 &= 0xff;
 
        /*
@@ -2704,7 +2815,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
        return true;
 }
 
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
+                                    enum ath9k_power_mode mode)
 {
        int status = true, setChip = true;
        static const char *modes[] = {
@@ -2714,6 +2826,9 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
                "UNDEFINED"
        };
 
+       if (ah->power_mode == mode)
+               return status;
+
        DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
                modes[ah->power_mode], modes[mode]);
 
@@ -2738,6 +2853,51 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
        return status;
 }
 
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
+       ret = ath9k_hw_setpower_nolock(ah, mode);
+       spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
+
+       return ret;
+}
+
+void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (++sc->ps_usecount != 1)
+               goto unlock;
+
+       ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
+
+ unlock:
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
+void ath9k_ps_restore(struct ath_softc *sc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (--sc->ps_usecount != 0)
+               goto unlock;
+
+       if (sc->ps_enabled &&
+           !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+                             SC_OP_WAIT_FOR_CAB |
+                             SC_OP_WAIT_FOR_PSPOLL_DATA |
+                             SC_OP_WAIT_FOR_TX_ACK)))
+               ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+
+ unlock:
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
 /*
  * Helper for ASPM support.
  *
@@ -2997,11 +3157,6 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
        return true;
 }
 
-enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah)
-{
-       return ah->mask_reg;
-}
-
 enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
 {
        u32 omask = ah->mask_reg;
@@ -3281,7 +3436,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
        }
 
        if (eeval & AR5416_OPFLAGS_11G) {
-               set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
                set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
                if (ah->config.ht_enable) {
                        if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
@@ -3377,7 +3531,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
            (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) ||
            (ah->hw_version.macVersion == AR_SREV_VERSION_9160) ||
            (ah->hw_version.macVersion == AR_SREV_VERSION_9100) ||
-           (ah->hw_version.macVersion == AR_SREV_VERSION_9280))
+           (ah->hw_version.macVersion == AR_SREV_VERSION_9280) ||
+           (ah->hw_version.macVersion == AR_SREV_VERSION_9285))
                pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
        else
                pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
@@ -3570,7 +3725,9 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
        if (gpio >= ah->caps.num_gpio_pins)
                return 0xffffffff;
 
-       if (AR_SREV_9285_10_OR_LATER(ah))
+       if (AR_SREV_9287_10_OR_LATER(ah))
+               return MS_REG_READ(AR9287, gpio) != 0;
+       else if (AR_SREV_9285_10_OR_LATER(ah))
                return MS_REG_READ(AR9285, gpio) != 0;
        else if (AR_SREV_9280_10_OR_LATER(ah))
                return MS_REG_READ(AR928X, gpio) != 0;
@@ -3599,20 +3756,6 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
                AR_GPIO_BIT(gpio));
 }
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-void ath9k_enable_rfkill(struct ath_hw *ah)
-{
-       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
-       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
-                   AR_GPIO_INPUT_MUX2_RFSILENT);
-
-       ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
-       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-}
-#endif
-
 u32 ath9k_hw_getdefantenna(struct ath_hw *ah)
 {
        return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
@@ -3718,22 +3861,19 @@ bool ath9k_hw_disable(struct ath_hw *ah)
        return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
 }
 
-bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
+void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
 {
        struct ath9k_channel *chan = ah->curchan;
        struct ieee80211_channel *channel = chan->chan;
 
        ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER);
 
-       if (ah->eep_ops->set_txpower(ah, chan,
-                            ath9k_regd_get_ctl(&ah->regulatory, chan),
-                            channel->max_antenna_gain * 2,
-                            channel->max_power * 2,
-                            min((u32) MAX_RATE_POWER,
-                                (u32) ah->regulatory.power_limit)) != 0)
-               return false;
-
-       return true;
+       ah->eep_ops->set_txpower(ah, chan,
+                                ath9k_regd_get_ctl(&ah->regulatory, chan),
+                                channel->max_antenna_gain * 2,
+                                channel->max_power * 2,
+                                min((u32) MAX_RATE_POWER,
+                                (u32) ah->regulatory.power_limit));
 }
 
 void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
@@ -3783,19 +3923,14 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
 
 void ath9k_hw_reset_tsf(struct ath_hw *ah)
 {
-       int count;
+       ath9k_ps_wakeup(ah->ah_sc);
+       if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
+                          AH_TSF_WRITE_TIMEOUT))
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+                       "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
 
-       count = 0;
-       while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
-               count++;
-               if (count > 10) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                               "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
-                       break;
-               }
-               udelay(10);
-       }
        REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+       ath9k_ps_restore(ah->ah_sc);
 }
 
 bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)