rt2x00: mt7620: lots of improvements
authorDaniel Golle <daniel@makrotopia.org>
Fri, 3 Feb 2017 14:02:32 +0000 (15:02 +0100)
committerDaniel Golle <daniel@makrotopia.org>
Wed, 8 Feb 2017 21:21:26 +0000 (22:21 +0100)
This commit combines all the changes I've made on my staging tree
into a single commit fixing many issues with our patch for MT7620.

First of all, checkpatch.pl revealed numerous code style issues with
the patch, so fix all the white-space and commets. Also use
usleep_range instead of legacy timing and relax timing for VCO
calibration just like the vendor driver does.

Several line programming registers were commented out in the patch.
Originally this came from the features present but disabled by default
in the vendor's driver (RTMP_TEMPERATURE_CALIBRATION and
ADJUST_POWER_CONSUMPTION_SUPPORT). Remove the dead code for now, it can
easily be re-added if we actually intend to support those features.

Move values from mt7620_freqconfig type into the existing rf_channel
struct, this shouldn't be a new typedef and it is possible to use the
existing struct because rf_channel got 4 32-bit fields, so two of the
8-bit values from mt7620_freqconfig can easily be stored in the same
32-bit field.

Map values such that
Rdiv -> rf1
N    -> rf2
K    -> rf3[0:7]
D    -> rf3[8:15]
Ksd  -> rf4

This makes the channel switching logic already look a bit more like
what we are used to in rt2x00... Probably many of the read-modify-write
calls could still be replaced by macros intended for that.

iq calibration seems to be identical to RT5592, so just enable it.
Test shows that this improves things quite a lot, datarates went up
by a couple of megabits when running iperf, signal quality seems jumpy
in the first few seconds once a station connencts, the stabelizes on a
value significantly better than what it was before.

Add description to the patch and reference the original OpenWrt commit
by which it was added.

The patch now passes checkpatch.pl and can thus be discussed with the
upstream authors of the rt2x00 driver.

Funded-by: https://www.kickstarter.com/projects/1327597961/better-support-for-mt7620a-n-in-openwrt-lede/
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
package/kernel/mac80211/patches/621-rt2x00-add-support-for-mt7620.patch

index ecb046b..e71ea45 100644 (file)
@@ -1,3 +1,14 @@
+From: Roman Yeryomin <roman@advem.lv>
+Date: Tue, 1 Jul 2014 10:26:18 +0000
+Subject: [PATCH] mac80211: rt2x00: add support for mt7620
+
+Support for MT7620 was added to OpenWrt in r41441 and heavily reworked
+since in order to match the Kernel's code quality standards.
+
+Signed-off-by: Roman Yeryomin <roman@advem.lv>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+
 --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
 +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
 @@ -81,6 +81,7 @@
  #define TX_PWR_CFG_7_OFDM54_CH0               FIELD32(0x0000000f)
 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
 +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -60,6 +60,8 @@
+@@ -60,6 +60,9 @@
        rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg))
  #define WAIT_FOR_RFCSR(__dev, __reg) \
        rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg))
 +#define WAIT_FOR_RFCSR_MT7620(__dev, __reg) \
-+      rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY_MT7620, (__reg))
++      rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY_MT7620, \
++                          (__reg))
  #define WAIT_FOR_RF(__dev, __reg) \
        rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg))
  #define WAIT_FOR_MCU(__dev, __reg) \
