ath9k: Enable dynamic power save in ath9k.
[pandora-kernel.git] / drivers / net / wireless / ath9k / hw.c
index 34474ed..ab15e55 100644 (file)
 #include "phy.h"
 #include "initvals.h"
 
-static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 };
+static int btcoex_enable;
+module_param(btcoex_enable, bool, 0);
+MODULE_PARM_DESC(btcoex_enable, "Enable Bluetooth coexistence support");
 
-extern struct hal_percal_data iq_cal_multi_sample;
-extern struct hal_percal_data iq_cal_single_sample;
-extern struct hal_percal_data adc_gain_cal_multi_sample;
-extern struct hal_percal_data adc_gain_cal_single_sample;
-extern struct hal_percal_data adc_dc_cal_multi_sample;
-extern struct hal_percal_data adc_dc_cal_single_sample;
-extern struct hal_percal_data adc_init_dc_cal;
+#define ATH9K_CLOCK_RATE_CCK           22
+#define ATH9K_CLOCK_RATE_5GHZ_OFDM     40
+#define ATH9K_CLOCK_RATE_2GHZ_OFDM     44
 
 static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type);
 static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
@@ -48,17 +46,18 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *cha
 
 static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
 {
-       if (ah->ah_curchan != NULL)
-               return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
-       else
-               return clks / CLOCK_RATE[ATH9K_MODE_11B];
+       struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+       if (!ah->ah_curchan) /* should really check for CCK instead */
+               return clks / ATH9K_CLOCK_RATE_CCK;
+       if (conf->channel->band == IEEE80211_BAND_2GHZ)
+               return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM;
+       return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM;
 }
 
 static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
 {
-       struct ath9k_channel *chan = ah->ah_curchan;
-
-       if (chan && IS_CHAN_HT40(chan))
+       struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+       if (conf_is_ht40(conf))
                return ath9k_hw_mac_usec(ah, clks) / 2;
        else
                return ath9k_hw_mac_usec(ah, clks);
@@ -66,34 +65,23 @@ static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
 
 static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
 {
-       if (ah->ah_curchan != NULL)
-               return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
-                       ah->ah_curchan)];
-       else
-               return usecs * CLOCK_RATE[ATH9K_MODE_11B];
+       struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+       if (!ah->ah_curchan) /* should really check for CCK instead */
+               return usecs *ATH9K_CLOCK_RATE_CCK;
+       if (conf->channel->band == IEEE80211_BAND_2GHZ)
+               return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM;
+       return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM;
 }
 
 static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
 {
-       struct ath9k_channel *chan = ah->ah_curchan;
-
-       if (chan && IS_CHAN_HT40(chan))
+       struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+       if (conf_is_ht40(conf))
                return ath9k_hw_mac_clks(ah, usecs) * 2;
        else
                return ath9k_hw_mac_clks(ah, usecs);
 }
 
-enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
-                              const struct ath9k_channel *chan)
-{
-       if (IS_CHAN_B(chan))
-               return ATH9K_MODE_11B;
-       if (IS_CHAN_G(chan))
-               return ATH9K_MODE_11G;
-
-       return ATH9K_MODE_11A;
-}
-
 bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val)
 {
        int i;
@@ -389,6 +377,8 @@ static const char *ath9k_hw_devname(u16 devid)
                return "Atheros 5418";
        case AR9160_DEVID_PCI:
                return "Atheros 9160";
+       case AR5416_AR9100_DEVID:
+               return "Atheros 9100";
        case AR9280_DEVID_PCI:
        case AR9280_DEVID_PCIE:
                return "Atheros 9280";
@@ -1023,7 +1013,7 @@ static void ath9k_hw_init_pll(struct ath_hal *ah,
                                pll |= SM(0xb, AR_RTC_PLL_DIV);
                }
        }
-       REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
+       REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
 
        udelay(RTC_PLL_SETTLE_DELAY);
 
@@ -1191,6 +1181,7 @@ struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
        switch (devid) {
        case AR5416_DEVID_PCI:
        case AR5416_DEVID_PCIE:
+       case AR5416_AR9100_DEVID:
        case AR9160_DEVID_PCI:
        case AR9280_DEVID_PCI:
        case AR9280_DEVID_PCIE:
@@ -1562,11 +1553,11 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
                        rst_flags |= AR_RTC_RC_MAC_COLD;
        }
 
-       REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
+       REG_WRITE(ah, AR_RTC_RC, rst_flags);
        udelay(50);
 
-       REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
-       if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
+       REG_WRITE(ah, AR_RTC_RC, 0);
+       if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET,
                        "RTC stuck in MAC reset\n");
                return false;
@@ -1588,8 +1579,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
 
