Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / drivers / net / wireless / b43 / main.c
index 6356fbc..a92cde8 100644 (file)
@@ -113,6 +113,17 @@ static int b43_modparam_pio = B43_PIO_DEFAULT;
 module_param_named(pio, b43_modparam_pio, int, 0644);
 MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
 
+#ifdef CONFIG_B43_BCMA
+static const struct bcma_device_id b43_bcma_tbl[] = {
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS),
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS),
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS),
+       BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl);
+#endif
+
+#ifdef CONFIG_B43_SSB
 static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
@@ -126,8 +137,8 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
        SSB_DEVTABLE_END
 };
-
 MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
+#endif
 
 /* Channel and ratetables are shared for all devices.
  * They can't be const, because ieee80211 puts some precalculated
@@ -548,7 +559,7 @@ void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
 {
        u32 low, high;
 
-       B43_WARN_ON(dev->sdev->id.revision < 3);
+       B43_WARN_ON(dev->dev->core_rev < 3);
 
        /* The hardware guarantees us an atomic read, if we
         * read the low register first. */
@@ -586,7 +597,7 @@ static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
 {
        u32 low, high;
 
-       B43_WARN_ON(dev->sdev->id.revision < 3);
+       B43_WARN_ON(dev->dev->core_rev < 3);
 
        low = tsf;
        high = (tsf >> 32);
@@ -714,7 +725,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
                b43_ram_write(dev, i * 4, buffer[i]);
 
        b43_write16(dev, 0x0568, 0x0000);
-       if (dev->sdev->id.revision < 11)
+       if (dev->dev->core_rev < 11)
                b43_write16(dev, 0x07C0, 0x0000);
        else
                b43_write16(dev, 0x07C0, 0x0100);
@@ -1132,7 +1143,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
        /* Commit write */
        b43_read32(dev, B43_MMIO_MACCTL);
-       if (awake && dev->sdev->id.revision >= 5) {
+       if (awake && dev->dev->core_rev >= 5) {
                /* Wait for the microcode to wake up. */
                for (i = 0; i < 100; i++) {
                        ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
@@ -1144,35 +1155,85 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        }
 }
 
-static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+#ifdef CONFIG_B43_BCMA
+static void b43_bcma_phy_reset(struct b43_wldev *dev)
+{
+       u32 flags;
+
+       /* Put PHY into reset */
+       flags = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+       flags |= B43_BCMA_IOCTL_PHY_RESET;
+       flags |= B43_BCMA_IOCTL_PHY_BW_20MHZ; /* Make 20 MHz def */
+       bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
+       udelay(2);
+
+       /* Take PHY out of reset */
+       flags = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+       flags &= ~B43_BCMA_IOCTL_PHY_RESET;
+       flags |= BCMA_IOCTL_FGC;
+       bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
+       udelay(1);
+
+       /* Do not force clock anymore */
+       flags = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+       flags &= ~BCMA_IOCTL_FGC;
+       bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
+       udelay(1);
+}
+
+static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
+{
+       b43_device_enable(dev, B43_BCMA_IOCTL_PHY_CLKEN);
+       bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
+       b43_bcma_phy_reset(dev);
+       bcma_core_pll_ctl(dev->dev->bdev, 0x300, 0x3000000, true);
+}
+#endif
+
+static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, bool gmode)
 {
+       struct ssb_device *sdev = dev->dev->sdev;
        u32 tmslow;
+       u32 flags = 0;
 
+       if (gmode)
+               flags |= B43_TMSLOW_GMODE;
        flags |= B43_TMSLOW_PHYCLKEN;
        flags |= B43_TMSLOW_PHYRESET;
        if (dev->phy.type == B43_PHYTYPE_N)
                flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
-       ssb_device_enable(dev->sdev, flags);
+       b43_device_enable(dev, flags);
        msleep(2);              /* Wait for the PLL to turn on. */
 
        /* Now take the PHY out of Reset again */
-       tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
+       tmslow = ssb_read32(sdev, SSB_TMSLOW);
        tmslow |= SSB_TMSLOW_FGC;
        tmslow &= ~B43_TMSLOW_PHYRESET;
-       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
-       ssb_read32(dev->sdev, SSB_TMSLOW);      /* flush */
+       ssb_write32(sdev, SSB_TMSLOW, tmslow);
+       ssb_read32(sdev, SSB_TMSLOW);   /* flush */
        msleep(1);
        tmslow &= ~SSB_TMSLOW_FGC;
-       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
-       ssb_read32(dev->sdev, SSB_TMSLOW);      /* flush */
+       ssb_write32(sdev, SSB_TMSLOW, tmslow);
+       ssb_read32(sdev, SSB_TMSLOW);   /* flush */
        msleep(1);
 }
 
-void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode)
 {
        u32 macctl;
 
-       b43_ssb_wireless_core_reset(dev, flags);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               b43_bcma_wireless_core_reset(dev, gmode);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               b43_ssb_wireless_core_reset(dev, gmode);
+               break;
+#endif
+       }
 
        /* Turn Analog ON, but only if we already know the PHY-type.
         * This protects against very early setup where we don't know the
@@ -1183,7 +1244,7 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
 
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
        macctl &= ~B43_MACCTL_GMODE;
-       if (flags & B43_TMSLOW_GMODE)
+       if (gmode)
                macctl |= B43_MACCTL_GMODE;
        macctl |= B43_MACCTL_IHR_ENABLED;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
@@ -1221,7 +1282,7 @@ static void drain_txstatus_queue(struct b43_wldev *dev)
 {
        u32 dummy;
 
-       if (dev->sdev->id.revision < 5)
+       if (dev->dev->core_rev < 5)
                return;
        /* Read all entries from the microcode TXstatus FIFO
         * and throw them away.
@@ -1427,9 +1488,9 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
 
        /* Get the mask of available antennas. */
        if (dev->phy.gmode)
