rt2x00: Gather channel information in structure
[safe/jmp/linux-2.6] / drivers / net / wireless / b43 / phy.c
index b544f7f..305d4cd 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/types.h>
+#include <linux/bitrev.h>
 
 #include "b43.h"
 #include "phy.h"
@@ -83,25 +84,9 @@ const u8 b43_radio_channel_codes_bg[] = {
        72, 84,
 };
 
+#define bitrev4(tmp) (bitrev8(tmp) >> 4)
 static void b43_phy_initg(struct b43_wldev *dev);
 
-/* Reverse the bits of a 4bit value.
- * Example:  1101 is flipped 1011
- */
-static u16 flip_4bit(u16 value)
-{
-       u16 flipped = 0x0000;
-
-       B43_WARN_ON(value & ~0x000F);
-
-       flipped |= (value & 0x0001) << 3;
-       flipped |= (value & 0x0002) << 1;
-       flipped |= (value & 0x0004) >> 1;
-       flipped |= (value & 0x0008) >> 3;
-
-       return flipped;
-}
-
 static void generate_rfatt_list(struct b43_wldev *dev,
                                struct b43_rfatt_list *list)
 {
@@ -145,8 +130,7 @@ static void generate_rfatt_list(struct b43_wldev *dev,
                {.att = 9,.with_padmix = 1,},
        };
 
-       if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) ||
-           (phy->type == B43_PHYTYPE_G && phy->rev < 6)) {
+       if (!b43_has_hardware_pctl(phy)) {
                /* Software pctl */
                list->list = rfatt_0;
                list->len = ARRAY_SIZE(rfatt_0);
@@ -158,7 +142,7 @@ static void generate_rfatt_list(struct b43_wldev *dev,
                /* Hardware pctl */
                list->list = rfatt_1;
                list->len = ARRAY_SIZE(rfatt_1);
-               list->min_val = 2;
+               list->min_val = 0;
                list->max_val = 14;
                return;
        }
@@ -228,42 +212,30 @@ static void b43_shm_clear_tssi(struct b43_wldev *dev)
        }
 }
 
-void b43_raw_phy_lock(struct b43_wldev *dev)
+/* Lock the PHY registers against concurrent access from the microcode.
+ * This lock is nonrecursive. */
+void b43_phy_lock(struct b43_wldev *dev)
 {
-       struct b43_phy *phy = &dev->phy;
-
-       B43_WARN_ON(!irqs_disabled());
-
-       /* We had a check for MACCTL==0 here, but I think that doesn't
-        * make sense, as MACCTL is never 0 when this is called.
-        *      --mb */
-       B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0);
+#if B43_DEBUG
+       B43_WARN_ON(dev->phy.phy_locked);
+       dev->phy.phy_locked = 1;
+#endif
+       B43_WARN_ON(dev->dev->id.revision < 3);
 
-       if (dev->dev->id.revision < 3) {
-               b43_mac_suspend(dev);
-               spin_lock(&phy->lock);
-       } else {
-               if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-                       b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
-       }
-       phy->locked = 1;
+       if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+               b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
 }
 
-void b43_raw_phy_unlock(struct b43_wldev *dev)
+void b43_phy_unlock(struct b43_wldev *dev)
 {
-       struct b43_phy *phy = &dev->phy;
+#if B43_DEBUG
+       B43_WARN_ON(!dev->phy.phy_locked);
+       dev->phy.phy_locked = 0;
+#endif
+       B43_WARN_ON(dev->dev->id.revision < 3);
 
-       B43_WARN_ON(!irqs_disabled());
-       if (dev->dev->id.revision < 3) {
-               if (phy->locked) {
-                       spin_unlock(&phy->lock);
-                       b43_mac_enable(dev);
-               }
-       } else {
-               if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-                       b43_power_saving_ctl_bits(dev, 0);
-       }
-       phy->locked = 0;
+       if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+               b43_power_saving_ctl_bits(dev, 0);
 }
 
 /* Different PHYs require different register routing flags.
@@ -274,15 +246,30 @@ static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
 {
        if (phy->type == B43_PHYTYPE_A) {
                /* OFDM registers are base-registers for the A-PHY. */
-               offset &= ~B43_PHYROUTE_OFDM_GPHY;
+               if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
+                       offset &= ~B43_PHYROUTE;
+                       offset |= B43_PHYROUTE_BASE;
+               }
        }
-       if (offset & B43_PHYROUTE_EXT_GPHY) {
+
+#if B43_DEBUG
+       if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
                /* Ext-G registers are only available on G-PHYs */
                if (phy->type != B43_PHYTYPE_G) {
-                       b43dbg(dev->wl, "EXT-G PHY access at "
-                              "0x%04X on %u type PHY\n", offset, phy->type);
+                       b43err(dev->wl, "Invalid EXT-G PHY access at "
+                              "0x%04X on PHY type %u\n", offset, phy->type);
+                       dump_stack();
                }
        }