-       REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
-       REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
+       REG_WRITE(ah, AR_RTC_RESET, 0);
+       REG_WRITE(ah, AR_RTC_RESET, 1);
 
        if (!ath9k_hw_wait(ah,
                           AR_RTC_STATUS,
@@ -1674,30 +1665,6 @@ static bool ath9k_hw_chip_reset(struct ath_hal *ah,
        return true;
 }
 
-static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
-                                                struct ath9k_channel *chan)
-{
-       if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                       "invalid channel %u/0x%x; not marked as "
-                       "2GHz or 5GHz\n", chan->channel, chan->channelFlags);
-               return NULL;
-       }
-
-       if (!IS_CHAN_OFDM(chan) &&
-           !IS_CHAN_B(chan) &&
-           !IS_CHAN_HT20(chan) &&
-           !IS_CHAN_HT40(chan)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                       "invalid channel %u/0x%x; not marked as "
-                       "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
-                       chan->channel, chan->channelFlags);
-               return NULL;
-       }
-
-       return ath9k_regd_check_channel(ah, chan);
-}
-
 static bool ath9k_hw_channel_change(struct ath_hal *ah,
                                    struct ath9k_channel *chan,
                                    enum ath9k_ht_macmode macmode)
@@ -1918,9 +1885,9 @@ static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel
                if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
 
                        /* workaround for gcc bug #37014 */
-                       volatile int tmp = abs(cur_vit_mask - bin);
+                       volatile int tmp_v = abs(cur_vit_mask - bin);
 
-                       if (tmp < 75)
+                       if (tmp_v < 75)
                                mask_amt = 1;
                        else
                                mask_amt = 0;
@@ -2119,9 +2086,9 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *cha
                if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
 
                        /* workaround for gcc bug #37014 */
-                       volatile int tmp = abs(cur_vit_mask - bin);
+                       volatile int tmp_v = abs(cur_vit_mask - bin);
 
-                       if (tmp < 75)
+                       if (tmp_v < 75)
                                mask_amt = 1;
                        else
                                mask_amt = 0;
@@ -2222,41 +2189,35 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *cha
        REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
-bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
-                   enum ath9k_ht_macmode macmode,
-                   u8 txchainmask, u8 rxchainmask,
-                   enum ath9k_ht_extprotspacing extprotspacing,
-                   bool bChannelChange, int *status)
+int ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
+                   bool bChannelChange)
 {
        u32 saveLedState;
+       struct ath_softc *sc = ah->ah_sc;
        struct ath_hal_5416 *ahp = AH5416(ah);
        struct ath9k_channel *curchan = ah->ah_curchan;
        u32 saveDefAntenna;
        u32 macStaId1;
-       int ecode;
-       int i, rx_chainmask;
+       int i, rx_chainmask, r;
 
-       ahp->ah_extprotspacing = extprotspacing;
-       ahp->ah_txchainmask = txchainmask;
-       ahp->ah_rxchainmask = rxchainmask;
+       ahp->ah_extprotspacing = sc->sc_ht_extprotspacing;
+       ahp->ah_txchainmask = sc->sc_tx_chainmask;
+       ahp->ah_rxchainmask = sc->sc_rx_chainmask;
 
        if (AR_SREV_9280(ah)) {
                ahp->ah_txchainmask &= 0x3;
                ahp->ah_rxchainmask &= 0x3;
        }
 
-       if (ath9k_hw_check_chan(ah, chan) == NULL) {
+       if (ath9k_regd_check_channel(ah, chan) == NULL) {
                DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
                        "invalid channel %u/0x%x; no mapping\n",
                        chan->channel, chan->channelFlags);
-               ecode = -EINVAL;
-               goto bad;
+               return -EINVAL;
        }
 
-       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
-               ecode = -EIO;
-               goto bad;
-       }
+       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+               return -EIO;
 
        if (curchan)
                ath9k_hw_getnf(ah, curchan);
@@ -2270,10 +2231,10 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
            (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
                                   !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) {
 
-               if (ath9k_hw_channel_change(ah, chan, macmode)) {
+               if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) {
                        ath9k_hw_loadnf(ah, ah->ah_curchan);
                        ath9k_hw_start_nfcal(ah);
-                       return true;
+                       return 0;
                }
        }
 
@@ -2291,8 +2252,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 
        if (!ath9k_hw_chip_reset(ah, chan)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n");
-               ecode = -EINVAL;
-               goto bad;
+               return -EINVAL;
        }
 
        if (AR_SREV_9280(ah)) {
@@ -2308,11 +2268,26 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
                ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
        }
 
-       ecode = ath9k_hw_process_ini(ah, chan, macmode);
-       if (ecode != 0) {
-               ecode = -EINVAL;
-               goto bad;
-       }
+       r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width);
+       if (r)
+               return r;
+
+       /* Setup MFP options for CCMP */
+       if (AR_SREV_9280_20_OR_LATER(ah)) {
+               /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
+                * frames when constructing CCMP AAD. */
+               REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT,
+                             0xc7ff);
+               ah->sw_mgmt_crypto = false;
+       } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+               /* Disable hardware crypto for management frames */
+               REG_CLR_BIT(ah, AR_PCU_MISC_MODE2,
+                           AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
+               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+                           AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
+               ah->sw_mgmt_crypto = true;
+       } else
+               ah->sw_mgmt_crypto = true;
 
        if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
                ath9k_hw_set_delta_slope(ah, chan);
