]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/ath/ath9k/hw.c
ath9k_hw: Fix ASPM L1 issue for AR9480
[karo-tx-linux.git] / drivers / net / wireless / ath / ath9k / hw.c
index f2de7ee047ce5566853e23396c441b59d3f75ffc..58794a4e40ad1a280b49eea7eaab98e751ec4231 100644 (file)
@@ -284,7 +284,12 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
                ah->hw_version.macVersion =
                        (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
                ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
-               ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
+
+               if (AR_SREV_9480(ah))
+                       ah->is_pciexpress = true;
+               else
+                       ah->is_pciexpress = (val &
+                                            AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
        } else {
                if (!AR_SREV_9100(ah))
                        ah->hw_version.macVersion = MS(val, AR_SREV_VERSION);
@@ -428,7 +433,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
 
        regulatory->country_code = CTRY_DEFAULT;
        regulatory->power_limit = MAX_RATE_POWER;
-       regulatory->tp_scale = ATH9K_TP_SCALE_MAX;
 
        ah->hw_version.magic = AR5416_MAGIC;
        ah->hw_version.subvendorid = 0;
@@ -537,6 +541,9 @@ static int __ath9k_hw_init(struct ath_hw *ah)
                return -EIO;
        }
 
+       if (AR_SREV_9480(ah))
+               ah->WARegVal &= ~AR_WA_D3_L1_DISABLE;
+
        ath9k_hw_init_defaults(ah);
        ath9k_hw_init_config(ah);
 
@@ -1384,9 +1391,7 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,
 static bool ath9k_hw_channel_change(struct ath_hw *ah,
                                    struct ath9k_channel *chan)
 {
-       struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ieee80211_channel *channel = chan->chan;
        u32 qnum;
        int r;
 
@@ -1411,14 +1416,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
                return false;
        }
        ath9k_hw_set_clockrate(ah);
-
-       ah->eep_ops->set_txpower(ah, chan,
-                            ath9k_regd_get_ctl(regulatory, chan),
-                            channel->max_antenna_gain * 2,
-                            channel->max_power * 2,
-                            min((u32) MAX_RATE_POWER,
-                            (u32) regulatory->power_limit), false);
-
+       ath9k_hw_apply_txpower(ah, chan);
        ath9k_hw_rfbus_done(ah);
 
        if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
@@ -1781,8 +1779,7 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
        }
 
        /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
-       if (!AR_SREV_9480(ah))
-               REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
+       REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
 }
 
 /*
@@ -2077,11 +2074,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
        regulatory->current_rd = eeval;
 
-       eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1);
-       if (AR_SREV_9285_12_OR_LATER(ah))
-               eeval |= AR9285_RDEXT_DEFAULT;
-       regulatory->current_rd_ext = eeval;
-
        if (ah->opmode != NL80211_IFTYPE_AP &&
            ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
                if (regulatory->current_rd == 0x64 ||
@@ -2153,6 +2145,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->num_gpio_pins = AR9271_NUM_GPIO;
        else if (AR_DEVID_7010(ah))
                pCap->num_gpio_pins = AR7010_NUM_GPIO;
+       else if (AR_SREV_9300_20_OR_LATER(ah))
+               pCap->num_gpio_pins = AR9300_NUM_GPIO;
+       else if (AR_SREV_9287_11_OR_LATER(ah))
+               pCap->num_gpio_pins = AR9287_NUM_GPIO;
        else if (AR_SREV_9285_12_OR_LATER(ah))
                pCap->num_gpio_pins = AR9285_NUM_GPIO;
        else if (AR_SREV_9280_20_OR_LATER(ah))
@@ -2489,23 +2485,56 @@ bool ath9k_hw_disable(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_disable);
 
+static int get_antenna_gain(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       enum eeprom_param gain_param;
+
+       if (IS_CHAN_2GHZ(chan))
+               gain_param = EEP_ANTENNA_GAIN_2G;
+       else
+               gain_param = EEP_ANTENNA_GAIN_5G;
+
+       return ah->eep_ops->get_eeprom(ah, gain_param);
+}
+
+void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
+       struct ieee80211_channel *channel;
+       int chan_pwr, new_pwr, max_gain;
+       int ant_gain, ant_reduction = 0;
+
+       if (!chan)
+               return;
+
+       channel = chan->chan;
+       chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
+       new_pwr = min_t(int, chan_pwr, reg->power_limit);
+       max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
+
+       ant_gain = get_antenna_gain(ah, chan);
+       if (ant_gain > max_gain)
+               ant_reduction = ant_gain - max_gain;
+
+       ah->eep_ops->set_txpower(ah, chan,
+                                ath9k_regd_get_ctl(reg, chan),
+                                ant_reduction, new_pwr, false);
+}
+
 void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
 {
-       struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+       struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
        struct ath9k_channel *chan = ah->curchan;
        struct ieee80211_channel *channel = chan->chan;
-       int reg_pwr = min_t(int, MAX_RATE_POWER, limit);
-       int chan_pwr = channel->max_power * 2;
 
+       reg->power_limit = min_t(int, limit, MAX_RATE_POWER);
        if (test)
-               reg_pwr = chan_pwr = MAX_RATE_POWER;
+               channel->max_power = MAX_RATE_POWER / 2;
 
-       regulatory->power_limit = reg_pwr;
+       ath9k_hw_apply_txpower(ah, chan);
 
-       ah->eep_ops->set_txpower(ah, chan,
-                                ath9k_regd_get_ctl(regulatory, chan),
-                                channel->max_antenna_gain * 2,
-                                chan_pwr, reg_pwr, test);
+       if (test)
+               channel->max_power = DIV_ROUND_UP(reg->max_power_level, 2);
 }
 EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);