-               antenna_mask = dev->sdev->bus->sprom.ant_available_bg;
+               antenna_mask = dev->dev->bus_sprom->ant_available_bg;
        else
-               antenna_mask = dev->sdev->bus->sprom.ant_available_a;
+               antenna_mask = dev->dev->bus_sprom->ant_available_a;
 
        if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
                /* This antenna is not available. Fall back to default. */
@@ -1644,7 +1705,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
        if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
-               if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
+               if (b43_bus_host_is_sdio(dev->dev)) {
                        /* wl->mutex is enough. */
                        b43_do_beacon_update_trigger_work(dev);
                        mmiowb();
@@ -1689,7 +1750,7 @@ static void b43_update_templates(struct b43_wl *wl)
 static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 {
        b43_time_lock(dev);
-       if (dev->sdev->id.revision >= 3) {
+       if (dev->dev->core_rev >= 3) {
                b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
                b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
        } else {
@@ -1923,7 +1984,7 @@ static irqreturn_t b43_do_interrupt(struct b43_wldev *dev)
                return IRQ_NONE;
        reason &= dev->irq_mask;
        if (!reason)
-               return IRQ_HANDLED;
+               return IRQ_NONE;
 
        dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
            & 0x0001DC00;
@@ -2063,7 +2124,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
                B43_WARN_ON(1);
                return -ENOSYS;
        }
-       err = request_firmware(&blob, ctx->fwname, ctx->dev->sdev->dev);
+       err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
        if (err == -ENOENT) {
                snprintf(ctx->errors[ctx->req_type],
                         sizeof(ctx->errors[ctx->req_type]),
@@ -2113,26 +2174,48 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
 {
        struct b43_wldev *dev = ctx->dev;
        struct b43_firmware *fw = &ctx->dev->fw;
-       const u8 rev = ctx->dev->sdev->id.revision;
+       const u8 rev = ctx->dev->dev->core_rev;
        const char *filename;
        u32 tmshigh;
        int err;
 
+       /* Files for HT and LCN were found by trying one by one */
+
        /* Get microcode */
-       if ((rev >= 5) && (rev <= 10))
+       if ((rev >= 5) && (rev <= 10)) {
                filename = "ucode5";
-       else if ((rev >= 11) && (rev <= 12))
+       } else if ((rev >= 11) && (rev <= 12)) {
                filename = "ucode11";
-       else if (rev == 13)
+       } else if (rev == 13) {
                filename = "ucode13";
-       else if (rev == 14)
+       } else if (rev == 14) {
                filename = "ucode14";
-       else if (rev == 15)
+       } else if (rev == 15) {
                filename = "ucode15";
-       else if ((rev >= 16) && (rev <= 20))
-               filename = "ucode16_mimo";
-       else
-               goto err_no_ucode;
+       } else {
+               switch (dev->phy.type) {
+               case B43_PHYTYPE_N:
+                       if (rev >= 16)
+                               filename = "ucode16_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               case B43_PHYTYPE_HT:
+                       if (rev == 29)
+                               filename = "ucode29_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               case B43_PHYTYPE_LCN:
+                       if (rev == 24)
+                               filename = "ucode24_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               default:
+                       goto err_no_ucode;
+               }
+       }
        err = b43_do_request_fw(ctx, filename, &fw->ucode);
        if (err)
                goto err_load;
@@ -2157,7 +2240,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
                if ((rev >= 5) && (rev <= 10)) {
-                       tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
+                       tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
                        if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
                                filename = "a0g1initvals5";
                        else
@@ -2191,6 +2274,18 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
                else
                        goto err_no_initvals;
                break;
+       case B43_PHYTYPE_HT:
+               if (rev == 29)
+                       filename = "ht0initvals29";
+               else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_LCN:
+               if (rev == 24)
+                       filename = "lcn0initvals24";
+               else
+                       goto err_no_initvals;
+               break;
        default:
                goto err_no_initvals;
        }
@@ -2202,7 +2297,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
                if ((rev >= 5) && (rev <= 10)) {
-                       tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
+                       tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
                        if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
                                filename = "a0g1bsinitvals5";
                        else
@@ -2238,6 +2333,18 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
                else
                        goto err_no_initvals;
                break;
+       case B43_PHYTYPE_HT:
+               if (rev == 29)
+                       filename = "ht0bsinitvals29";
+               else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_LCN:
+               if (rev == 24)
+                       filename = "lcn0bsinitvals24";
+               else
+                       goto err_no_initvals;
+               break;
        default:
                goto err_no_initvals;
        }
@@ -2448,7 +2555,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 
        snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
                        dev->fw.rev, dev->fw.patch);
-       wiphy->hw_version = dev->sdev->id.coreid;
+       wiphy->hw_version = dev->dev->core_id;
 
        if (b43_is_old_txhdr_format(dev)) {
                /* We're over the deadline, but we keep support for old fw
@@ -2566,7 +2673,7 @@ out:
  */
 static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
 
 #ifdef CONFIG_SSB_DRIVER_PCICORE
        return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
@@ -2588,7 +2695,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
 
        mask = 0x0000001F;
        set = 0x0000000F;
-       if (dev->sdev->bus->chip_id == 0x4301) {
+       if (dev->dev->chip_id == 0x4301) {
                mask |= 0x0060;
                set |= 0x0060;
        }
@@ -2599,21 +2706,34 @@ static int b43_gpio_init(struct b43_wldev *dev)
                mask |= 0x0180;
                set |= 0x0180;
        }
-       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
+       if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0200);
                mask |= 0x0200;
                set |= 0x0200;
        }
-       if (dev->sdev->id.revision >= 2)
+       if (dev->dev->core_rev >= 2)
                mask |= 0x0010; /* FIXME: This is redundant. */
 
-       gpiodev = b43_ssb_gpio_dev(dev);
-       if (gpiodev)
-               ssb_write32(gpiodev, B43_GPIO_CONTROL,
-                           (ssb_read32(gpiodev, B43_GPIO_CONTROL)
-                            & mask) | set);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
+                               (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc,
+                                       BCMA_CC_GPIOCTL) & mask) | set);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               gpiodev = b43_ssb_gpio_dev(dev);
+               if (gpiodev)
+                       ssb_write32(gpiodev, B43_GPIO_CONTROL,
+                                   (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+                                   & mask) | set);
+               break;
+#endif
+       }
 
        return 0;
 }
