ath9k_hw: clean up tx power handling
[pandora-kernel.git] / drivers / net / wireless / ath / ath9k / hw.c
index f2065fc..949656d 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;
@@ -580,6 +584,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
        case AR_SREV_VERSION_9330:
        case AR_SREV_VERSION_9485:
        case AR_SREV_VERSION_9340:
+       case AR_SREV_VERSION_9480:
                break;
        default:
                ath_err(common,
@@ -664,6 +669,7 @@ int ath9k_hw_init(struct ath_hw *ah)
        case AR9300_DEVID_AR9330:
        case AR9300_DEVID_AR9340:
        case AR9300_DEVID_AR9580:
+       case AR9300_DEVID_AR9480:
                break;
        default:
                if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -1340,6 +1346,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 {
+
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                REG_WRITE(ah, AR_WA, ah->WARegVal);
                udelay(10);
@@ -1381,9 +1388,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;
 
@@ -1408,14 +1413,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))
@@ -1496,14 +1494,16 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        }
        ah->noise = ath9k_hw_getchan_noise(ah, chan);
 
+       if ((AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) ||
+           (AR_SREV_9300_20_OR_LATER(ah) && IS_CHAN_5GHZ(chan)))
+               bChannelChange = false;
+
        if (bChannelChange &&
            (ah->chip_fullsleep != true) &&
            (ah->curchan != NULL) &&
            (chan->channel != ah->curchan->channel) &&
            ((chan->channelFlags & CHANNEL_ALL) ==
-            (ah->curchan->channelFlags & CHANNEL_ALL)) &&
-           (!AR_SREV_9280(ah) || AR_DEVID_7010(ah))) {
-
+            (ah->curchan->channelFlags & CHANNEL_ALL))) {
                if (ath9k_hw_channel_change(ah, chan)) {
                        ath9k_hw_loadnf(ah, ah->curchan);
                        ath9k_hw_start_nfcal(ah, true);
@@ -1743,25 +1743,41 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
 {
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
        if (setChip) {
+               if (AR_SREV_9480(ah)) {
+                       REG_WRITE(ah, AR_TIMER_MODE,
+                                 REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00);
+                       REG_WRITE(ah, AR_NDP2_TIMER_MODE, REG_READ(ah,
+                                 AR_NDP2_TIMER_MODE) & 0xFFFFFF00);
+                       REG_WRITE(ah, AR_SLP32_INC,
+                                 REG_READ(ah, AR_SLP32_INC) & 0xFFF00000);
+                       /* xxx Required for WLAN only case ? */
+                       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
+                       udelay(100);
+               }
+
                /*
                 * Clear the RTC force wake bit to allow the
                 * mac to go to sleep.
                 */
-               REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
-                           AR_RTC_FORCE_WAKE_EN);
+               REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+
+               if (AR_SREV_9480(ah))
+                       udelay(100);
+
                if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
                        REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
 
                /* Shutdown chip. Active low */
-               if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah))
-                       REG_CLR_BIT(ah, (AR_RTC_RESET),
-                                   AR_RTC_RESET_EN);
+               if (!AR_SREV_5416(ah) &&
+                               !AR_SREV_9271(ah) && !AR_SREV_9480_10(ah)) {
+                       REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
+                       udelay(2);
+               }
        }
 
        /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
-       if (AR_SREV_9300_20_OR_LATER(ah))
-               REG_WRITE(ah, AR_WA,
-                         ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
+       if (!AR_SREV_9480(ah))
+               REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
 }
 
 /*
@@ -1771,6 +1787,8 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
  */
 static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
 {
+       u32 val;
+
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
        if (setChip) {
                struct ath9k_hw_capabilities *pCap = &ah->caps;
@@ -1780,12 +1798,30 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
                        REG_WRITE(ah, AR_RTC_FORCE_WAKE,
                                  AR_RTC_FORCE_WAKE_ON_INT);
                } else {
+
+                       /* When chip goes into network sleep, it could be waken
+                        * up by MCI_INT interrupt caused by BT's HW messages
+                        * (LNA_xxx, CONT_xxx) which chould be in a very fast
+                        * rate (~100us). This will cause chip to leave and
+                        * re-enter network sleep mode frequently, which in
+                        * consequence will have WLAN MCI HW to generate lots of
+                        * SYS_WAKING and SYS_SLEEPING messages which will make
+                        * BT CPU to busy to process.
+                        */
+                       if (AR_SREV_9480(ah)) {
+                               val = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) &
+                                       ~AR_MCI_INTERRUPT_RX_HW_MSG_MASK;
+                               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, val);
+                       }
                        /*
                         * Clear the RTC force wake bit to allow the
                         * mac to go to sleep.
                         */
                        REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
                                    AR_RTC_FORCE_WAKE_EN);
+
+                       if (AR_SREV_9480(ah))
+                               udelay(30);
                }
        }
 
@@ -2112,6 +2148,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))
@@ -2404,6 +2444,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
 
        ENABLE_REGWRITE_BUFFER(ah);
 
+       if (AR_SREV_9480(ah))
+               bits |= ATH9K_RX_FILTER_CONTROL_WRAPPER;
+
        REG_WRITE(ah, AR_RX_FILTER, bits);
 
        phybits = 0;
@@ -2445,23 +2488,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);
 
@@ -2660,6 +2736,20 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,
        REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
                    gen_tmr_configuration[timer->index].mode_mask);
 
+       if (AR_SREV_9480(ah)) {
+               /*
+                * Starting from AR9480, each generic timer can select which tsf
+                * to use. But we still follow the old rule, 0 - 7 use tsf and
+                * 8 - 15  use tsf2.
+                */
+               if ((timer->index < AR_GEN_TIMER_BANK_1_LEN))
+                       REG_CLR_BIT(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL,
+                                      (1 << timer->index));
+               else
+                       REG_SET_BIT(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL,
+                                      (1 << timer->index));
+       }
+
        /* Enable both trigger and thresh interrupt masks */
        REG_SET_BIT(ah, AR_IMR_S5,
                (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
@@ -2765,6 +2855,7 @@ static struct {
        { AR_SREV_VERSION_9330,         "9330" },
        { AR_SREV_VERSION_9340,         "9340" },
        { AR_SREV_VERSION_9485,         "9485" },
+       { AR_SREV_VERSION_9480,         "9480" },
 };
 
 /* For devices with external radios */