Merge bcm43xx-mac80211 driver from tree at bu3sch.de, pulled 24/6
[openwrt/svn-archive/archive.git] / package / bcm43xx-mac80211 / src / bcm43xx / bcm43xx_phy.c
index 39ed81f850995c87e344d3fb5fccff1c1bb656cd..406e0034d98ca8030505aff613b287b9d4aa5869 100644 (file)
@@ -285,12 +285,195 @@ void bcm43xx_phy_write(struct bcm43xx_wldev *dev, u16 offset, u16 val)
        bcm43xx_write16(dev, BCM43xx_MMIO_PHY_DATA, val);
 }
 
+static void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower);
+
+/* Adjust the transmission power output (G-PHY) */
+void bcm43xx_set_txpower_g(struct bcm43xx_wldev *dev,
+                          const struct bcm43xx_bbatt *bbatt,
+                          const struct bcm43xx_rfatt *rfatt,
+                          u8 tx_control)
+{
+       struct bcm43xx_phy *phy = &dev->phy;
+       struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
+       u16 bb, rf;
+       u16 tx_bias, tx_magn;
+
+       bb = bbatt->att;
+       rf = rfatt->att;
+       tx_bias = lo->tx_bias;
+       tx_magn = lo->tx_magn;
+       if (unlikely(tx_bias == 0xFF))
+               tx_bias = 0;
+
+       /* Save the values for later */
+       phy->tx_control = tx_control;
+       memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
+       memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
+
+       if (bcm43xx_debug(dev, BCM43xx_DBG_XMITPOWER)) {
+               dprintk(KERN_DEBUG PFX "Tuning TX-power to bbatt(%u), "
+                       "rfatt(%u), tx_control(0x%02X), "
+                       "tx_bias(0x%02X), tx_magn(0x%02X)\n",
+                       bb, rf, tx_control, tx_bias, tx_magn);
+       }
+
+       bcm43xx_phy_set_baseband_attenuation(dev, bb);
+       bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED, BCM43xx_SHM_SH_RFATT, rf);
+       if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+               bcm43xx_radio_write16(dev, 0x43,
+                                     (rf & 0x000F) | (tx_control & 0x0070));
+       } else {
+               bcm43xx_radio_write16(dev, 0x43,
+                                     (bcm43xx_radio_read16(dev, 0x43)
+                                      & 0xFFF0) | (rf & 0x000F));
+               bcm43xx_radio_write16(dev, 0x52,
+                                     (bcm43xx_radio_read16(dev, 0x52)
+                                      & ~0x0070) | (tx_control & 0x0070));
+       }
+       if (has_tx_magnification(phy)) {
+               bcm43xx_radio_write16(dev, 0x52, tx_magn | tx_bias);
+       } else {
+               bcm43xx_radio_write16(dev, 0x52,
+                                     (bcm43xx_radio_read16(dev, 0x52)
+                                      & 0xFFF0) | (tx_bias & 0x000F));
+       }
+       if (phy->type == BCM43xx_PHYTYPE_G)
+               bcm43xx_lo_g_adjust(dev);
+}
+
+static void default_baseband_attenuation(struct bcm43xx_wldev *dev,
+                                        struct bcm43xx_bbatt *bb)
+{
+       struct bcm43xx_phy *phy = &dev->phy;
+
+       if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+               bb->att = 0;
+       else
+               bb->att = 2;
+}
+
+static void default_radio_attenuation(struct bcm43xx_wldev *dev,
+                                     struct bcm43xx_rfatt *rf)
+{
+       struct ssb_bus *bus = dev->dev->bus;
+       struct bcm43xx_phy *phy = &dev->phy;
+
+       rf->with_padmix = 0;
+
+       if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+           bus->boardinfo.type == SSB_BOARD_BCM4309G) {
+               if (bus->boardinfo.rev < 0x43) {
+                       rf->att = 2;
+                       return;
+               } else if (bus->boardinfo.rev < 0x51) {
+                       rf->att = 3;
+                       return;
+               }
+       }
+
+       if (phy->type == BCM43xx_PHYTYPE_A) {
+               rf->att = 0x60;
+               return;
+       }
+
+       switch (phy->radio_ver) {
+       case 0x2053:
+               switch (phy->radio_rev) {
+               case 1:
+                       rf->att = 6;
+                       return;
+               }
+               break;
+       case 0x2050:
+               switch (phy->radio_rev) {
+               case 0:
+                       rf->att = 5;
+                       return;
+               case 1:
+                       if (phy->type == BCM43xx_PHYTYPE_G) {
+                               if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+                                   bus->boardinfo.type == SSB_BOARD_BCM4309G &&
+                                   bus->boardinfo.rev >= 30)
+                                       rf->att = 3;
+                               else if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+                                        bus->boardinfo.type == SSB_BOARD_BU4306)
+                                       rf->att = 3;
+                               else
+                                       rf->att = 1;
+                       } else {
+                               if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+                                   bus->boardinfo.type == SSB_BOARD_BCM4309G &&
+                                   bus->boardinfo.rev >= 30)
+                                       rf->att = 7;
+                               else
+                                       rf->att = 6;
+                       }
+                       return;
+               case 2:
+                       if (phy->type == BCM43xx_PHYTYPE_G) {
+                               if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+                                   bus->boardinfo.type == SSB_BOARD_BCM4309G &&
+                                   bus->boardinfo.rev >= 30)
+                                       rf->att = 3;
+                               else if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+                                        bus->boardinfo.type == SSB_BOARD_BU4306)
+                                       rf->att = 5;
+                               else if (bus->chip_id == 0x4320)
+                                       rf->att = 4;
+                               else
+                                       rf->att = 3;
+                       } else
+                               rf->att = 6;
+                       return;
+               case 3:
+                       rf->att = 5;
+                       return;
+               case 4:
+               case 5:
+                       rf->att = 1;
+                       return;
+               case 6:
+               case 7:
+                       rf->att = 5;
+                       return;
+               case 8:
+                       rf->att = 0xA;
+                       rf->with_padmix = 1;
+                       return;
+               case 9:
+               default:
+                       rf->att = 5;
+                       return;
+               }
+       }
+       rf->att = 5;
+}
+
+static u16 default_tx_control(struct bcm43xx_wldev *dev)
+{
+       struct bcm43xx_phy *phy = &dev->phy;
+
+       if (phy->radio_ver != 0x2050)
+               return 0;
+       if (phy->radio_rev == 1)
+               return BCM43xx_TXCTL_PA2DB | BCM43xx_TXCTL_TXMIX;
+       if (phy->radio_rev < 6)
+               return BCM43xx_TXCTL_PA2DB;
+       if (phy->radio_rev == 8)
+               return BCM43xx_TXCTL_TXMIX;
+       return 0;
+}
+
 /* This func is called "PHY calibrate" in the specs... */
 void bcm43xx_phy_early_init(struct bcm43xx_wldev *dev)
 {
        struct bcm43xx_phy *phy = &dev->phy;
        struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
 
+       default_baseband_attenuation(dev, &phy->bbatt);
+       default_radio_attenuation(dev, &phy->rfatt);
+       phy->tx_control = (default_tx_control(dev) << 4);
+
        bcm43xx_read32(dev, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
        if (phy->type == BCM43xx_PHYTYPE_B ||
            phy->type == BCM43xx_PHYTYPE_G) {
@@ -510,9 +693,12 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_wldev *dev)
 {
        struct ssb_bus *bus = dev->dev->bus;
        struct bcm43xx_phy *phy = &dev->phy;
+       struct bcm43xx_rfatt old_rfatt;
+       struct bcm43xx_bbatt old_bbatt;
+       u8 old_tx_control = 0;
 
-       if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
-           (bus->board_type == SSB_BOARD_BU4306))
+       if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+           (bus->boardinfo.type == SSB_BOARD_BU4306))
                return;
 
        bcm43xx_phy_write(dev, 0x0028, 0x8018);
@@ -531,10 +717,22 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_wldev *dev)
                                              (bcm43xx_radio_read16(dev, 0x0076)
                                               & 0x00F7) | 0x0084);
                } else {
-                       if (phy->radio_rev == 8)
-                               bcm43xx_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
-                       else
-                               bcm43xx_radio_set_txpower_bg(dev, 0xB, 9, 0);
+                       struct bcm43xx_rfatt rfatt;
+                       struct bcm43xx_bbatt bbatt;
+
+                       memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt));
+                       memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt));
+                       old_tx_control = phy->tx_control;
+
+                       bbatt.att = 11;
+                       if (phy->radio_rev == 8) {
+                               rfatt.att = 15;
+                               rfatt.with_padmix = 1;
+                       } else {
+                               rfatt.att = 9;
+                               rfatt.with_padmix = 0;
+                       }
+                       bcm43xx_set_txpower_g(dev, &bbatt, &rfatt, 0);
                }
                bcm43xx_dummy_transmission(dev);
                phy->cur_idle_tssi = bcm43xx_phy_read(dev, BCM43xx_PHY_ITSSI);