-@@ -151,19 +153,55 @@ static void rt2800_rfcsr_write(struct rt
+@@ -151,19 +154,56 @@ static void rt2800_rfcsr_write(struct rt
         * Wait until the RFCSR becomes available, afterwards we
         * can safely write the new data into the register.
         */
 +              if (WAIT_FOR_RFCSR_MT7620(rt2x00dev, &reg)) {
 +                      reg = 0;
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_DATA_MT7620, value);
-+                      rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM_MT7620, word);
++                      rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM_MT7620,
++                                         word);
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE_MT7620, 1);
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY_MT7620, 1);
--              rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
++
 +                      rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
 +              }
 +              break;
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 1);
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
-+
+-              rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
 +                      rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
 +              }
 +              break;
  static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev,
                              const unsigned int word, u8 *value)
  {
-@@ -179,22 +217,47 @@ static void rt2800_rfcsr_read(struct rt2
+@@ -179,22 +219,48 @@ static void rt2800_rfcsr_read(struct rt2
         * doesn't become available in time, reg will be 0xffffffff
         * which means we return 0xff to the caller.
         */
 +      case RF7620:
 +              if (WAIT_FOR_RFCSR_MT7620(rt2x00dev, &reg)) {
 +                      reg = 0;
-+                      rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM_MT7620, word);
++                      rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM_MT7620,
++                                         word);
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE_MT7620, 0);
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY_MT7620, 1);
  
 -      }
 +                      WAIT_FOR_RFCSR_MT7620(rt2x00dev, &reg);
 +              }
--      *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA);
++
 +              *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA_MT7620);
 +              break;
 +
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 0);
 +                      rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
-+
+-      *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA);
 +                      rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg);
 +
 +                      WAIT_FOR_RFCSR(rt2x00dev, &reg);
  static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev,
                            const unsigned int word, const u32 value)
  {
-@@ -526,6 +589,16 @@ void rt2800_get_txwi_rxwi_size(struct rt
+@@ -526,6 +592,16 @@ void rt2800_get_txwi_rxwi_size(struct rt
                *rxwi_size = RXWI_DESC_SIZE_5WORDS;
                break;
  
 +      case RT5390:
-+              if ( rt2x00dev->chip.rf == RF7620 ) {
++              if (rt2x00dev->chip.rf == RF7620) {
 +                      *txwi_size = TXWI_DESC_SIZE_5WORDS;
 +                      *rxwi_size = RXWI_DESC_SIZE_6WORDS;
 +              } else {
        case RT5592:
                *txwi_size = TXWI_DESC_SIZE_5WORDS;
                *rxwi_size = RXWI_DESC_SIZE_6WORDS;
-@@ -3258,6 +3331,317 @@ static void rt2800_config_channel_rf55xx
+@@ -3258,6 +3334,296 @@ static void rt2800_config_channel_rf55xx
        rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x19 : 0x7F);
  }
  
-+typedef struct mt7620_freqconfig {
-+      u8      Channel;
-+      u8      Rdiv;
-+      u16     N;
-+      u8      K;
-+      u8      D;
-+      u32     Ksd;
-+} mt7620_freqconfig;
-+
-+mt7620_freqconfig mt7620_chanconfig[] =
-+{
-+      /* 2.4 to 2.483 GHz
-+       * CH   Rdiv    N       K       D       Ksd */
-+      { 0,    0,      0,      0,      0,      0       },
-+      { 1,    3,      0x50,   0,      0,      0x19999 },
-+      { 2,    3,      0x50,   0,      0,      0x24444 },
-+      { 3,    3,      0x50,   0,      0,      0x2EEEE },
-+      { 4,    3,      0x50,   0,      0,      0x39999 },
-+      { 5,    3,      0x51,   0,      0,      0x04444 },
-+      { 6,    3,      0x51,   0,      0,      0x0EEEE },
-+      { 7,    3,      0x51,   0,      0,      0x19999 },
-+      { 8,    3,      0x51,   0,      0,      0x24444 },
-+      { 9,    3,      0x51,   0,      0,      0x2EEEE },
-+      { 10,   3,      0x51,   0,      0,      0x39999 },
-+      { 11,   3,      0x52,   0,      0,      0x04444 },
-+      { 12,   3,      0x52,   0,      0,      0x0EEEE },
-+      { 13,   3,      0x52,   0,      0,      0x19999 },
-+      { 14,   3,      0x52,   0,      0,      0x33333 },
-+};
-+
 +static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev,
 +                                       struct ieee80211_conf *conf,
 +                                       struct rf_channel *rf,
 +      int i;
 +
 +      /* Frequeny plan setting */
-+      /*      
-+        * Rdiv setting
-+        * R13[1:0] 
-+        */
++      /* Rdiv setting (stored in rf->rf1)
++       * R13[1:0]
++       */
 +      rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
 +      rfcsr = rfcsr & (~0x03);
 +      if (rt2800_clk_is_20mhz(rt2x00dev))
-+              rfcsr |= (mt7620_chanconfig[rf->channel].Rdiv & 0x3);
++              rfcsr |= (rf->rf1 & 0x03);
++
 +      rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
 +
-+      /*  
-+       * N setting
-+       * R21[0], R20[7:0] 
++      /* N setting (stored in rf->rf2)
++       * R21[0], R20[7:0]
 +       */
 +      rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr);
-+      rfcsr = (mt7620_chanconfig[rf->channel].N & 0x00ff);
++      rfcsr = (rf->rf2 & 0x00ff);
 +      rt2800_rfcsr_write(rt2x00dev, 20, rfcsr);
 +
 +      rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr);
 +      rfcsr = rfcsr & (~0x01);
-+      rfcsr |= ((mt7620_chanconfig[rf->channel].N & 0x0100) >> 8);
++      rfcsr |= ((rf->rf2 & 0x0100) >> 8);
 +      rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
 +
-+      /* 
-+       * K setting 
++      /* K setting (stored in rf->rf3[0:7])
 +       * R16[3:0] (RF PLL freq selection)
 +       */
 +      rt2800_rfcsr_read(rt2x00dev, 16, &rfcsr);
 +      rfcsr = rfcsr & (~0x0f);
-+      rfcsr |= (mt7620_chanconfig[rf->channel].K & 0x0f);
++      rfcsr |= (rf->rf3 & 0x0f);
 +      rt2800_rfcsr_write(rt2x00dev, 16, rfcsr);
 +
-+      /* 
-+       * D setting 
++      /* D setting (stored in rf->rf3[8:15])
 +       * R22[2:0] (D=15, R22[2:0]=<111>)
 +       */
 +      rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr);
 +      rfcsr = rfcsr & (~0x07);