+       if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
+               /* N-BMODE registers are only available on N-PHYs */
+               if (phy->type != B43_PHYTYPE_N) {
+                       b43err(dev->wl, "Invalid N-BMODE PHY access at "
+                              "0x%04X on PHY type %u\n", offset, phy->type);
+                       dump_stack();
+               }
+       }
+#endif /* B43_DEBUG */
 
        return offset;
 }
@@ -302,10 +289,27 @@ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
 
        offset = adjust_phyreg_for_phytype(phy, offset, dev);
        b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
-       mmiowb();
        b43_write16(dev, B43_MMIO_PHY_DATA, val);
 }
 
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+       b43_phy_write(dev, offset,
+                     b43_phy_read(dev, offset) & mask);
+}
+
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+       b43_phy_write(dev, offset,
+                     b43_phy_read(dev, offset) | set);
+}
+
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+       b43_phy_write(dev, offset,
+                     (b43_phy_read(dev, offset) & mask) | set);
+}
+
 /* Adjust the transmission power output (G-PHY) */
 void b43_set_txpower_g(struct b43_wldev *dev,
                       const struct b43_bbatt *bbatt,
@@ -326,6 +330,7 @@ void b43_set_txpower_g(struct b43_wldev *dev,
        /* Save the values for later */
        phy->tx_control = tx_control;
        memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
+       phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
        memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
 
        if (b43_debug(dev, B43_DBG_XMITPOWER)) {
@@ -539,11 +544,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
        u16 tmp;
        u8 rf, bb;
 
-       if (!lo->lo_measured) {
-               b43_phy_write(dev, 0x3FF, 0);
-               return;
-       }
-
        for (rf = 0; rf < lo->rfatt_list.len; rf++) {
                for (bb = 0; bb < lo->bbatt_list.len; bb++) {
                        if (nr_written >= 0x40)
@@ -561,42 +561,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
        }
 }
 
-/* GPHY_DC_Lookup_Table */
-void b43_gphy_dc_lt_init(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
-       struct b43_loctl *loctl0;
-       struct b43_loctl *loctl1;
-       int i;
-       int rf_offset, bb_offset;
-       u16 tmp;
-
-       for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) {
-               rf_offset = i / lo->rfatt_list.len;
-               bb_offset = i % lo->rfatt_list.len;
-
-               loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
-                                         &lo->bbatt_list.list[bb_offset]);
-               if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) {
-                       rf_offset = (i + 1) / lo->rfatt_list.len;
-                       bb_offset = (i + 1) % lo->rfatt_list.len;
-
-                       loctl1 =
-                           b43_get_lo_g_ctl(dev,
-                                            &lo->rfatt_list.list[rf_offset],
-                                            &lo->bbatt_list.list[bb_offset]);
-               } else
-                       loctl1 = loctl0;
-
-               tmp = ((u16) loctl0->q & 0xF);
-               tmp |= ((u16) loctl0->i & 0xF) << 4;
-               tmp |= ((u16) loctl1->q & 0xF) << 8;
-               tmp |= ((u16) loctl1->i & 0xF) << 12;   //FIXME?
-               b43_phy_write(dev, 0x3A0 + (i / 2), tmp);
-       }
-}
-
 static void hardware_pctl_init_aphy(struct b43_wldev *dev)
 {
        //TODO
@@ -623,7 +587,7 @@ static void hardware_pctl_init_gphy(struct b43_wldev *dev)
        b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
                      & 0xFFBF);
 
-       b43_gphy_dc_lt_init(dev);
+       b43_gphy_dc_lt_init(dev, 1);
 }
 
 /* HardwarePowerControl init for A and G PHY */