@@ -2623,9 +2743,21 @@ static void b43_gpio_cleanup(struct b43_wldev *dev)
 {
        struct ssb_device *gpiodev;
 
-       gpiodev = b43_ssb_gpio_dev(dev);
-       if (gpiodev)
-               ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
+                               0);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               gpiodev = b43_ssb_gpio_dev(dev);
+               if (gpiodev)
+                       ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+               break;
+#endif
+       }
 }
 
 /* http://bcm-specs.sipsolutions.net/EnableMac */
@@ -2697,12 +2829,30 @@ out:
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
 void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
 {
-       u32 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
-       if (on)
-               tmslow |= B43_TMSLOW_MACPHYCLKEN;
-       else
-               tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
-       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+       u32 tmp;
+
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+               if (on)
+                       tmp |= B43_BCMA_IOCTL_MACPHYCLKEN;
+               else
+                       tmp &= ~B43_BCMA_IOCTL_MACPHYCLKEN;
+               bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               if (on)
+                       tmp |= B43_TMSLOW_MACPHYCLKEN;
+               else
+                       tmp &= ~B43_TMSLOW_MACPHYCLKEN;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               break;
+#endif
+       }
 }
 
 static void b43_adjust_opmode(struct b43_wldev *dev)
@@ -2741,15 +2891,15 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
        /* Workaround: On old hardware the HW-MAC-address-filter
         * doesn't work properly, so always run promisc in filter
         * it in software. */
-       if (dev->sdev->id.revision <= 4)
+       if (dev->dev->core_rev <= 4)
                ctl |= B43_MACCTL_PROMISC;
 
        b43_write32(dev, B43_MMIO_MACCTL, ctl);
 
        cfp_pretbtt = 2;
        if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
-               if (dev->sdev->bus->chip_id == 0x4306 &&
-                   dev->sdev->bus->chip_rev == 3)
+               if (dev->dev->chip_id == 0x4306 &&
+                   dev->dev->chip_rev == 3)
                        cfp_pretbtt = 100;
                else
                        cfp_pretbtt = 50;
@@ -2907,7 +3057,7 @@ static int b43_chip_init(struct b43_wldev *dev)
                b43_write16(dev, 0x005E, value16);
        }
        b43_write32(dev, 0x0100, 0x01000000);