-+      rfcsr |= (mt7620_chanconfig[rf->channel].D & 0x07);
++      rfcsr |= ((rf->rf3 >> 8) & 0x07);
 +      rt2800_rfcsr_write(rt2x00dev, 22, rfcsr);
 +
-+      /*      
-+       * Ksd setting
++      /* Ksd setting (stored in rf->rf4)
 +       * Ksd: R19<1:0>,R18<7:0>,R17<7:0>
 +       */
 +      rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
-+      rfcsr = (mt7620_chanconfig[rf->channel].Ksd & 0x000000ff);
++      rfcsr = (rf->rf4 & 0x000000ff);
 +      rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
 +
 +      rt2800_rfcsr_read(rt2x00dev, 18, &rfcsr);
-+      rfcsr = ((mt7620_chanconfig[rf->channel].Ksd & 0x0000ff00) >> 8);
++      rfcsr = ((rf->rf4 & 0x0000ff00) >> 8);
 +      rt2800_rfcsr_write(rt2x00dev, 18, rfcsr);
 +
 +      rt2800_rfcsr_read(rt2x00dev, 19, &rfcsr);
 +      rfcsr = rfcsr & (~0x03);
-+      rfcsr |= ((mt7620_chanconfig[rf->channel].Ksd & 0x00030000) >> 16);
++      rfcsr |= ((rf->rf4 & 0x00030000) >> 16);
 +      rt2800_rfcsr_write(rt2x00dev, 19, rfcsr);
 +
 +      /* Default: XO=20MHz , SDM mode */
 +                                              RFCSR24_TX_AGC_FC);
 +      } else {
 +              txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw20,
-+                                              RFCSR24_TX_AGC_FC);             
++                                              RFCSR24_TX_AGC_FC);
 +      }
 +      rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &rfcsr);
 +      rfcsr &= (~0x3F);
 +      for (i = 0; i < 10000; i++) {
 +              rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, &mac_status);
 +              if (mac_status & 0x3)