@@ -547,13 +745,14 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_wldev *dev)
                                phy->cur_idle_tssi = 0;
                        }
                }
-
                if (phy->radio_ver == 0x2050 && phy->analog == 0) {
                        bcm43xx_radio_write16(dev, 0x0076,
                                              bcm43xx_radio_read16(dev, 0x0076)
                                               & 0xFF7B);
-               } else
-                       bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1);
+               } else {
+                       bcm43xx_set_txpower_g(dev, &old_bbatt,
+                                             &old_rfatt, old_tx_control);
+               }
        }
        bcm43xx_hardware_pctl_init(dev);
        bcm43xx_shm_clear_tssi(dev);
@@ -758,23 +957,19 @@ static void bcm43xx_phy_setupg(struct bcm43xx_wldev *dev)
        if (phy->rev == 1) {
                for (i = 0; i < BCM43xx_TAB_RETARD_SIZE; i++)
                        bcm43xx_ofdmtab_write32(dev, 0x2400, i, bcm43xx_tab_retard[i]);
-               for (i = 0; i < 4; i++) {
-                       bcm43xx_ofdmtab_write16(dev, 0x5404, i, 0x0020);
-                       bcm43xx_ofdmtab_write16(dev, 0x5408, i, 0x0020);
-                       bcm43xx_ofdmtab_write16(dev, 0x540C, i, 0x0020);
-                       bcm43xx_ofdmtab_write16(dev, 0x5410, i, 0x0020);
-               }
+               for (i = 4; i < 20; i++)
+                       bcm43xx_ofdmtab_write16(dev, 0x5400, i, 0x0020);
                bcm43xx_phy_agcsetup(dev);
 
-               if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
-                   (bus->board_type == SSB_BOARD_BU4306) &&
-                   (bus->board_rev == 0x17))
+               if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+                   (bus->boardinfo.type == SSB_BOARD_BU4306) &&
+                   (bus->boardinfo.rev == 0x17))
                        return;
 
                bcm43xx_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
                bcm43xx_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
        } else {
-               for (i = 0; i <= 0x2F; i++)
+               for (i = 0; i < 0x20; i++)
                        bcm43xx_ofdmtab_write16(dev, 0x1000, i, 0x0820);
                bcm43xx_phy_agcsetup(dev);
                bcm43xx_phy_read(dev, 0x0400); /* dummy read */
@@ -782,9 +977,9 @@ static void bcm43xx_phy_setupg(struct bcm43xx_wldev *dev)
                bcm43xx_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
                bcm43xx_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
 
-               if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
-                   (bus->board_type == SSB_BOARD_BU4306) &&
-                   (bus->board_rev == 0x17))
+               if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+                   (bus->boardinfo.type == SSB_BOARD_BU4306) &&
+                   (bus->boardinfo.rev == 0x17))
                        return;
 
                bcm43xx_ofdmtab_write16(dev, 0x0401, 0, 0x0002);
