carl9170: allow users to lower output power level
authorChristian Lamparter <chunkeey@googlemail.com>
Sat, 21 Jan 2012 15:59:10 +0000 (16:59 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 27 Jan 2012 19:56:57 +0000 (14:56 -0500)
This patch implements a simple way of reducing the
output power of the device by a configurable upper
limit.

Requested-by: Harshal Chhaya <harshal@gmail.com>
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/carl9170/carl9170.h
drivers/net/wireless/ath/carl9170/mac.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/phy.c
drivers/net/wireless/ath/carl9170/tx.c

index f0f44c30b2f74297c3336c83706d2cbbf733920f..0cea20e3e250049d58b96466bcfed59927ae158b 100644 (file)
@@ -559,6 +559,7 @@ int carl9170_set_hwretry_limit(struct ar9170 *ar, const u32 max_retry);
 int carl9170_upload_key(struct ar9170 *ar, const u8 id, const u8 *mac,
        const u8 ktype, const u8 keyidx, const u8 *keydata, const int keylen);
 int carl9170_disable_key(struct ar9170 *ar, const u8 id);
+int carl9170_set_mac_tpc(struct ar9170 *ar, struct ieee80211_channel *channel);
 
 /* RX */
 void carl9170_rx(struct ar9170 *ar, void *buf, unsigned int len);
index dfda919709954d27cb0a288c556c9933e55c731c..53415bfd8bef7e673749904369775520ff74beae 100644 (file)
@@ -485,3 +485,38 @@ int carl9170_disable_key(struct ar9170 *ar, const u8 id)
        return carl9170_exec_cmd(ar, CARL9170_CMD_DKEY,
                sizeof(key), (u8 *)&key, 0, NULL);
 }
+
+int carl9170_set_mac_tpc(struct ar9170 *ar, struct ieee80211_channel *channel)
+{
+       unsigned int power, chains;
+
+       if (ar->eeprom.tx_mask != 1)
+               chains = AR9170_TX_PHY_TXCHAIN_2;
+       else
+               chains = AR9170_TX_PHY_TXCHAIN_1;
+
+       switch (channel->band) {
+       case IEEE80211_BAND_2GHZ:
+               power = ar->power_2G_ofdm[0] & 0x3f;
+               break;
+       case IEEE80211_BAND_5GHZ:
+               power = ar->power_5G_leg[0] & 0x3f;
+               break;
+       default:
+               BUG_ON(1);
+       }
+
+       power = min_t(unsigned int, power, ar->hw->conf.power_level * 2);
+
+       carl9170_regwrite_begin(ar);
+       carl9170_regwrite(AR9170_MAC_REG_ACK_TPC,
+                         0x3c1e | power << 20 | chains << 26);
+       carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_TPC,
+                         power << 5 | chains << 11 |
+                         power << 21 | chains << 27);
+       carl9170_regwrite(AR9170_MAC_REG_CFEND_QOSNULL_TPC,
+                         power << 5 | chains << 11 |
+                         power << 21 | chains << 27);
+       carl9170_regwrite_finish();
+       return carl9170_regwrite_result();
+}
index 6ee7c55f75a85e42ce7505cf7b87feb7939f3892..8d2523b3f722ea39785876333a687cfd9597bfd9 100644 (file)
@@ -853,11 +853,6 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
                        goto out;
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_POWER) {
-               /* TODO */
-               err = 0;
-       }
-
        if (changed & IEEE80211_CONF_CHANGE_SMPS) {
                /* TODO */
                err = 0;
@@ -891,6 +886,12 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
                        goto out;
        }
 
+       if (changed & IEEE80211_CONF_CHANGE_POWER) {
+               err = carl9170_set_mac_tpc(ar, ar->hw->conf.channel);
+               if (err)
+                       goto out;
+       }
+
 out:
        mutex_unlock(&ar->mutex);
        return err;
index 472efc7e34022ffbc9162afb9752069803833edd..b72c09cf43a4c614a56d5b63ca1f34f11b28d4f0 100644 (file)
@@ -1426,15 +1426,15 @@ static void carl9170_calc_ctl(struct ar9170 *ar, u32 freq, enum carl9170_bw bw)
 #undef EDGES
 }
 
-static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq,
-                                 enum carl9170_bw bw)
+static void carl9170_set_power_cal(struct ar9170 *ar, u32 freq,
+                                  enum carl9170_bw bw)
 {
        struct ar9170_calibration_target_power_legacy *ctpl;
        struct ar9170_calibration_target_power_ht *ctph;
        u8 *ctpres;
        int ntargets;
        int idx, i, n;
-       u8 ackpower, ackchains, f;
+       u8 f;
        u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS];
 
        if (freq < 3000)
@@ -1523,32 +1523,6 @@ static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq,
 
        /* calc. conformance test limits and apply to ar->power*[] */
        carl9170_calc_ctl(ar, freq, bw);
-
-       /* set ACK/CTS TX power */
-       carl9170_regwrite_begin(ar);
-
-       if (ar->eeprom.tx_mask != 1)
-               ackchains = AR9170_TX_PHY_TXCHAIN_2;
-       else
-               ackchains = AR9170_TX_PHY_TXCHAIN_1;
-
-       if (freq < 3000)
-               ackpower = ar->power_2G_ofdm[0] & 0x3f;
-       else
-               ackpower = ar->power_5G_leg[0] & 0x3f;
-
-       carl9170_regwrite(AR9170_MAC_REG_ACK_TPC,
-                         0x3c1e | ackpower << 20 | ackchains << 26);
-       carl9170_regwrite(AR9170_MAC_REG_RTS_CTS_TPC,
-                         ackpower << 5 | ackchains << 11 |
-                         ackpower << 21 | ackchains << 27);
-
-       carl9170_regwrite(AR9170_MAC_REG_CFEND_QOSNULL_TPC,
-                         ackpower << 5 | ackchains << 11 |
-                         ackpower << 21 | ackchains << 27);
-
-       carl9170_regwrite_finish();
-       return carl9170_regwrite_result();
 }
 
 int carl9170_get_noisefloor(struct ar9170 *ar)
@@ -1712,7 +1686,9 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
        if (err)
                return err;
 
-       err = carl9170_set_power_cal(ar, channel->center_freq, bw);
+       carl9170_set_power_cal(ar, channel->center_freq, bw);
+
+       err = carl9170_set_mac_tpc(ar, channel);
        if (err)
                return err;
 
index d19a9ee9d057a904577d9497435911bc2867e978..771e1a9294c54e1d70e1183e2cdbe00fa2595dc7 100644 (file)
@@ -719,6 +719,8 @@ static void carl9170_tx_rate_tpc_chains(struct ar9170 *ar,
                else
                        *chains = AR9170_TX_PHY_TXCHAIN_2;
        }
+
+       *tpc = min_t(unsigned int, *tpc, ar->hw->conf.power_level * 2);
 }
 
 static __le32 carl9170_tx_physet(struct ar9170 *ar,