-+                      udelay(50);
++                      usleep_range(50, 200);
 +              else
 +                      break;
 +      }
 +      rt2800_rfcsr_read(rt2x00dev, 4, &rfcsr);
 +      rfcsr = ((rfcsr & ~0x80) | 0x80);
 +      rt2800_rfcsr_write(rt2x00dev, 4, rfcsr);
-+      mdelay(2);
++      usleep_range(2000, 3000);
 +
 +      rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
 +
 +              rt2800_bbp_write(rt2x00dev, 195, 170);
 +              rt2800_bbp_write(rt2x00dev, 196, 0x12);
 +              rt2800_bbp_write(rt2x00dev, 195, 171);
-+              rt2800_bbp_write(rt2x00dev, 196, 0x10);         
++              rt2800_bbp_write(rt2x00dev, 196, 0x10);
 +      } else {
 +              rt2800_bbp_write(rt2x00dev, 91, 0x06);
 +              rt2800_bbp_write(rt2x00dev, 95, 0x9A);
 +              rt2800_bbp_write(rt2x00dev, 196, 0x30);
 +      }
 +
-+      /* On 11A, We should delay and wait RF/BBP to be stable*/
-+      /* and the appropriate time should be 1000 micro seconds */
-+      /* 2005/06/05 - On 11G, We also need this delay time.
-+       * Otherwise it's difficult to pass the WHQL.*/
-+      udelay(1000);
-+}
++      if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
++              rt2800_bbp_write(rt2x00dev, 75, 0x60);
++              rt2800_bbp_write(rt2x00dev, 76, 0x44);
++              rt2800_bbp_write(rt2x00dev, 79, 0x1C);
++              rt2800_bbp_write(rt2x00dev, 80, 0x0C);
++              rt2800_bbp_write(rt2x00dev, 82, 0xB6);
 +
++              if (!conf_is_ht40(conf)) {
++                      rt2800_bbp_write(rt2x00dev, 195, 141);
++                      rt2800_bbp_write(rt2x00dev, 196, 0x1A);
++              }
++      }
++
++      /* On 11A, We should delay and wait RF/BBP to be stable
++       * and the appropriate time should be 1000 micro seconds
++       * 2005/06/05 - On 11G, we also need this delay time.
++       * Otherwise it's difficult to pass the WHQL.
++       */
++      usleep_range(1000, 1500);
++}
 +
  static void rt2800_bbp_write_with_rx_chain(struct rt2x00_dev *rt2x00dev,
                                           const unsigned int word,
                                           const u8 value)