@@ -955,6 +1150,8 @@ static void bcm43xx_phy_inita(struct bcm43xx_wldev *dev)
        struct bcm43xx_phy *phy = &dev->phy;
        u16 tval;
 
+       might_sleep();
+
        if (phy->type == BCM43xx_PHYTYPE_A) {
                bcm43xx_phy_setupa(dev);
        } else {
@@ -974,9 +1171,9 @@ static void bcm43xx_phy_inita(struct bcm43xx_wldev *dev)
                          bcm43xx_phy_read(dev, BCM43xx_PHY_A_CRS) | (1 << 14));
        bcm43xx_radio_init2060(dev);
 
-       if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
-           ((bus->board_type == SSB_BOARD_BU4306) ||
-            (bus->board_type == SSB_BOARD_BU4309))) {
+       if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+           ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
+            (bus->boardinfo.type == SSB_BOARD_BU4309))) {
                if (phy->lofcal == 0xFFFF) {
                        TODO();//TODO: LOF Cal
                        bcm43xx_radio_set_tx_iq(dev);
@@ -1056,7 +1253,7 @@ static void bcm43xx_phy_initb2(struct bcm43xx_wldev *dev)
        bcm43xx_phy_write(dev, 0x002A, 0x88A3);
        if (phy->radio_ver != 0x2050)
                bcm43xx_phy_write(dev, 0x002A, 0x88C2);
-       bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1);
+       bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
        bcm43xx_phy_init_pctl(dev);
 }
 