@@ -840,7 +804,7 @@ static void b43_phy_ww(struct b43_wldev *dev)
        b43_phy_write(dev, B43_PHY_OFDM(0xBB),
                (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
        b43_phy_write(dev, B43_PHY_OFDM61,
-               (b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120);
+               (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120);
        b43_phy_write(dev, B43_PHY_OFDM(0x13),
                (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
        b43_phy_write(dev, B43_PHY_OFDM(0x14),
@@ -911,109 +875,6 @@ static void b43_phy_inita(struct b43_wldev *dev)
        }
 }
 
-static void b43_phy_initb2(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       u16 offset, val;
-
-       b43_write16(dev, 0x03EC, 0x3F22);
-       b43_phy_write(dev, 0x0020, 0x301C);
-       b43_phy_write(dev, 0x0026, 0x0000);
-       b43_phy_write(dev, 0x0030, 0x00C6);
-       b43_phy_write(dev, 0x0088, 0x3E00);
-       val = 0x3C3D;
-       for (offset = 0x0089; offset < 0x00A7; offset++) {
-               b43_phy_write(dev, offset, val);
-               val -= 0x0202;
-       }
-       b43_phy_write(dev, 0x03E4, 0x3000);
-       b43_radio_selectchannel(dev, phy->channel, 0);
-       if (phy->radio_ver != 0x2050) {
-               b43_radio_write16(dev, 0x0075, 0x0080);
-               b43_radio_write16(dev, 0x0079, 0x0081);
-       }
-       b43_radio_write16(dev, 0x0050, 0x0020);
-       b43_radio_write16(dev, 0x0050, 0x0023);
-       if (phy->radio_ver == 0x2050) {
-               b43_radio_write16(dev, 0x0050, 0x0020);
-               b43_radio_write16(dev, 0x005A, 0x0070);
-               b43_radio_write16(dev, 0x005B, 0x007B);
-               b43_radio_write16(dev, 0x005C, 0x00B0);
-               b43_radio_write16(dev, 0x007A, 0x000F);
-               b43_phy_write(dev, 0x0038, 0x0677);
-               b43_radio_init2050(dev);
-       }
-       b43_phy_write(dev, 0x0014, 0x0080);
-       b43_phy_write(dev, 0x0032, 0x00CA);
-       b43_phy_write(dev, 0x0032, 0x00CC);
-       b43_phy_write(dev, 0x0035, 0x07C2);
-       b43_lo_b_measure(dev);
-       b43_phy_write(dev, 0x0026, 0xCC00);
-       if (phy->radio_ver != 0x2050)
-               b43_phy_write(dev, 0x0026, 0xCE00);
-       b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000);
-       b43_phy_write(dev, 0x002A, 0x88A3);
-       if (phy->radio_ver != 0x2050)
-               b43_phy_write(dev, 0x002A, 0x88C2);
-       b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-       b43_phy_init_pctl(dev);
-}
-
-static void b43_phy_initb4(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       u16 offset, val;
-
-       b43_write16(dev, 0x03EC, 0x3F22);
-       b43_phy_write(dev, 0x0020, 0x301C);
-       b43_phy_write(dev, 0x0026, 0x0000);
-       b43_phy_write(dev, 0x0030, 0x00C6);
-       b43_phy_write(dev, 0x0088, 0x3E00);
-       val = 0x3C3D;
-       for (offset = 0x0089; offset < 0x00A7; offset++) {
-               b43_phy_write(dev, offset, val);
-               val -= 0x0202;
-       }
-       b43_phy_write(dev, 0x03E4, 0x3000);
-       b43_radio_selectchannel(dev, phy->channel, 0);
-       if (phy->radio_ver != 0x2050) {
-               b43_radio_write16(dev, 0x0075, 0x0080);
-               b43_radio_write16(dev, 0x0079, 0x0081);
-       }
-       b43_radio_write16(dev, 0x0050, 0x0020);
-       b43_radio_write16(dev, 0x0050, 0x0023);
-       if (phy->radio_ver == 0x2050) {
-               b43_radio_write16(dev, 0x0050, 0x0020);
-               b43_radio_write16(dev, 0x005A, 0x0070);
-               b43_radio_write16(dev, 0x005B, 0x007B);
-               b43_radio_write16(dev, 0x005C, 0x00B0);
-               b43_radio_write16(dev, 0x007A, 0x000F);
-               b43_phy_write(dev, 0x0038, 0x0677);
-               b43_radio_init2050(dev);
-       }
-       b43_phy_write(dev, 0x0014, 0x0080);
-       b43_phy_write(dev, 0x0032, 0x00CA);
-       if (phy->radio_ver == 0x2050)
-               b43_phy_write(dev, 0x0032, 0x00E0);
-       b43_phy_write(dev, 0x0035, 0x07C2);
-
-       b43_lo_b_measure(dev);
-
-       b43_phy_write(dev, 0x0026, 0xCC00);
-       if (phy->radio_ver == 0x2050)
-               b43_phy_write(dev, 0x0026, 0xCE00);
-       b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100);
-       b43_phy_write(dev, 0x002A, 0x88A3);
-       if (phy->radio_ver == 0x2050)
-               b43_phy_write(dev, 0x002A, 0x88C2);
-       b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
-               b43_calc_nrssi_slope(dev);
-               b43_calc_nrssi_threshold(dev);
-       }
-       b43_phy_init_pctl(dev);
-}
-
 static void b43_phy_initb5(struct b43_wldev *dev)
 {
        struct ssb_bus *bus = dev->dev->bus;
@@ -1239,19 +1100,9 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
                              | 0x0004);
        }