@@ -2325,8 +2300,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
        if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
                DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
                        "error setting board options\n");
-               ecode = -EIO;
-               goto bad;
+               return -EIO;
        }
 
        ath9k_hw_decrease_chain_power(ah, chan);
@@ -2354,15 +2328,11 @@ bool ath9k_hw_reset(struct ath_hal *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))) {
-                       ecode = -EIO;
-                       goto bad;
-               }
+               if (!(ath9k_hw_ar9280_set_channel(ah, chan)))
+                       return -EIO;
        } else {
-               if (!(ath9k_hw_set_channel(ah, chan))) {
-                       ecode = -EIO;
-                       goto bad;
-               }
+               if (!(ath9k_hw_set_channel(ah, chan)))
+                       return -EIO;
        }
 
        for (i = 0; i < AR_NUM_DCU; i++)
@@ -2396,10 +2366,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 
        ath9k_hw_init_bb(ah, chan);
 
-       if (!ath9k_hw_init_cal(ah, chan)){
-               ecode = -EIO;;
-               goto bad;
-       }
+       if (!ath9k_hw_init_cal(ah, chan))
+               return -EIO;;
 
        rx_chainmask = ahp->ah_rxchainmask;
        if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -2428,11 +2396,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
 #endif
        }
 
-       return true;
-bad:
-       if (status)
-               *status = ecode;
-       return false;
+       return 0;
 }
 
 /************************/
@@ -2658,7 +2622,7 @@ static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
                if (!AR_SREV_9100(ah))
                        REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
 
-               REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
+               REG_CLR_BIT(ah, (AR_RTC_RESET),
                            AR_RTC_RESET_EN);
        }
 }
@@ -2734,7 +2698,7 @@ bool ath9k_hw_setpower(struct ath_hal *ah,
        int status = true, setChip = true;
 
        DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n",
-               modes[ahp->ah_powerMode], modes[mode],
+               modes[ah->ah_power_mode], modes[mode],
                setChip ? "set chip " : "");
 
        switch (mode) {
@@ -2753,7 +2717,7 @@ bool ath9k_hw_setpower(struct ath_hal *ah,
                        "Unknown power mode %u\n", mode);
                return false;
        }
-       ahp->ah_powerMode = mode;
+       ah->ah_power_mode = mode;
 
        return status;
 }
@@ -3332,7 +3296,9 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
        pCap->num_mr_retries = 4;
        pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
 
-       if (AR_SREV_9280_10_OR_LATER(ah))
+       if (AR_SREV_9285_10_OR_LATER(ah))
+               pCap->num_gpio_pins = AR9285_NUM_GPIO;
+       else if (AR_SREV_9280_10_OR_LATER(ah))
                pCap->num_gpio_pins = AR928X_NUM_GPIO;
        else
                pCap->num_gpio_pins = AR_NUM_GPIO;
@@ -3399,6 +3365,12 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
        pCap->num_antcfg_2ghz =
                ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
 
+       if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) {
+               pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX;
+               ah->ah_btactive_gpio = 6;
+               ah->ah_wlanactive_gpio = 5;
+       }
+
        return true;
 }
 
@@ -3577,17 +3549,18 @@ void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
 
 u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
 {
+#define MS_REG_READ(x, y) \
+       (MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y)))
+
        if (gpio >= ah->ah_caps.num_gpio_pins)
                return 0xffffffff;
 
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
-               return (MS
-                       (REG_READ(ah, AR_GPIO_IN_OUT),
-                        AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
-       } else {
-               return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
-                       AR_GPIO_BIT(gpio)) != 0;
-       }
+       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;
+       else
+               return MS_REG_READ(AR, gpio) != 0;
 }
 
 void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
@@ -3893,3 +3866,30 @@ void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
 
        REG_WRITE(ah, AR_2040_MODE, macmode);
 }
+
+/***************************/
+/*  Bluetooth Coexistence  */
+/***************************/
+
+void ath9k_hw_btcoex_enable(struct ath_hal *ah)
+{
+       /* connect bt_active to baseband */
+       REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                       (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
+                        AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
+
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                       AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
+
+       /* Set input mux for bt_active to gpio pin */
+       REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+                       AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+                       ah->ah_btactive_gpio);
+
+       /* Configure the desired gpio port for input */
+       ath9k_hw_cfg_gpio_input(ah, ah->ah_btactive_gpio);
+
+       /* Configure the desired GPIO port for TX_FRAME output */
+       ath9k_hw_cfg_output(ah, ah->ah_wlanactive_gpio,
+                           AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
+}