@@ -1110,7 +1307,7 @@ static void bcm43xx_phy_initb4(struct bcm43xx_wldev *dev)
        bcm43xx_phy_write(dev, 0x002A, 0x88A3);
        if (phy->radio_ver == 0x2050)
                bcm43xx_phy_write(dev, 0x002A, 0x88C2);
-       bcm43xx_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+       bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
        if (dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI) {
                bcm43xx_calc_nrssi_slope(dev);
                bcm43xx_calc_nrssi_threshold(dev);
@@ -1130,8 +1327,8 @@ static void bcm43xx_phy_initb5(struct bcm43xx_wldev *dev)
                                      bcm43xx_radio_read16(dev, 0x007A)
                                      | 0x0050);
        }
-       if ((bus->board_vendor != SSB_BOARDVENDOR_BCM) &&
-           (bus->board_type != SSB_BOARD_BU4306)) {
+       if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
+           (bus->boardinfo.type != SSB_BOARD_BU4306)) {
                value = 0x2120;
                for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
                        bcm43xx_phy_write(dev, offset, value);
@@ -1217,7 +1414,7 @@ static void bcm43xx_phy_initb5(struct bcm43xx_wldev *dev)
        bcm43xx_phy_write(dev, 0x0032, 0x00CA);
        bcm43xx_phy_write(dev, 0x002A, 0x88A3);
 
-       bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1);
+       bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
 
        if (phy->radio_ver == 0x2050)
                bcm43xx_radio_write16(dev, 0x005D, 0x000D);
@@ -1328,7 +1525,7 @@ static void bcm43xx_phy_initb6(struct bcm43xx_wldev *dev)
        else
                bcm43xx_phy_write(dev, 0x2A, 0x8AC0);
        bcm43xx_phy_write(dev, 0x0038, 0x0668);
-       bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1);
+       bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
        if (phy->radio_rev <= 5) {
                bcm43xx_phy_write(dev, 0x5D,
                                  (bcm43xx_phy_read(dev, 0x5D)
@@ -1391,7 +1588,7 @@ static void bcm43xx_calc_loopback_gain(struct bcm43xx_wldev *dev)
        backup_phy[13] = bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x2B));
        backup_phy[14] = bcm43xx_phy_read(dev, BCM43xx_PHY_PGACTL);
        backup_phy[15] = bcm43xx_phy_read(dev, BCM43xx_PHY_LO_LEAKAGE);
-       backup_bband = phy->bbatt;
+       backup_bband = phy->bbatt.att;
        backup_radio[0] = bcm43xx_radio_read16(dev, 0x52);
        backup_radio[1] = bcm43xx_radio_read16(dev, 0x43);
        backup_radio[2] = bcm43xx_radio_read16(dev, 0x7A);
@@ -1689,23 +1886,20 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_wldev *dev,
                                          u16 baseband_attenuation)
 {
        struct bcm43xx_phy *phy = &dev->phy;
-       u16 value;
 
        if (phy->analog == 0) {
-               value = (bcm43xx_read16(dev, 0x03E6) & 0xFFF0);
-               value |= (baseband_attenuation & 0x000F);
-               bcm43xx_write16(dev, 0x03E6, value);
-               return;
-       }
-
-       if (phy->analog > 1) {
-               value = bcm43xx_phy_read(dev, 0x0060) & ~0x003C;
-               value |= (baseband_attenuation << 2) & 0x003C;
+               bcm43xx_write16(dev, BCM43xx_MMIO_PHY0,
+                               (bcm43xx_read16(dev, BCM43xx_MMIO_PHY0)
+                                & 0xFFF0) | baseband_attenuation);
+       } else if (phy->analog == 1) {
+               bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL,
+                                 (bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL)
+                                  & 0xFFC3) | (baseband_attenuation << 2));
        } else {
-               value = bcm43xx_phy_read(dev, 0x0060) & ~0x0078;
-               value |= (baseband_attenuation << 3) & 0x0078;
+               bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL,
+                                 (bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL)
+                                  & 0xFF87) | (baseband_attenuation << 3));
        }