-@@ -3414,7 +3798,7 @@ static void rt2800_config_channel(struct
+@@ -3414,7 +3780,7 @@ static void rt2800_config_channel(struct
                                  struct channel_info *info)
  {
        u32 reg;
        u8 bbp, rfcsr;
  
        info->default_power1 = rt2800_txpower_to_dev(rt2x00dev, rf->channel,
-@@ -3468,6 +3852,9 @@ static void rt2800_config_channel(struct
+@@ -3468,6 +3834,9 @@ static void rt2800_config_channel(struct
        case RF5592:
                rt2800_config_channel_rf55xx(rt2x00dev, conf, rf, info);
                break;
        default:
                rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
        }
-@@ -3574,7 +3961,7 @@ static void rt2800_config_channel(struct
+@@ -3574,7 +3943,7 @@ static void rt2800_config_channel(struct
                else if (rt2x00_rt(rt2x00dev, RT3593) ||
                         rt2x00_rt(rt2x00dev, RT3883))
                        rt2800_bbp_write(rt2x00dev, 82, 0x82);
                        rt2800_bbp_write(rt2x00dev, 82, 0xf2);
  
                if (rt2x00_rt(rt2x00dev, RT3593) ||
-@@ -3596,7 +3983,7 @@ static void rt2800_config_channel(struct
+@@ -3596,7 +3965,7 @@ static void rt2800_config_channel(struct
        if (rt2x00_rt(rt2x00dev, RT3572))
                rt2800_rfcsr_write(rt2x00dev, 8, 0);
  
  
        switch (rt2x00dev->default_ant.tx_chain_num) {
        case 3:
-@@ -3645,6 +4032,7 @@ static void rt2800_config_channel(struct
+@@ -3645,6 +4014,7 @@ static void rt2800_config_channel(struct
  
        rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1);
        rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1);
  
        rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
  
-@@ -4662,6 +5050,14 @@ void rt2800_vco_calibration(struct rt2x0
+@@ -3720,7 +4090,8 @@ static void rt2800_config_channel(struct
+               usleep_range(1000, 1500);
+       }
+-      if (rt2x00_rt(rt2x00dev, RT5592)) {
++      if (rt2x00_rt(rt2x00dev, RT5592) ||
++          (rt2x00_rt(rt2x00dev, RT5390) && rt2x00_rf(rt2x00dev, RF7620))) {
+               rt2800_bbp_write(rt2x00dev, 195, 141);
+               rt2800_bbp_write(rt2x00dev, 196, conf_is_ht40(conf) ? 0x10 : 0x1a);
+@@ -4662,6 +5033,15 @@ void rt2800_vco_calibration(struct rt2x0
                rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1);
                rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
                break;
 +      case RF7620:
 +              rt2800_rfcsr_read(rt2x00dev, 4, &rfcsr);
 +              /* vcocal_en (initiate VCO calibration (reset after completion))
-+               * It should be at the end of RF configuration. */
-+              rfcsr = ((rfcsr & ~0x80) | 0x80); 
++               * It should be at the end of RF configuration.
++               */
++              rfcsr = ((rfcsr & ~0x80) | 0x80);
 +              rt2800_rfcsr_write(rt2x00dev, 4, rfcsr);
-+              mdelay(1);
++              usleep_range(2000, 3000);
 +              break;
        default:
                WARN_ONCE(1, "Not supported RF chipet %x for VCO recalibration",
                          rt2x00dev->chip.rf);
-@@ -5037,6 +5433,24 @@ static int rt2800_init_registers(struct
+@@ -5037,6 +5417,24 @@ static int rt2800_init_registers(struct
                rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00040000);
                rt2800_register_write(rt2x00dev, TX_TXBF_CFG_0, 0x8000fc21);
                rt2800_register_write(rt2x00dev, TX_TXBF_CFG_3, 0x00009c40);
        } else if (rt2x00_rt(rt2x00dev, RT5390) ||
                   rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
-@@ -6075,6 +6489,225 @@ static void rt2800_init_bbp_5592(struct
+@@ -6075,6 +6473,225 @@ static void rt2800_init_bbp_5592(struct
                rt2800_bbp_write(rt2x00dev, 103, 0xc0);
  }
  
  static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
  {
        unsigned int i;
-@@ -6117,7 +6750,10 @@ static void rt2800_init_bbp(struct rt2x0
+@@ -6117,7 +6735,10 @@ static void rt2800_init_bbp(struct rt2x0
                return;
        case RT5390:
        case RT5392:
                break;
        case RT5592:
                rt2800_init_bbp_5592(rt2x00dev);
-@@ -7331,6 +7967,295 @@ static void rt2800_init_rfcsr_5592(struc
+@@ -7331,6 +7952,277 @@ static void rt2800_init_rfcsr_5592(struc
        rt2800_led_open_drain_enable(rt2x00dev);
  }
  
 +      rt2800_rfcsr_write(rt2x00dev, 28, 0x62);
 +      rt2800_rfcsr_write(rt2x00dev, 29, 0xAD);
 +      rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
-+      /* RTMP_TEMPERATURE_CALIBRATION */
-+      /* rt2800_rfcsr_write(rt2x00dev, 34, 0x23); */
-+      /* rt2800_rfcsr_write(rt2x00dev, 35, 0x01); */
 +
 +      /* use rt2800_adjust_freq_offset ? */
 +      rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &freq);
 +      rt2800_rfcsr_write_chanreg(rt2x00dev, 62, 0x1C);
 +      rt2800_rfcsr_write_chanreg(rt2x00dev, 63, 0x00);
 +
-+      rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5);
++      rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5);
 +
 +      rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47);
 +      rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71);
 +      rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02);
 +      rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7);
 +
-+      /* reduce power consumption */
-+/*    rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0x53);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0x53);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0x53);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x64);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0x4F);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x02);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0x4F);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x02);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x27);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x64);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0x4F);
-+      rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x02);
-+*/
 +      /* Initialize RF DC calibration register to default value */
 +      rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47);
 +      rt2800_rfcsr_write_dccal(rt2x00dev, 1, 0x00);
  static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
  {
        if (rt2800_is_305x_soc(rt2x00dev)) {
-@@ -7366,7 +8291,10 @@ static void rt2800_init_rfcsr(struct rt2
+@@ -7366,7 +8258,10 @@ static void rt2800_init_rfcsr(struct rt2
                rt2800_init_rfcsr_5350(rt2x00dev);
                break;
        case RT5390:
                break;
        case RT5392:
                rt2800_init_rfcsr_5392(rt2x00dev);
-@@ -7780,6 +8708,7 @@ static int rt2800_init_eeprom(struct rt2
+@@ -7780,6 +8675,7 @@ static int rt2800_init_eeprom(struct rt2
        case RF5390:
        case RF5392:
        case RF5592:
                break;
        default:
                rt2x00_err(rt2x00dev, "Invalid RF chipset 0x%04x detected\n",
-@@ -8354,6 +9283,7 @@ static int rt2800_probe_hw_mode(struct r
-       case RF5372:
-       case RF5390:
-       case RF5392:
+@@ -8258,6 +9154,24 @@ static const struct rf_channel rf_vals_5
+       {196, 83, 0, 12, 1},
+ };
++static const struct rf_channel rf_vals_7620[] = {
++      /* Channel, Rdiv, N, K | (D >> 8), Ksd */
++      {1, 3, 0x50, 0 | (0 >> 8), 0x19999},
++      {2, 3, 0x50, 0 | (0 >> 8), 0x24444},
++      {3, 3, 0x50, 0 | (0 >> 8), 0x2EEEE},
++      {4, 3, 0x50, 0 | (0 >> 8), 0x39999},
++      {5, 3, 0x51, 0 | (0 >> 8), 0x04444},
++      {6, 3, 0x51, 0 | (0 >> 8), 0x0EEEE},
++      {7, 3, 0x51, 0 | (0 >> 8), 0x19999},
++      {8, 3, 0x51, 0 | (0 >> 8), 0x24444},
++      {9, 3, 0x51, 0 | (0 >> 8), 0x2EEEE},
++      {10, 3, 0x51, 0 | (0 >> 8), 0x39999},
++      {11, 3, 0x52, 0 | (0 >> 8), 0x04444},
++      {12, 3, 0x52, 0 | (0 >> 8), 0x0EEEE},
++      {13, 3, 0x52, 0 | (0 >> 8), 0x19999},
++      {14, 3, 0x52, 0 | (0 >> 8), 0x33333},
++};
++
+ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+ {
+       struct hw_mode_spec *spec = &rt2x00dev->spec;
+@@ -8361,6 +9275,11 @@ static int rt2800_probe_hw_mode(struct r
+                       spec->channels = rf_vals_3x;
+               break;
 +      case RF7620:
-               spec->num_channels = 14;
-               if (rt2800_clk_is_20mhz(rt2x00dev))
-                       spec->channels = rf_vals_3x_xtal20;
-@@ -8498,6 +9428,7 @@ static int rt2800_probe_hw_mode(struct r
++              spec->num_channels = ARRAY_SIZE(rf_vals_7620);
++              spec->channels = rf_vals_7620;
++              break;
++
+       case RF3052:
+       case RF3053:
+               spec->num_channels = ARRAY_SIZE(rf_vals_3x);
+@@ -8498,6 +9417,7 @@ static int rt2800_probe_hw_mode(struct r
        case RF5390:
        case RF5392:
        case RF5592: