Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[pandora-kernel.git] / drivers / net / wireless / b43 / phy.c
index 67b8a92..de024dc 100644 (file)
@@ -228,42 +228,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.
@@ -320,6 +308,24 @@ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
        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,
@@ -854,7 +860,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),
@@ -1730,7 +1736,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);
@@ -1861,15 +1866,18 @@ 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);
        }
@@ -2035,7 +2043,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;
 
@@ -2129,6 +2137,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);
        }
@@ -2158,6 +2169,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
@@ -2174,6 +2186,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);
 }
@@ -2226,6 +2239,24 @@ void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
        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)
 {
@@ -2355,12 +2386,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,
@@ -2389,7 +2419,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];
 }
@@ -3853,7 +3883,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) {
@@ -3864,6 +3895,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);
                }
@@ -3873,13 +3908,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);
@@ -3926,9 +3966,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);
@@ -3951,13 +3994,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)
@@ -3997,6 +4052,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);
        }
@@ -4010,13 +4068,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);
@@ -4028,7 +4090,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;
 }