-       bcm43xx_phy_write(dev, 0x0060, value);
 }
 
 /* http://bcm-specs.sipsolutions.net/EstimatePowerOut
@@ -1738,20 +1932,21 @@ static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_wldev *dev, s8 tssi)
        return dbm;
 }
 
-static void put_attenuation_into_ranges(struct bcm43xx_wldev *dev,
-                                       int *_rfatt, int *_bbatt)
+void bcm43xx_put_attenuation_into_ranges(struct bcm43xx_wldev *dev,
+                                        int *_bbatt, int *_rfatt)
 {
        int rfatt = *_rfatt;
        int bbatt = *_bbatt;
+       struct bcm43xx_txpower_lo_control *lo = dev->phy.lo_control;
 
        /* Get baseband and radio attenuation values into their permitted ranges.
         * Radio attenuation affects power level 4 times as much as baseband. */
 
        /* Range constants */
-       const int rf_min = 0;
-       const int rf_max = 9;
-       const int bb_min = 0;
-       const int bb_max = 11;
+       const int rf_min = lo->rfatt_list.min_val;
+       const int rf_max = lo->rfatt_list.max_val;
+       const int bb_min = lo->bbatt_list.min_val;
+       const int bb_max = lo->bbatt_list.max_val;
 
        while (1) {
                if (rfatt > rf_max &&
@@ -1802,9 +1997,13 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev)
 
        if (phy->cur_idle_tssi == 0)
                return;
-       if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
-           (bus->board_type == SSB_BOARD_BU4306))
+       if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+           (bus->boardinfo.type == SSB_BOARD_BU4306))
                return;
+#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
+       if (phy->manual_txpower_control)
+               return;
+#endif
 
        switch (phy->type) {
        case BCM43xx_PHYTYPE_A: {
@@ -1816,13 +2015,13 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev)
        case BCM43xx_PHYTYPE_B:
        case BCM43xx_PHYTYPE_G: {
                u16 tmp;
-               u16 txpower;
                s8 v0, v1, v2, v3;
                s8 average;
-               u8 max_pwr;
-               s16 desired_pwr, estimated_pwr, pwr_adjust;
-               int radio_att_delta, baseband_att_delta;
-               int radio_attenuation, baseband_attenuation;
+               int max_pwr;
+               int desired_pwr, estimated_pwr, pwr_adjust;
+               int rfatt_delta, bbatt_delta;
+               int rfatt, bbatt;
+               u8 tx_control;
                unsigned long phylock_flags;
 
                tmp = bcm43xx_shm_read16(dev, BCM43xx_SHM_SHARED, 0x0058);
@@ -1858,10 +2057,14 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev)
                estimated_pwr = bcm43xx_phy_estimate_power_out(dev, average);
 
                max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
-
                if ((dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) &&
                    (phy->type == BCM43xx_PHYTYPE_G))
                        max_pwr -= 0x3;
+               if (unlikely(max_pwr <= 0)) {
+                       printk(KERN_ERR PFX "Invalid max-TX-power value in SPROM.\n");
+                       max_pwr = 60; /* fake it */
+                       dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+               }
 
                /*TODO:
                max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
@@ -1871,53 +2074,56 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev)
                desired_pwr = phy->power_level;
                /* Convert the desired_pwr to Q5.2 and limit it. */
                desired_pwr = limit_value((desired_pwr << 2), 0, max_pwr);
+               if (bcm43xx_debug(dev, BCM43xx_DBG_XMITPOWER)) {
+                       dprintk(KERN_DEBUG PFX
+                               "Current TX power output: " Q52_FMT " dBm, "
+                               "Desired TX power output: " Q52_FMT " dBm\n",
+                               Q52_ARG(estimated_pwr), Q52_ARG(desired_pwr));
+               }
 
                pwr_adjust = desired_pwr - estimated_pwr;
-               radio_att_delta = -((pwr_adjust + 7) >> 3);
-               baseband_att_delta = (-(pwr_adjust >> 1)) - (4 * radio_att_delta);
-               if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
+               rfatt_delta = -((pwr_adjust + 7) >> 3);
+               bbatt_delta = (-(pwr_adjust >> 1)) - (4 * rfatt_delta);
+               if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
                        bcm43xx_lo_g_ctl_mark_cur_used(dev);
                        return;
                }
 
                /* Calculate the new attenuation values. */