-       if (dev->sdev->id.revision < 5)
+       if (dev->dev->core_rev < 5)
                b43_write32(dev, 0x010C, 0x01000000);
 
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
@@ -2922,7 +3072,7 @@ static int b43_chip_init(struct b43_wldev *dev)
        /* Initially set the wireless operation mode. */
        b43_adjust_opmode(dev);
 
-       if (dev->sdev->id.revision < 3) {
+       if (dev->dev->core_rev < 3) {
                b43_write16(dev, 0x060E, 0x0000);
                b43_write16(dev, 0x0610, 0x8000);
                b43_write16(dev, 0x0604, 0x0000);
@@ -2941,8 +3091,20 @@ static int b43_chip_init(struct b43_wldev *dev)
 
        b43_mac_phy_clock_set(dev, true);
 
-       b43_write16(dev, B43_MMIO_POWERUP_DELAY,
-                   dev->sdev->bus->chipco.fast_pwrup_delay);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               /* FIXME: 0xE74 is quite common, but should be read from CC */
+               b43_write16(dev, B43_MMIO_POWERUP_DELAY, 0xE74);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               b43_write16(dev, B43_MMIO_POWERUP_DELAY,
+                           dev->dev->sdev->bus->chipco.fast_pwrup_delay);
+               break;
+#endif
+       }
 
        err = 0;
        b43dbg(dev->wl, "Chip initialized\n");
@@ -3105,7 +3267,7 @@ static int b43_validate_chipaccess(struct b43_wldev *dev)
        b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
        b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
 
-       if ((dev->sdev->id.revision >= 3) && (dev->sdev->id.revision <= 10)) {
+       if ((dev->dev->core_rev >= 3) && (dev->dev->core_rev <= 10)) {
                /* The 32bit register shadows the two 16bit registers
                 * with update sideeffects. Validate this. */
                b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
@@ -3458,21 +3620,33 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 
 static void b43_put_phy_into_reset(struct b43_wldev *dev)
 {
-       struct ssb_device *sdev = dev->sdev;
-       u32 tmslow;
+       u32 tmp;
 
-       tmslow = ssb_read32(sdev, SSB_TMSLOW);
-       tmslow &= ~B43_TMSLOW_GMODE;
-       tmslow |= B43_TMSLOW_PHYRESET;
-       tmslow |= SSB_TMSLOW_FGC;
-       ssb_write32(sdev, SSB_TMSLOW, tmslow);
-       msleep(1);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               b43err(dev->wl,
+                      "Putting PHY into reset not supported on BCMA\n");
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               tmp &= ~B43_TMSLOW_GMODE;
+               tmp |= B43_TMSLOW_PHYRESET;
+               tmp |= SSB_TMSLOW_FGC;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               msleep(1);
+
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               tmp &= ~SSB_TMSLOW_FGC;
+               tmp |= B43_TMSLOW_PHYRESET;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               msleep(1);
 
-       tmslow = ssb_read32(sdev, SSB_TMSLOW);
-       tmslow &= ~SSB_TMSLOW_FGC;
-       tmslow |= B43_TMSLOW_PHYRESET;
-       ssb_write32(sdev, SSB_TMSLOW, tmslow);
-       msleep(1);
+               break;
+#endif
+       }
 }
 
 static const char *band_to_string(enum ieee80211_band band)
@@ -3954,7 +4128,7 @@ redo:
 
        /* Disable interrupts on the device. */
        b43_set_status(dev, B43_STAT_INITIALIZED);
-       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (b43_bus_host_is_sdio(dev->dev)) {
                /* wl->mutex is locked. That is enough. */
                b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
                b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
@@ -3967,11 +4141,11 @@ redo:
        /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
        orig_dev = dev;
        mutex_unlock(&wl->mutex);
-       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (b43_bus_host_is_sdio(dev->dev)) {
                b43_sdio_free_irq(dev);
        } else {
-               synchronize_irq(dev->sdev->irq);
-               free_irq(dev->sdev->irq, dev);
+               synchronize_irq(dev->dev->irq);
+               free_irq(dev->dev->irq, dev);
        }
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
@@ -4004,19 +4178,19 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
        B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
 
        drain_txstatus_queue(dev);
-       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (b43_bus_host_is_sdio(dev->dev)) {
                err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
                if (err) {
                        b43err(dev->wl, "Cannot request SDIO IRQ\n");
                        goto out;
                }
        } else {
-               err = request_threaded_irq(dev->sdev->irq, b43_interrupt_handler,
+               err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
                                           b43_interrupt_thread_handler,
                                           IRQF_SHARED, KBUILD_MODNAME, dev);
                if (err) {
                        b43err(dev->wl, "Cannot request IRQ-%d\n",
-                              dev->sdev->irq);
+                              dev->dev->irq);
                        goto out;
                }
        }
@@ -4082,10 +4256,22 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                if (phy_rev > 2)
                        unsupported = 1;
                break;
+#endif
+#ifdef CONFIG_B43_PHY_HT
+       case B43_PHYTYPE_HT:
+               if (phy_rev > 1)
+                       unsupported = 1;
+               break;
+#endif
+#ifdef CONFIG_B43_PHY_LCN
+       case B43_PHYTYPE_LCN:
+               if (phy_rev > 1)
+                       unsupported = 1;
+               break;
 #endif
        default:
                unsupported = 1;
-       };
+       }
        if (unsupported) {
                b43err(dev->wl, "FOUND UNSUPPORTED PHY "
                       "(Analog %u, Type %u, Revision %u)\n",
@@ -4096,22 +4282,42 @@ static int b43_phy_versioning(struct b43_wldev *dev)
               analog_type, phy_type, phy_rev);
 
        /* Get RADIO versioning */
-       if (dev->sdev->bus->chip_id == 0x4317) {
-               if (dev->sdev->bus->chip_rev == 0)
-                       tmp = 0x3205017F;
-               else if (dev->sdev->bus->chip_rev == 1)
-                       tmp = 0x4205017F;
-               else
-                       tmp = 0x5205017F;
+       if (dev->dev->core_rev >= 24) {
+               u16 radio24[3];
+
+               for (tmp = 0; tmp < 3; tmp++) {
+                       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+                       radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
+               }
+
+               /* Broadcom uses "id" for our "ver" and has separated "ver" */
+               /* radio_ver = (radio24[0] & 0xF0) >> 4; */
+
+               radio_manuf = 0x17F;
+               radio_ver = (radio24[2] << 8) | radio24[1];
+               radio_rev = (radio24[0] & 0xF);
        } else {
-               b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-               tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
-               b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-               tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
-       }
-       radio_manuf = (tmp & 0x00000FFF);
-       radio_ver = (tmp & 0x0FFFF000) >> 12;
-       radio_rev = (tmp & 0xF0000000) >> 28;
+               if (dev->dev->chip_id == 0x4317) {
+                       if (dev->dev->chip_rev == 0)
+                               tmp = 0x3205017F;
+                       else if (dev->dev->chip_rev == 1)
+                               tmp = 0x4205017F;
+                       else
+                               tmp = 0x5205017F;
+               } else {
+                       b43_write16(dev, B43_MMIO_RADIO_CONTROL,
+                                   B43_RADIOCTL_ID);
+                       tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+                       b43_write16(dev, B43_MMIO_RADIO_CONTROL,
+                                   B43_RADIOCTL_ID);
+                       tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH)
+                               << 16;
+               }
+               radio_manuf = (tmp & 0x00000FFF);
+               radio_ver = (tmp & 0x0FFFF000) >> 12;
+               radio_rev = (tmp & 0xF0000000) >> 28;
+       }
+
        if (radio_manuf != 0x17F /* Broadcom */)
                unsupported = 1;
        switch (phy_type) {
@@ -4139,6 +4345,14 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                if (radio_ver != 0x2062 && radio_ver != 0x2063)
                        unsupported = 1;
                break;
+       case B43_PHYTYPE_HT:
+               if (radio_ver != 0x2059)
+                       unsupported = 1;
+               break;
+       case B43_PHYTYPE_LCN:
+               if (radio_ver != 0x2064)
+                       unsupported = 1;
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -4204,7 +4418,7 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 
 static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
 {
-       struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        u64 hf;
 
        if (!modparam_btcoex)
@@ -4231,16 +4445,21 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
 
 static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus;
        u32 tmp;
 
+       if (dev->dev->bus_type != B43_BUS_SSB)
+               return;
+
+       bus = dev->dev->sdev->bus;
+
        if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) ||
            (bus->chip_id == 0x4312)) {
-               tmp = ssb_read32(dev->sdev, SSB_IMCFGLO);
+               tmp = ssb_read32(dev->dev->sdev, SSB_IMCFGLO);
                tmp &= ~SSB_IMCFGLO_REQTO;
                tmp &= ~SSB_IMCFGLO_SERTO;
                tmp |= 0x3;
-               ssb_write32(dev->sdev, SSB_IMCFGLO, tmp);
+               ssb_write32(dev->dev->sdev, SSB_IMCFGLO, tmp);
                ssb_commit_settings(bus);
        }
 }