-       if (phy->type == B43_PHYTYPE_B) {
-               b43_write16(dev, 0x03E6, 0x8140);
-               b43_phy_write(dev, 0x0016, 0x0410);
-               b43_phy_write(dev, 0x0017, 0x0820);
-               b43_phy_write(dev, 0x0062, 0x0007);
-               b43_radio_init2050(dev);
-               b43_lo_g_measure(dev);
-               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
-                       b43_calc_nrssi_slope(dev);
-                       b43_calc_nrssi_threshold(dev);
-               }
-               b43_phy_init_pctl(dev);
-       } else if (phy->type == B43_PHYTYPE_G)
+       if (phy->type == B43_PHYTYPE_B)
+               B43_WARN_ON(1);
+       else if (phy->type == B43_PHYTYPE_G)
                b43_write16(dev, 0x03E6, 0x0);
 }
 
@@ -1273,14 +1124,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
                backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
        }
-       backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A));
-       backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59));
-       backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58));
-       backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A));
-       backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03));
+       backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+       backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
+       backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
+       backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
+       backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
        backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
        backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
-       backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B));
+       backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
        backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
        backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
        backup_bband = phy->bbatt.att;
@@ -1322,12 +1173,12 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
                       & 0xFFCF) | 0x10);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780);
-       b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-       b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+       b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
+       b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x0A),
-                     b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000);
+       b43_phy_write(dev, B43_PHY_CCK(0x0A),
+                     b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000);
        if (phy->rev != 1) {    /* Not in specs, but needed to prevent PPC machine check */
                b43_phy_write(dev, B43_PHY_ANALOGOVER,
                              b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
@@ -1335,8 +1186,8 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                              b43_phy_read(dev,
                                           B43_PHY_ANALOGOVERVAL) & 0xFFFB);
        }
-       b43_phy_write(dev, B43_PHY_BASE(0x03),
-                     (b43_phy_read(dev, B43_PHY_BASE(0x03))
+       b43_phy_write(dev, B43_PHY_CCK(0x03),
+                     (b43_phy_read(dev, B43_PHY_CCK(0x03))
                       & 0xFF9F) | 0x40);
 
        if (phy->radio_rev == 8) {
@@ -1354,11 +1205,11 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
        b43_phy_write(dev, B43_PHY_LO_CTL, 0);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x2B),
-                     (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+       b43_phy_write(dev, B43_PHY_CCK(0x2B),
+                     (b43_phy_read(dev, B43_PHY_CCK(0x2B))
                       & 0xFFC0) | 0x01);
-       b43_phy_write(dev, B43_PHY_BASE(0x2B),
-                     (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+       b43_phy_write(dev, B43_PHY_CCK(0x2B),
+                     (b43_phy_read(dev, B43_PHY_CCK(0x2B))
                       & 0xC0FF) | 0x800);
 
        b43_phy_write(dev, B43_PHY_RFOVER,
@@ -1429,14 +1280,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
                b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
        }
-       b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]);
-       b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]);
-       b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]);
-       b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]);
-       b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]);
+       b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
+       b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
+       b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
+       b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
        b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
        b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
-       b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]);
+       b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
        b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
 
        b43_phy_set_baseband_attenuation(dev, backup_bband);
@@ -1514,34 +1365,31 @@ static void b43_phy_initg(struct b43_wldev *dev)
                else
                        b43_radio_write16(dev, 0x0078, phy->initval);
        }
-       if (phy->lo_control->tx_bias == 0xFF) {
-               b43_lo_g_measure(dev);
+       b43_lo_g_init(dev);
+       if (has_tx_magnification(phy)) {
+               b43_radio_write16(dev, 0x52,
+                                 (b43_radio_read16(dev, 0x52) & 0xFF00)
+                                 | phy->lo_control->tx_bias | phy->
+                                 lo_control->tx_magn);
        } else {
-               if (has_tx_magnification(phy)) {
-                       b43_radio_write16(dev, 0x52,
-                                         (b43_radio_read16(dev, 0x52) & 0xFF00)
-                                         | phy->lo_control->tx_bias | phy->
-                                         lo_control->tx_magn);
-               } else {
-                       b43_radio_write16(dev, 0x52,
-                                         (b43_radio_read16(dev, 0x52) & 0xFFF0)
-                                         | phy->lo_control->tx_bias);
-               }
-               if (phy->rev >= 6) {
-                       b43_phy_write(dev, B43_PHY_BASE(0x36),
-                                     (b43_phy_read(dev, B43_PHY_BASE(0x36))
-                                      & 0x0FFF) | (phy->lo_control->
-                                                   tx_bias << 12));
-               }
-               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
-                       b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075);
-               else
-                       b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F);
-               if (phy->rev < 2)
-                       b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101);
-               else
-                       b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202);
+               b43_radio_write16(dev, 0x52,
+                                 (b43_radio_read16(dev, 0x52) & 0xFFF0)
+                                 | phy->lo_control->tx_bias);
+       }
+       if (phy->rev >= 6) {
+               b43_phy_write(dev, B43_PHY_CCK(0x36),
+                             (b43_phy_read(dev, B43_PHY_CCK(0x36))
+                              & 0x0FFF) | (phy->lo_control->
+                                           tx_bias << 12));
        }