-               baseband_attenuation = phy->bbatt;
-               baseband_attenuation += baseband_att_delta;
-               radio_attenuation = phy->rfatt;
-               radio_attenuation += radio_att_delta;
-               put_attenuation_into_ranges(dev, &radio_attenuation,
-                                           &baseband_attenuation);
-
-               txpower = phy->txctl1;
+               bbatt = phy->bbatt.att;
+               bbatt += bbatt_delta;
+               rfatt = phy->rfatt.att;
+               rfatt += rfatt_delta;
+
+               bcm43xx_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+               tx_control = phy->tx_control;
                if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
-                       if (radio_attenuation <= 1) {
-                               if (txpower == 0) {
-                                       txpower = 3;
-                                       radio_attenuation += 2;
-                                       baseband_attenuation += 2;
+                       if (rfatt <= 1) {
+                               if (tx_control == 0) {
+                                       tx_control = BCM43xx_TXCTL_PA2DB | BCM43xx_TXCTL_TXMIX;
+                                       rfatt += 2;
+                                       bbatt += 2;
                                } else if (dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) {
-                                       baseband_attenuation += 4 * (radio_attenuation - 2);
-                                       radio_attenuation = 2;
+                                       bbatt += 4 * (rfatt - 2);
+                                       rfatt = 2;
                                }
-                       } else if (radio_attenuation > 4 && txpower != 0) {
-                               txpower = 0;
-                               if (baseband_attenuation < 3) {
-                                       radio_attenuation -= 3;
-                                       baseband_attenuation += 2;
+                       } else if (rfatt > 4 && tx_control) {
+                               tx_control = 0;
+                               if (bbatt < 3) {
+                                       rfatt -= 3;
+                                       bbatt += 2;
                                } else {
-                                       radio_attenuation -= 2;
-                                       baseband_attenuation -= 2;
+                                       rfatt -= 2;
+                                       bbatt -= 2;
                                }
                        }
                }
-               phy->txctl1 = txpower;
-               baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
-               radio_attenuation = limit_value(radio_attenuation, 0, 9);
+               phy->tx_control = tx_control;
+               bcm43xx_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
 
                bcm43xx_phy_lock(dev, phylock_flags);
                bcm43xx_radio_lock(dev);
-               bcm43xx_radio_set_txpower_bg(dev, baseband_attenuation,
-                                            radio_attenuation, txpower);
+               bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
                bcm43xx_lo_g_ctl_mark_cur_used(dev);
                bcm43xx_radio_unlock(dev);
                bcm43xx_phy_unlock(dev, phylock_flags);
@@ -2324,6 +2530,8 @@ static void bcm43xx_synth_pu_workaround(struct bcm43xx_wldev *dev, u8 channel)
 {
        struct bcm43xx_phy *phy = &dev->phy;
 
+       might_sleep();
+
        if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
                /* We do not need the workaround. */
                return;
@@ -2336,7 +2544,7 @@ static void bcm43xx_synth_pu_workaround(struct bcm43xx_wldev *dev, u8 channel)
                bcm43xx_write16(dev, BCM43xx_MMIO_CHANNEL,
                                channel2freq_bg(1));
        }
-       udelay(100);
+       msleep(1);
        bcm43xx_write16(dev, BCM43xx_MMIO_CHANNEL,
                        channel2freq_bg(channel));
 }
@@ -3843,10 +4051,10 @@ void bcm43xx_radio_init2060(struct bcm43xx_wldev *dev)
        bcm43xx_radio_write16(dev, 0x0081, bcm43xx_radio_read16(dev, 0x0081) & ~0x0010);
        bcm43xx_radio_write16(dev, 0x0081, bcm43xx_radio_read16(dev, 0x0081) & ~0x0020);
        bcm43xx_radio_write16(dev, 0x0081, bcm43xx_radio_read16(dev, 0x0081) & ~0x0020);
-       udelay(400);
+       msleep(1); /* delay 400usec */
 
        bcm43xx_radio_write16(dev, 0x0081, (bcm43xx_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
-       udelay(400);
+       msleep(1); /* delay 400usec */
 
        bcm43xx_radio_write16(dev, 0x0005, (bcm43xx_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
        bcm43xx_radio_write16(dev, 0x0085, bcm43xx_radio_read16(dev, 0x0085) & ~0x0010);
@@ -3860,7 +4068,8 @@ void bcm43xx_radio_init2060(struct bcm43xx_wldev *dev)
 
        err = bcm43xx_radio_selectchannel(dev, BCM43xx_DEFAULT_CHANNEL_A, 0);
        assert(err == 0);
-       udelay(1000);
+
+       msleep(1);
 }
 
 static inline
@@ -3995,9 +4204,8 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_wldev *dev,
        }
 
        phy->channel = channel;
-       //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
-       //     that 2000 usecs might suffice.
-       udelay(8000);
+       /* Wait for the radio to tune to the channel and stabilize. */
+       msleep(8);
 
        return 0;
 }
@@ -4069,7 +4277,7 @@ static u16 bcm43xx_get_txgain_dac(u16 txpower)
        return ret;
 }
 
-void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower)
+static void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower)
 {
        struct bcm43xx_phy *phy = &dev->phy;
        u16 pamp, base, dac, t;
@@ -4100,182 +4308,13 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower)
        //TODO: FuncPlaceholder (Adjust BB loft cancel)
 }
 