@@ -4310,36 +4529,45 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
                dev->wl->current_beacon = NULL;
        }
 
-       ssb_device_disable(dev->sdev, 0);
-       ssb_bus_may_powerdown(dev->sdev->bus);
+       b43_device_disable(dev, 0);
+       b43_bus_may_powerdown(dev);
 }
 
 /* Initialize a wireless core */
 static int b43_wireless_core_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
-       struct ssb_sprom *sprom = &bus->sprom;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy *phy = &dev->phy;
        int err;
        u64 hf;
-       u32 tmp;
 
        B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
 
-       err = ssb_bus_powerup(bus, 0);
+       err = b43_bus_powerup(dev, 0);
        if (err)
                goto out;
-       if (!ssb_device_is_enabled(dev->sdev)) {
-               tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
-               b43_wireless_core_reset(dev, tmp);
-       }
+       if (!b43_device_is_enabled(dev))
+               b43_wireless_core_reset(dev, phy->gmode);
 
        /* Reset all data structures. */
        setup_struct_wldev_for_init(dev);
        phy->ops->prepare_structs(dev);
 
        /* Enable IRQ routing to this device. */
-       ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->sdev);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci,
+                                     dev->dev->bdev, true);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               ssb_pcicore_dev_irqvecs_enable(&dev->dev->sdev->bus->pcicore,
+                                              dev->dev->sdev);
+               break;
+#endif
+       }
 
        b43_imcfglo_timeouts_workaround(dev);
        b43_bluetooth_coext_disable(dev);