+       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+               b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
+       else
+               b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
+       if (phy->rev < 2)
+               b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
+       else
+               b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
        if (phy->gmode || phy->rev >= 2) {
                b43_lo_g_adjust(dev);
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
@@ -1552,7 +1400,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
                 * the value 0x7FFFFFFF here. I think that is some weird
                 * compiler optimization in the original driver.
                 * Essentially, what we do here is resetting all NRSSI LT
-                * entries to -32 (see the limit_value() in nrssi_hw_update())
+                * entries to -32 (see the clamp_val() in nrssi_hw_update())
                 */
                b43_nrssi_hw_update(dev, 0xFFFF);       //FIXME?
                b43_calc_nrssi_threshold(dev);
@@ -1614,13 +1462,13 @@ static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
        switch (phy->type) {
        case B43_PHYTYPE_A:
                tmp += 0x80;
-               tmp = limit_value(tmp, 0x00, 0xFF);
+               tmp = clamp_val(tmp, 0x00, 0xFF);
                dbm = phy->tssi2dbm[tmp];
                //TODO: There's a FIXME on the specs
                break;
        case B43_PHYTYPE_B:
        case B43_PHYTYPE_G:
-               tmp = limit_value(tmp, 0x00, 0x3F);
+               tmp = clamp_val(tmp, 0x00, 0x3F);
                dbm = phy->tssi2dbm[tmp];
                break;
        default:
@@ -1679,8 +1527,8 @@ void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
                break;
        }
 
-       *_rfatt = limit_value(rfatt, rf_min, rf_max);
-       *_bbatt = limit_value(bbatt, bb_min, bb_max);
+       *_rfatt = clamp_val(rfatt, rf_min, rf_max);
+       *_bbatt = clamp_val(bbatt, bb_min, bb_max);
 }
 
 /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
@@ -1716,7 +1564,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        int rfatt_delta, bbatt_delta;
                        int rfatt, bbatt;
                        u8 tx_control;
-                       unsigned long phylock_flags;
 
                        tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
                        v0 = (s8) (tmp & 0x00FF);
@@ -1776,7 +1623,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        /* Get desired power (in Q5.2) */
                        desired_pwr = INT_TO_Q52(phy->power_level);
                        /* And limit it. max_pwr already is Q5.2 */
-                       desired_pwr = limit_value(desired_pwr, 0, max_pwr);
+                       desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
                        if (b43_debug(dev, B43_DBG_XMITPOWER)) {
                                b43dbg(dev->wl,
                                       "Current TX power output: " Q52_FMT
@@ -1802,10 +1649,8 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        bbatt_delta -= 4 * rfatt_delta;
 
                        /* So do we finally need to adjust something? */
-                       if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
-                               b43_lo_g_ctl_mark_cur_used(dev);
+                       if ((rfatt_delta == 0) && (bbatt_delta == 0))
                                return;
-                       }
 
                        /* Calculate the new attenuation values. */
                        bbatt = phy->bbatt.att;
@@ -1847,15 +1692,17 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        phy->bbatt.att = bbatt;
 
                        /* Adjust the hardware */
-                       b43_phy_lock(dev, phylock_flags);
+                       b43_phy_lock(dev);
                        b43_radio_lock(dev);
                        b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
                                          phy->tx_control);
-                       b43_lo_g_ctl_mark_cur_used(dev);
                        b43_radio_unlock(dev);
-                       b43_phy_unlock(dev, phylock_flags);
+                       b43_phy_unlock(dev);
                        break;
                }
+       case B43_PHYTYPE_N:
+               b43_nphy_xmitpower(dev);
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -1886,7 +1733,7 @@ static inline
                f = q;
                i++;
        } while (delta >= 2);
-       entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+       entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
        return 0;
 }
 
@@ -1985,24 +1832,6 @@ int b43_phy_init(struct b43_wldev *dev)
                else
                        unsupported = 1;
                break;
-       case B43_PHYTYPE_B:
-               switch (phy->rev) {
-               case 2:
-                       b43_phy_initb2(dev);
-                       break;
-               case 4:
-                       b43_phy_initb4(dev);
-                       break;
-               case 5:
-                       b43_phy_initb5(dev);
-                       break;
-               case 6:
-                       b43_phy_initb6(dev);
-                       break;
-               default:
-                       unsupported = 1;
-               }
-               break;
        case B43_PHYTYPE_G:
                b43_phy_initg(dev);
                break;