-void bcm43xx_radio_set_txpower_bg(struct bcm43xx_wldev *dev,
-                                 s16 baseband_attenuation,
-                                 s16 radio_attenuation,
-                                 s16 _tx_magn)
-{
-       struct bcm43xx_phy *phy = &dev->phy;
-       u8 tx_bias = phy->lo_control->tx_bias;
-       u8 tx_magn;
-
-       if (baseband_attenuation < 0)
-               baseband_attenuation = phy->bbatt;
-       if (radio_attenuation < 0)
-               radio_attenuation = phy->rfatt;
-       if (_tx_magn < 0)
-               _tx_magn = phy->lo_control->tx_magn;
-       tx_magn = _tx_magn;
-       phy->bbatt = baseband_attenuation;
-       phy->rfatt = radio_attenuation;
-
-       /* Set Baseband Attenuation on device. */
-       bcm43xx_phy_set_baseband_attenuation(dev, baseband_attenuation);
-
-       /* Set Radio Attenuation on device. */
-       bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED,
-                           0x0064, radio_attenuation);
-       if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
-               bcm43xx_phy_write(dev, 0x0043, radio_attenuation);
-       } else {
-               bcm43xx_radio_write16(dev, 0x0043,
-                                     (bcm43xx_radio_read16(dev, 0x0043)
-                                      & 0xFFF0) | radio_attenuation);
-       }
-
-       if (phy->radio_ver == 0x2050) {//FIXME: It seems like tx_magn and tx_bias are swapped in this func.
-               if (phy->radio_rev < 6) {
-                       bcm43xx_radio_write16(dev, 0x0043,
-                                             (bcm43xx_radio_read16(dev, 0x0043)
-                                              & 0xFF8F) | tx_magn);
-               } else if (phy->radio_rev != 8) {
-                       bcm43xx_radio_write16(dev, 0x0052,
-                                             (bcm43xx_radio_read16(dev, 0x0052)
-                                              & 0xFF8F) | tx_magn);
-               } else {
-                       bcm43xx_radio_write16(dev, 0x52,
-                                             (bcm43xx_radio_read16(dev, 0x52) & 0xFF00) |
-                                             tx_magn | tx_bias);
-               }
-       }
-       if (phy->radio_rev != 8) {
-               bcm43xx_radio_write16(dev, 0x0052,
-                                     (bcm43xx_radio_read16(dev, 0x0052)
-                                      & 0xFFF0) | tx_bias);
-       }
-       if (phy->type == BCM43xx_PHYTYPE_G)
-               bcm43xx_lo_g_adjust(dev);
-}
-
-u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_wldev *dev)
-{
-       struct bcm43xx_phy *phy = &dev->phy;
-
-       if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
-               return 0;
-       return 2;
-}
-
-u16 bcm43xx_default_radio_attenuation(struct bcm43xx_wldev *dev)
-{
-       struct ssb_bus *bus = dev->dev->bus;
-       struct bcm43xx_phy *phy = &dev->phy;
-       u16 att = 0xFFFF;
-
-       if (phy->type == BCM43xx_PHYTYPE_A)
-               return 0x60;
-
-       switch (phy->radio_ver) {
-       case 0x2053:
-               switch (phy->radio_rev) {
-               case 1:
-                       att = 6;
-                       break;
-               }
-               break;
-       case 0x2050:
-               switch (phy->radio_rev) {
-               case 0:
-                       att = 5;
-                       break;
-               case 1:
-                       if (phy->type == BCM43xx_PHYTYPE_G) {
-                               if (bus->board_vendor == SSB_BOARDVENDOR_BCM &&
-                                   bus->board_type == SSB_BOARD_BCM4309G &&
-                                   bus->board_rev >= 30)
-                                       att = 3;
-                               else if (bus->board_vendor == SSB_BOARDVENDOR_BCM &&
-                                        bus->board_type == SSB_BOARD_BU4306)
-                                       att = 3;
-                               else
-                                       att = 1;
-                       } else {
-                               if (bus->board_vendor == SSB_BOARDVENDOR_BCM &&
-                                   bus->board_type == SSB_BOARD_BCM4309G &&
-                                   bus->board_rev >= 30)
-                                       att = 7;
-                               else
-                                       att = 6;
-                       }
-                       break;
-               case 2:
-                       if (phy->type == BCM43xx_PHYTYPE_G) {
-                               if (bus->board_vendor == SSB_BOARDVENDOR_BCM &&
-                                   bus->board_type == SSB_BOARD_BCM4309G &&
-                                   bus->board_rev >= 30)
-                                       att = 3;
-                               else if (bus->board_vendor == SSB_BOARDVENDOR_BCM &&
-                                        bus->board_type == SSB_BOARD_BU4306)
-                                       att = 5;
-                               else if (bus->chip_id == 0x4320)
-                                       att = 4;
-                               else
-                                       att = 3;
-                       } else
-                               att = 6;
-                       break;
-               case 3:
-                       att = 5;
-                       break;
-               case 4:
-               case 5:
-                       att = 1;
-                       break;
-               case 6:
-               case 7:
-                       att = 5;
-                       break;
-               case 8:
-                       att = 0x1A;
-                       break;
-               case 9:
-               default:
-                       att = 5;
-               }
-       }
-       if (bus->board_vendor == SSB_BOARDVENDOR_BCM &&
-           bus->board_type == SSB_BOARD_BCM4309G) {
-               if (bus->board_rev < 0x43)
-                       att = 2;
-               else if (bus->board_rev < 0x51)
-                       att = 3;
-       }
-       if (att == 0xFFFF)
-               att = 5;
-
-       return att;
-}
-
-u16 bcm43xx_default_txctl1(struct bcm43xx_wldev *dev)
-{
-       struct bcm43xx_phy *phy = &dev->phy;
-
-       if (phy->radio_ver != 0x2050)
-               return 0;
-       if (phy->radio_rev == 1)
-               return 3;
-       if (phy->radio_rev < 6)
-               return 2;
-       if (phy->radio_rev == 8)
-               return 1;
-       return 0;
-}
-
 void bcm43xx_radio_turn_on(struct bcm43xx_wldev *dev)
 {
        struct bcm43xx_phy *phy = &dev->phy;
        int err;
 
+       might_sleep();
+
        if (phy->radio_on)
                return;