@@ -4352,7 +4580,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        if (err)
                goto err_busdown;
        b43_shm_write16(dev, B43_SHM_SHARED,
-                       B43_SHM_SH_WLCOREREV, dev->sdev->id.revision);
+                       B43_SHM_SH_WLCOREREV, dev->dev->core_rev);
        hf = b43_hf_read(dev);
        if (phy->type == B43_PHYTYPE_G) {
                hf |= B43_HF_SYMW;
@@ -4370,8 +4598,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
                hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
 #ifdef CONFIG_SSB_DRIVER_PCICORE
-       if ((bus->bustype == SSB_BUSTYPE_PCI) &&
-           (bus->pcicore.dev->id.revision <= 10))
+       if (dev->dev->bus_type == B43_BUS_SSB &&
+           dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
+           dev->dev->sdev->bus->pcicore.dev->id.revision <= 10)
                hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */
 #endif
        hf &= ~B43_HF_SKCFPUP;
@@ -4399,8 +4628,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-       if ((dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
-           (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) ||
+       if (b43_bus_host_is_pcmcia(dev->dev) ||
+           b43_bus_host_is_sdio(dev->dev) ||
            dev->use_pio) {
                dev->__using_pio_transfers = 1;
                err = b43_pio_init(dev);
@@ -4414,7 +4643,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        b43_set_synth_pu_delay(dev, 1);
        b43_bluetooth_coext_enable(dev);
 
-       ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
+       b43_bus_powerup(dev, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
 
@@ -4431,7 +4660,7 @@ out:
 err_chip_exit:
        b43_chip_exit(dev);
 err_busdown:
-       ssb_bus_may_powerdown(bus);
+       b43_bus_may_powerdown(dev);
        B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
        return err;
 }
@@ -4737,11 +4966,10 @@ static void b43_wireless_core_detach(struct b43_wldev *dev)
 static int b43_wireless_core_attach(struct b43_wldev *dev)
 {
        struct b43_wl *wl = dev->wl;
-       struct ssb_bus *bus = dev->sdev->bus;
-       struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
+       struct pci_dev *pdev = NULL;
        int err;
-       bool have_2ghz_phy = 0, have_5ghz_phy = 0;
        u32 tmp;
+       bool have_2ghz_phy = 0, have_5ghz_phy = 0;
 
        /* Do NOT do any device initialization here.
         * Do it in wireless_core_init() instead.
@@ -4750,25 +4978,42 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
         * that in core_init(), too.
         */
 
-       err = ssb_bus_powerup(bus, 0);
+#ifdef CONFIG_B43_SSB
+       if (dev->dev->bus_type == B43_BUS_SSB &&
+           dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI)
+               pdev = dev->dev->sdev->bus->host_pci;
+#endif
+
+       err = b43_bus_powerup(dev, 0);
        if (err) {
                b43err(wl, "Bus powerup failed\n");
                goto out;
        }
-       /* Get the PHY type. */
-       if (dev->sdev->id.revision >= 5) {
-               u32 tmshigh;
 
-               tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
-               have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
-               have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
-       } else
-               B43_WARN_ON(1);
+       /* Get the PHY type. */
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               tmp = bcma_aread32(dev->dev->bdev, BCMA_IOST);
+               have_2ghz_phy = !!(tmp & B43_BCMA_IOST_2G_PHY);
+               have_5ghz_phy = !!(tmp & B43_BCMA_IOST_5G_PHY);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               if (dev->dev->core_rev >= 5) {
+                       tmp = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
+                       have_2ghz_phy = !!(tmp & B43_TMSHIGH_HAVE_2GHZ_PHY);
+                       have_5ghz_phy = !!(tmp & B43_TMSHIGH_HAVE_5GHZ_PHY);
+               } else
+                       B43_WARN_ON(1);
+               break;
+#endif
+       }
 
        dev->phy.gmode = have_2ghz_phy;
        dev->phy.radio_on = 1;
-       tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
-       b43_wireless_core_reset(dev, tmp);
+       b43_wireless_core_reset(dev, dev->phy.gmode);
 
        err = b43_phy_versioning(dev);
        if (err)
@@ -4790,6 +5035,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 #endif
                case B43_PHYTYPE_G:
                case B43_PHYTYPE_N:
+               case B43_PHYTYPE_HT:
+               case B43_PHYTYPE_LCN:
                        have_2ghz_phy = 1;
                        break;
                default:
@@ -4816,8 +5063,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                goto err_powerdown;
 
        dev->phy.gmode = have_2ghz_phy;
-       tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
-       b43_wireless_core_reset(dev, tmp);
+       b43_wireless_core_reset(dev, dev->phy.gmode);
 
        err = b43_validate_chipaccess(dev);
        if (err)
@@ -4832,8 +5078,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        INIT_WORK(&dev->restart_work, b43_chip_reset);
 
        dev->phy.ops->switch_analog(dev, 0);
-       ssb_device_disable(dev->sdev, 0);
-       ssb_bus_may_powerdown(bus);
+       b43_device_disable(dev, 0);
+       b43_bus_may_powerdown(dev);
 
 out:
        return err;
@@ -4841,7 +5087,7 @@ out:
 err_phy_free:
        b43_phy_free(dev);
 err_powerdown:
-       ssb_bus_may_powerdown(bus);
+       b43_bus_may_powerdown(dev);
        return err;
 }
 
@@ -4853,13 +5099,13 @@ static void b43_one_core_detach(struct b43_bus_dev *dev)
        /* Do not cancel ieee80211-workqueue based work here.
         * See comment in b43_remove(). */
 
-       wldev = ssb_get_drvdata(dev->sdev);
+       wldev = b43_bus_get_wldev(dev);
        wl = wldev->wl;
        b43_debugfs_remove_device(wldev);
        b43_wireless_core_detach(wldev);
        list_del(&wldev->list);
        wl->nr_devs--;
-       ssb_set_drvdata(dev->sdev, NULL);
+       b43_bus_set_wldev(dev, NULL);
        kfree(wldev);
 }
 
@@ -4874,7 +5120,6 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl)
 
        wldev->use_pio = b43_modparam_pio;
        wldev->dev = dev;
-       wldev->sdev = dev->sdev; /* TODO: Remove when not needed */
        wldev->wl = wl;
        b43_set_status(wldev, B43_STAT_UNINIT);
        wldev->bad_frames_preempt = modparam_bad_frames_preempt;
@@ -4886,7 +5131,7 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl)
 
        list_add(&wldev->list, &wl->devlist);
        wl->nr_devs++;