@@ -2021,7 +1850,7 @@ int b43_phy_init(struct b43_wldev *dev)
 void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
 {
        struct b43_phy *phy = &dev->phy;
-       u32 hf;
+       u64 hf;
        u16 tmp;
        int autodiv = 0;
 
@@ -2115,6 +1944,9 @@ void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
                    << B43_PHY_BBANDCFG_RXANT_SHIFT;
                b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
                break;
+       case B43_PHYTYPE_N:
+               b43_nphy_set_rxantenna(dev, antenna);
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -2144,6 +1976,7 @@ void b43_radio_lock(struct b43_wldev *dev)
        u32 macctl;
 
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
        macctl |= B43_MACCTL_RADIOLOCK;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
        /* Commit the write and wait for the device
@@ -2160,6 +1993,7 @@ void b43_radio_unlock(struct b43_wldev *dev)
        b43_read16(dev, B43_MMIO_PHY_VER);
        /* unlock */
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
        macctl &= ~B43_MACCTL_RADIOLOCK;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
 }
@@ -2168,9 +2002,12 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 {
        struct b43_phy *phy = &dev->phy;
 
+       /* Offset 1 is a 32-bit register. */
+       B43_WARN_ON(offset == 1);
+
        switch (phy->type) {
        case B43_PHYTYPE_A:
-               offset |= 0x0040;
+               offset |= 0x40;
                break;
        case B43_PHYTYPE_B:
                if (phy->radio_ver == 0x2053) {
@@ -2186,6 +2023,14 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
        case B43_PHYTYPE_G:
                offset |= 0x80;
                break;
+       case B43_PHYTYPE_N:
+               offset |= 0x100;
+               break;
+       case B43_PHYTYPE_LP:
+               /* No adjustment required. */
+               break;
+       default:
+               B43_WARN_ON(1);
        }
 
        b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
@@ -2194,11 +2039,31 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 
 void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
 {
+       /* Offset 1 is a 32-bit register. */
+       B43_WARN_ON(offset == 1);
+
        b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
-       mmiowb();
        b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
 }
 
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+       b43_radio_write16(dev, offset,
+                         b43_radio_read16(dev, offset) & mask);
+}
+
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+       b43_radio_write16(dev, offset,
+                         b43_radio_read16(dev, offset) | set);
+}
+
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+       b43_radio_write16(dev, offset,
+                         (b43_radio_read16(dev, offset) & mask) | set);
+}
+
 static void b43_set_all_gains(struct b43_wldev *dev,
                              s16 first, s16 second, s16 third)
 {
@@ -2328,12 +2193,11 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev)
        u8 ret[13];
        unsigned int channel = phy->channel;
        unsigned int i, j, start, end;
-       unsigned long phylock_flags;
 
        if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
                return 0;
 
-       b43_phy_lock(dev, phylock_flags);
+       b43_phy_lock(dev);
        b43_radio_lock(dev);
        b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
        b43_phy_write(dev, B43_PHY_G_CRS,
@@ -2362,7 +2226,7 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev)
                        ret[j] = 1;
        }
        b43_radio_unlock(dev);
-       b43_phy_unlock(dev, phylock_flags);
+       b43_phy_unlock(dev);
 
        return ret[channel - 1];
 }
@@ -2395,7 +2259,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
        for (i = 0; i < 64; i++) {
                tmp = b43_nrssi_hw_read(dev, i);
                tmp -= val;
-               tmp = limit_value(tmp, -32, 31);
+               tmp = clamp_val(tmp, -32, 31);
                b43_nrssi_hw_write(dev, i, tmp);
        }
 }
@@ -2412,7 +2276,7 @@ void b43_nrssi_mem_update(struct b43_wldev *dev)
                tmp = (i - delta) * phy->nrssislope;
                tmp /= 0x10000;
                tmp += 0x3A;
-               tmp = limit_value(tmp, 0, 0x3F);
+               tmp = clamp_val(tmp, 0, 0x3F);
                phy->nrssi_lt[i] = tmp;
        }
 }
@@ -2849,7 +2713,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                        } else
                                threshold = phy->nrssi[1] - 5;
 
-                       threshold = limit_value(threshold, 0, 0x3E);
+                       threshold = clamp_val(threshold, 0, 0x3E);
                        b43_phy_read(dev, 0x0020);      /* dummy read */
                        b43_phy_write(dev, 0x0020,
                                      (((u16) threshold) << 8) | 0x001C);
@@ -2900,7 +2764,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                        else
                                a += 32;
                        a = a >> 6;
-                       a = limit_value(a, -31, 31);
+                       a = clamp_val(a, -31, 31);
 
                        b = b * (phy->nrssi[1] - phy->nrssi[0]);
                        b += (phy->nrssi[0] << 6);
@@ -2909,7 +2773,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                        else
                                b += 32;
                        b = b >> 6;
-                       b = limit_value(b, -31, 31);
+                       b = clamp_val(b, -31, 31);
 
                        tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
                        tmp_u16 |= ((u32) b & 0x0000003F);
@@ -3012,13 +2876,13 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
                }
                radio_stacksave(0x0078);
                tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
-               flipped = flip_4bit(tmp);
+               B43_WARN_ON(tmp > 15);
+               flipped = bitrev4(tmp);
                if (flipped < 10 && flipped >= 8)
                        flipped = 7;
                else if (flipped >= 10)
                        flipped -= 3;
-               flipped = flip_4bit(flipped);
-               flipped = (flipped << 1) | 0x0020;
+               flipped = (bitrev4(flipped) << 1) | 0x0020;
                b43_radio_write16(dev, 0x0078, flipped);
 
                b43_calc_nrssi_threshold(dev);
@@ -3480,10 +3344,10 @@ struct init2050_saved_values {
        u16 radio_52;
        /* PHY registers */
        u16 phy_pgactl;
-       u16 phy_base_5A;
-       u16 phy_base_59;
-       u16 phy_base_58;
-       u16 phy_base_30;
+       u16 phy_cck_5A;
+       u16 phy_cck_59;
+       u16 phy_cck_58;
+       u16 phy_cck_30;
        u16 phy_rfover;
        u16 phy_rfoverval;
        u16 phy_analogover;
@@ -3511,15 +3375,15 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
        sav.radio_51 = b43_radio_read16(dev, 0x51);
        sav.radio_52 = b43_radio_read16(dev, 0x52);
        sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
-       sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A));
-       sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59));
-       sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58));
+       sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+       sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
+       sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
 
        if (phy->type == B43_PHYTYPE_B) {
-               sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+               sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
                sav.reg_3EC = b43_read16(dev, 0x3EC);
 
-               b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF);
+               b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
                b43_write16(dev, 0x3EC, 0x3F3F);
        } else if (phy->gmode || phy->rev >= 2) {
                sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
@@ -3570,8 +3434,8 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                b43_write16(dev, 0x03E6, 0x0122);
        } else {
                if (phy->analog >= 2) {
-                       b43_phy_write(dev, B43_PHY_BASE(0x03),
-                                     (b43_phy_read(dev, B43_PHY_BASE(0x03))
+                       b43_phy_write(dev, B43_PHY_CCK(0x03),
+                                     (b43_phy_read(dev, B43_PHY_CCK(0x03))
                                       & 0xFFBF) | 0x40);
                }
                b43_write16(dev, B43_MMIO_CHANNEL_EXT,
@@ -3588,7 +3452,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                                                   LPD(0, 1, 1)));
        }
        b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
-       b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403);
+       b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
        if (phy->gmode || phy->rev >= 2) {
                b43_phy_write(dev, B43_PHY_RFOVERVAL,
                              radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
@@ -3604,12 +3468,12 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
                                              & 0xFFF0) | 0x0009);
        }