-       ssb_set_drvdata(dev->sdev, wldev);
+       b43_bus_set_wldev(dev, wldev);
        b43_debugfs_add_device(wldev);
 
       out:
@@ -4935,11 +5180,12 @@ static void b43_wireless_exit(struct b43_bus_dev *dev, struct b43_wl *wl)
        ieee80211_free_hw(hw);
 }
 
-static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
+static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
 {
-       struct ssb_sprom *sprom = &dev->bus->sprom;
+       struct ssb_sprom *sprom = dev->bus_sprom;
        struct ieee80211_hw *hw;
        struct b43_wl *wl;
+       char chip_name[6];
 
        hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
        if (!hw) {
@@ -4978,11 +5224,81 @@ static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
        INIT_WORK(&wl->tx_work, b43_tx_work);
        skb_queue_head_init(&wl->tx_queue);
 
-       b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
-               dev->bus->chip_id, dev->id.revision);
+       snprintf(chip_name, ARRAY_SIZE(chip_name),
+                (dev->chip_id > 0x9999) ? "%d" : "%04X", dev->chip_id);
+       b43info(wl, "Broadcom %s WLAN found (core revision %u)\n", chip_name,
+               dev->core_rev);
        return wl;
 }
 
+#ifdef CONFIG_B43_BCMA
+static int b43_bcma_probe(struct bcma_device *core)
+{
+       struct b43_bus_dev *dev;
+       struct b43_wl *wl;
+       int err;
+
+       dev = b43_bus_dev_bcma_init(core);
+       if (!dev)
+               return -ENODEV;
+
+       wl = b43_wireless_init(dev);
+       if (IS_ERR(wl)) {
+               err = PTR_ERR(wl);
+               goto bcma_out;
+       }
+
+       err = b43_one_core_attach(dev, wl);
+       if (err)
+               goto bcma_err_wireless_exit;
+
+       err = ieee80211_register_hw(wl->hw);
+       if (err)
+               goto bcma_err_one_core_detach;
+       b43_leds_register(wl->current_dev);
+
+bcma_out:
+       return err;
+
+bcma_err_one_core_detach:
+       b43_one_core_detach(dev);
+bcma_err_wireless_exit:
+       ieee80211_free_hw(wl->hw);
+       return err;
+}
+
+static void b43_bcma_remove(struct bcma_device *core)
+{
+       struct b43_wldev *wldev = bcma_get_drvdata(core);
+       struct b43_wl *wl = wldev->wl;
+
+       /* We must cancel any work here before unregistering from ieee80211,
+        * as the ieee80211 unreg will destroy the workqueue. */
+       cancel_work_sync(&wldev->restart_work);
+
+       /* Restore the queues count before unregistering, because firmware detect
+        * might have modified it. Restoring is important, so the networking
+        * stack can properly free resources. */
+       wl->hw->queues = wl->mac80211_initially_registered_queues;
+       b43_leds_stop(wldev);
+       ieee80211_unregister_hw(wl->hw);
+
+       b43_one_core_detach(wldev->dev);
+
+       b43_leds_unregister(wl);
+
+       ieee80211_free_hw(wl->hw);
+}
+
+static struct bcma_driver b43_bcma_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = b43_bcma_tbl,
+       .probe          = b43_bcma_probe,
+       .remove         = b43_bcma_remove,
+};
+#endif
+
+#ifdef CONFIG_B43_SSB
 static
 int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
 {
@@ -4992,13 +5308,15 @@ int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
        int first = 0;
 
        dev = b43_bus_dev_ssb_init(sdev);
+       if (!dev)
+               return -ENOMEM;
 
        wl = ssb_get_devtypedata(sdev);
        if (!wl) {
                /* Probing the first core. Must setup common struct b43_wl */
                first = 1;
                b43_sprom_fixup(sdev->bus);
-               wl = b43_wireless_init(sdev);
+               wl = b43_wireless_init(dev);
                if (IS_ERR(wl)) {
                        err = PTR_ERR(wl);
                        goto out;
@@ -5032,6 +5350,7 @@ static void b43_ssb_remove(struct ssb_device *sdev)
 {
        struct b43_wl *wl = ssb_get_devtypedata(sdev);
        struct b43_wldev *wldev = ssb_get_drvdata(sdev);
+       struct b43_bus_dev *dev = wldev->dev;
 
        /* We must cancel any work here before unregistering from ieee80211,
         * as the ieee80211 unreg will destroy the workqueue. */
@@ -5047,17 +5366,25 @@ static void b43_ssb_remove(struct ssb_device *sdev)
                ieee80211_unregister_hw(wl->hw);
        }
 
-       b43_one_core_detach(wldev->dev);
+       b43_one_core_detach(dev);
 
        if (list_empty(&wl->devlist)) {
                b43_leds_unregister(wl);
                /* Last core on the chip unregistered.
                 * We can destroy common struct b43_wl.
                 */
-               b43_wireless_exit(wldev->dev, wl);
+               b43_wireless_exit(dev, wl);
        }
 }
 
+static struct ssb_driver b43_ssb_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = b43_ssb_tbl,
+       .probe          = b43_ssb_probe,
+       .remove         = b43_ssb_remove,
+};
+#endif /* CONFIG_B43_SSB */
+
 /* Perform a hardware reset. This can be called from any context. */
 void b43_controller_restart(struct b43_wldev *dev, const char *reason)
 {
@@ -5068,13 +5395,6 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
        ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
 }
 
-static struct ssb_driver b43_ssb_driver = {
-       .name           = KBUILD_MODNAME,
-       .id_table       = b43_ssb_tbl,
-       .probe          = b43_ssb_probe,
-       .remove         = b43_ssb_remove,
-};
-
 static void b43_print_driverinfo(void)
 {
        const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
@@ -5113,14 +5433,27 @@ static int __init b43_init(void)
        err = b43_sdio_init();
        if (err)
                goto err_pcmcia_exit;
-       err = ssb_driver_register(&b43_ssb_driver);
+#ifdef CONFIG_B43_BCMA
+       err = bcma_driver_register(&b43_bcma_driver);
        if (err)
                goto err_sdio_exit;
+#endif
+#ifdef CONFIG_B43_SSB
+       err = ssb_driver_register(&b43_ssb_driver);
+       if (err)
+               goto err_bcma_driver_exit;
+#endif
        b43_print_driverinfo();
 
        return err;
 
+#ifdef CONFIG_B43_SSB
+err_bcma_driver_exit:
+#endif
+#ifdef CONFIG_B43_BCMA
+       bcma_driver_unregister(&b43_bcma_driver);
 err_sdio_exit:
+#endif
        b43_sdio_exit();
 err_pcmcia_exit:
        b43_pcmcia_exit();
@@ -5131,7 +5464,12 @@ err_dfs_exit:
 
 static void __exit b43_exit(void)
 {
+#ifdef CONFIG_B43_SSB
        ssb_driver_unregister(&b43_ssb_driver);
+#endif
+#ifdef CONFIG_B43_BCMA
+       bcma_driver_unregister(&b43_bcma_driver);
+#endif
        b43_sdio_exit();
        b43_pcmcia_exit();
        b43_debugfs_exit();