-       b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 
        for (i = 0; i < 16; i++) {
-               b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480);
-               b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-               b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+               b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
+               b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+               b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
                if (phy->gmode || phy->rev >= 2) {
                        b43_phy_write(dev, B43_PHY_RFOVERVAL,
                                      radio2050_rfover_val(dev,
@@ -3635,7 +3499,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
                udelay(20);
                tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-               b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+               b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
                if (phy->gmode || phy->rev >= 2) {
                        b43_phy_write(dev, B43_PHY_RFOVERVAL,
                                      radio2050_rfover_val(dev,
@@ -3646,18 +3510,18 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
        }
        udelay(10);
 
-       b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
        tmp1++;
        tmp1 >>= 9;
 
        for (i = 0; i < 16; i++) {
-               radio78 = ((flip_4bit(i) << 1) | 0x20);
+               radio78 = (bitrev4(i) << 1) | 0x0020;
                b43_radio_write16(dev, 0x78, radio78);
                udelay(10);
                for (j = 0; j < 16; j++) {
-                       b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80);
-                       b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-                       b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+                       b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
+                       b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+                       b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
                        if (phy->gmode || phy->rev >= 2) {
                                b43_phy_write(dev, B43_PHY_RFOVERVAL,
                                              radio2050_rfover_val(dev,
@@ -3686,7 +3550,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
                        b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
                        udelay(10);
                        tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-                       b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+                       b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
                        if (phy->gmode || phy->rev >= 2) {
                                b43_phy_write(dev, B43_PHY_RFOVERVAL,
                                              radio2050_rfover_val(dev,
@@ -3707,16 +3571,16 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
        b43_radio_write16(dev, 0x51, sav.radio_51);
        b43_radio_write16(dev, 0x52, sav.radio_52);
        b43_radio_write16(dev, 0x43, sav.radio_43);
-       b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A);
-       b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59);
-       b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58);
+       b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
+       b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
+       b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
        b43_write16(dev, 0x3E6, sav.reg_3E6);
        if (phy->analog != 0)
                b43_write16(dev, 0x3F4, sav.reg_3F4);
        b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
        b43_synth_pu_workaround(dev, phy->channel);
        if (phy->type == B43_PHYTYPE_B) {
-               b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30);
+               b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
                b43_write16(dev, 0x3EC, sav.reg_3EC);
        } else if (phy->gmode) {
                b43_write16(dev, B43_MMIO_PHY_RADIO,
@@ -3826,7 +3690,8 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
        struct b43_phy *phy = &dev->phy;
        u16 r8, tmp;
        u16 freq;
-       u16 channelcookie;
+       u16 channelcookie, savedcookie;
+       int err = 0;
 
        if (channel == 0xFF) {
                switch (phy->type) {
@@ -3837,6 +3702,10 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
                case B43_PHYTYPE_G:
                        channel = B43_DEFAULT_CHANNEL_BG;
                        break;
+               case B43_PHYTYPE_N:
+                       //FIXME check if we are on 2.4GHz or 5GHz and set a default channel.
+                       channel = 1;
+                       break;
                default:
                        B43_WARN_ON(1);
                }
@@ -3846,13 +3715,18 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
         * firmware from sending ghost packets.
         */
        channelcookie = channel;
-       if (phy->type == B43_PHYTYPE_A)
+       if (0 /*FIXME on 5Ghz */)
                channelcookie |= 0x100;
+       //FIXME set 40Mhz flag if required
+       savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
 
-       if (phy->type == B43_PHYTYPE_A) {
-               if (channel > 200)
-                       return -EINVAL;
+       switch (phy->type) {
+       case B43_PHYTYPE_A:
+               if (channel > 200) {
+                       err = -EINVAL;
+                       goto out;
+               }
                freq = channel2freq_a(channel);
 
                r8 = b43_radio_read16(dev, 0x0008);
@@ -3899,9 +3773,12 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
                b43_radio_set_tx_iq(dev);
                //TODO: TSSI2dbm workaround
                b43_phy_xmitpower(dev); //FIXME correct?
-       } else {
-               if ((channel < 1) || (channel > 14))
-                       return -EINVAL;
+               break;
+       case B43_PHYTYPE_G:
+               if ((channel < 1) || (channel > 14)) {
+                       err = -EINVAL;
+                       goto out;
+               }
 
                if (synthetic_pu_workaround)
                        b43_synth_pu_workaround(dev, channel);
@@ -3924,13 +3801,25 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
                                    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
                                    & 0xF7BF);
                }
+               break;
+       case B43_PHYTYPE_N:
+               err = b43_nphy_selectchannel(dev, channel);
+               if (err)
+                       goto out;
+               break;
+       default:
+               B43_WARN_ON(1);
        }
 
        phy->channel = channel;
        /* Wait for the radio to tune to the channel and stabilize. */
        msleep(8);
-
-       return 0;
+out:
+       if (err) {
+               b43_shm_write16(dev, B43_SHM_SHARED,
+                               B43_SHM_SH_CHAN, savedcookie);
+       }
+       return err;
 }
 
 void b43_radio_turn_on(struct b43_wldev *dev)
@@ -3970,6 +3859,9 @@ void b43_radio_turn_on(struct b43_wldev *dev)
                err |= b43_radio_selectchannel(dev, channel, 0);
                B43_WARN_ON(err);
                break;
+       case B43_PHYTYPE_N:
+               b43_nphy_radio_turn_on(dev);
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -3983,13 +3875,17 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force)
        if (!phy->radio_on && !force)
                return;
 
-       if (phy->type == B43_PHYTYPE_A) {
+       switch (phy->type) {
+       case B43_PHYTYPE_N:
+               b43_nphy_radio_turn_off(dev);
+               break;
+       case B43_PHYTYPE_A:
                b43_radio_write16(dev, 0x0004, 0x00FF);
                b43_radio_write16(dev, 0x0005, 0x00FB);
                b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
                b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
-       }
-       if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
+               break;
+       case B43_PHYTYPE_G: {
                u16 rfover, rfoverval;
 
                rfover = b43_phy_read(dev, B43_PHY_RFOVER);
@@ -4001,7 +3897,10 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force)
                }
                b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
                b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
-       } else
-               b43_phy_write(dev, 0x0015, 0xAA00);
+               break;
+       }
+       default:
+               B43_WARN_ON(1);
+       }
        phy->radio_on = 0;
 }