]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/bcm43xx/bcm43xx_radio.c
Merge branch 'for-linus' of git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / bcm43xx / bcm43xx_radio.c
index 32beb91b7164a5d27ebb9d23f1546de85610d87a..c605099c9baf9037eb0bc7de3212a1ec14a2f7ec 100644 (file)
@@ -458,7 +458,7 @@ static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x005A, 0x0480);
                bcm43xx_phy_write(bcm, 0x0059, 0x0810);
                bcm43xx_phy_write(bcm, 0x0058, 0x000D);
-               if (phy->rev == 0) {
+               if (phy->analog == 0) {
                        bcm43xx_phy_write(bcm, 0x0003, 0x0122);
                } else {
                        bcm43xx_phy_write(bcm, 0x000A,
@@ -570,9 +570,9 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
                nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027);
                bcm43xx_radio_write16(bcm, 0x007A,
                                      bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
-               if (phy->rev >= 2) {
+               if (phy->analog >= 2) {
                        bcm43xx_write16(bcm, 0x03E6, 0x0040);
-               } else if (phy->rev == 0) {
+               } else if (phy->analog == 0) {
                        bcm43xx_write16(bcm, 0x03E6, 0x0122);
                } else {
                        bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
@@ -596,7 +596,7 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0015, backup[5]);
                bcm43xx_phy_write(bcm, 0x002A, backup[6]);
                bcm43xx_synth_pu_workaround(bcm, radio->channel);
-               if (phy->rev != 0)
+               if (phy->analog != 0)
                        bcm43xx_write16(bcm, 0x03F4, backup[13]);
 
                bcm43xx_phy_write(bcm, 0x0020, backup[7]);
@@ -692,7 +692,7 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm)
 
                bcm43xx_radio_write16(bcm, 0x007A,
                                      bcm43xx_radio_read16(bcm, 0x007A) & 0x007F);
-               if (phy->rev >= 2) {
+               if (phy->analog >= 2) {
                        bcm43xx_phy_write(bcm, 0x0003,
                                          (bcm43xx_phy_read(bcm, 0x0003)
                                           & 0xFF9F) | 0x0040);
@@ -882,10 +882,10 @@ static void _stack_save(u32 *_stackptr, size_t *stackidx,
 {
        u32 *stackptr = &(_stackptr[*stackidx]);
 
-       assert((offset & 0xF000) == 0x0000);
-       assert((id & 0xF0) == 0x00);
+       assert((offset & 0xE000) == 0x0000);
+       assert((id & 0xF8) == 0x00);
        *stackptr = offset;
-       *stackptr |= ((u32)id) << 12;
+       *stackptr |= ((u32)id) << 13;
        *stackptr |= ((u32)value) << 16;
        (*stackidx)++;
        assert(*stackidx < BCM43xx_INTERFSTACK_SIZE);
@@ -896,12 +896,12 @@ static u16 _stack_restore(u32 *stackptr,
 {
        size_t i;
 
-       assert((offset & 0xF000) == 0x0000);
-       assert((id & 0xF0) == 0x00);
+       assert((offset & 0xE000) == 0x0000);
+       assert((id & 0xF8) == 0x00);
        for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) {
-               if ((*stackptr & 0x00000FFF) != offset)
+               if ((*stackptr & 0x00001FFF) != offset)
                        continue;
-               if (((*stackptr & 0x0000F000) >> 12) != id)
+               if (((*stackptr & 0x00007000) >> 13) != id)
                        continue;
                return ((*stackptr & 0xFFFF0000) >> 16);
        }
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
        return ret;
 }
 
+#define LPD(L, P, D)    (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd)
+{
+       struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+       struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+       u16 loop_or = 0;
+       u16 adj_loopback_gain = phy->loopback_gain[0];
+       u8 loop;
+       u16 extern_lna_control;
+
+       if (!phy->connected)
+               return 0;
+       if (!has_loopback_gain(phy)) {
+               if (phy->rev < 7 || !(bcm->sprom.boardflags
+                   & BCM43xx_BFL_EXTLNA)) {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x0FB2;
+                       case LPD(0, 0, 1):
+                               return 0x00B2;
+                       case LPD(1, 0, 1):
+                               return 0x30B2;
+                       case LPD(1, 0, 0):
+                               return 0x30B3;
+                       default:
+                               assert(0);
+                       }
+               } else {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x8FB2;
+                       case LPD(0, 0, 1):
+                               return 0x80B2;
+                       case LPD(1, 0, 1):
+                               return 0x20B2;
+                       case LPD(1, 0, 0):
+                               return 0x20B3;
+                       default:
+                               assert(0);
+                       }
+               }
+       } else {
+               if (radio->revision == 8)
+                       adj_loopback_gain += 0x003E;
+               else
+                       adj_loopback_gain += 0x0026;
+               if (adj_loopback_gain >= 0x46) {
+                       adj_loopback_gain -= 0x46;
+                       extern_lna_control = 0x3000;
+               } else if (adj_loopback_gain >= 0x3A) {
+                       adj_loopback_gain -= 0x3A;
+                       extern_lna_control = 0x2000;
+               } else if (adj_loopback_gain >= 0x2E) {
+                       adj_loopback_gain -= 0x2E;
+                       extern_lna_control = 0x1000;
+               } else {
+                       adj_loopback_gain -= 0x10;
+                       extern_lna_control = 0x0000;
+               }
+               for (loop = 0; loop < 16; loop++) {
+                       u16 tmp = adj_loopback_gain - 6 * loop;
+                       if (tmp < 6)
+                               break;
+               }
+
+               loop_or = (loop << 8) | extern_lna_control;
+               if (phy->rev >= 7 && bcm->sprom.boardflags
+                   & BCM43xx_BFL_EXTLNA) {
+                       if (extern_lna_control)
+                               loop_or |= 0x8000;
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x8F92;
+                       case LPD(0, 0, 1):
+                               return (0x8092 | loop_or);
+                       case LPD(1, 0, 1):
+                               return (0x2092 | loop_or);
+                       case LPD(1, 0, 0):
+                               return (0x2093 | loop_or);
+                       default:
+                               assert(0);
+                       }
+               } else {
+                       switch (lpd) {
+                       case LPD(0, 1, 1):
+                               return 0x0F92;
+                       case LPD(0, 0, 1):
+                       case LPD(1, 0, 1):
+                               return (0x0092 | loop_or);
+                       case LPD(1, 0, 0):
+                               return (0x0093 | loop_or);
+                       default:
+                               assert(0);
+                       }
+               }
+       }
+       return 0;
+}
+
 u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
-       u16 backup[19] = { 0 };
+       u16 backup[21] = { 0 };
        u16 ret;
        u16 i, j;
        u32 tmp1 = 0, tmp2 = 0;
@@ -1373,19 +1472,36 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                        backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
                        backup[9] = bcm43xx_phy_read(bcm, 0x0802);
                        bcm43xx_phy_write(bcm, 0x0814,
-                                         (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+                                         (bcm43xx_phy_read(bcm, 0x0814)
+                                         | 0x0003));
                        bcm43xx_phy_write(bcm, 0x0815,
-                                         (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));    
+                                         (bcm43xx_phy_read(bcm, 0x0815)
+                                         & 0xFFFC));
                        bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
-                                         (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+                                         (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+                                         & 0x7FFF));
                        bcm43xx_phy_write(bcm, 0x0802,
                                          (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
-                       bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
-                       bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+                       if (phy->rev > 1) { /* loopback gain enabled */
+                               backup[19] = bcm43xx_phy_read(bcm, 0x080F);
+                               backup[20] = bcm43xx_phy_read(bcm, 0x0810);
+                               if (phy->rev >= 3)
+                                       bcm43xx_phy_write(bcm, 0x080F, 0xC020);
+                               else
+                                       bcm43xx_phy_write(bcm, 0x080F, 0x8020);
+                               bcm43xx_phy_write(bcm, 0x0810, 0x0000);
+                       }
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
+                       if (phy->rev < 7 || !(bcm->sprom.boardflags
+                           & BCM43xx_BFL_EXTLNA))
+                               bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+                       else
+                               bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
                }
-               bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
        }
+       bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+                       (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
        backup[10] = bcm43xx_phy_read(bcm, 0x0035);
        bcm43xx_phy_write(bcm, 0x0035,
                          (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
@@ -1397,10 +1513,12 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_write16(bcm, 0x03E6, 0x0122);
        } else {
                if (phy->analog >= 2)
-                       bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003)
-                                       & 0xFFBF) | 0x0040);
+                       bcm43xx_phy_write(bcm, 0x0003,
+                                         (bcm43xx_phy_read(bcm, 0x0003)
+                                         & 0xFFBF) | 0x0040);
                bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
+                               (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+                               | 0x2000));
        }
 
        ret = bcm43xx_radio_calibrationvalue(bcm);
@@ -1408,16 +1526,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
        if (phy->type == BCM43xx_PHYTYPE_B)
                bcm43xx_radio_write16(bcm, 0x0078, 0x0026);
 
+       if (phy->connected)
+               bcm43xx_phy_write(bcm, 0x0812,
+                                 bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
        bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
        bcm43xx_phy_write(bcm, 0x002B, 0x1403);
        if (phy->connected)
-               bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+               bcm43xx_phy_write(bcm, 0x0812,
+                                 bcm43xx_get_812_value(bcm, LPD(0, 0, 1)));
        bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
        bcm43xx_radio_write16(bcm, 0x0051,
                              (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
-       bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
-       bcm43xx_radio_write16(bcm, 0x0043,
-                             (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009);
+       if (radio->revision == 8)
+               bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+       else {
+               bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+               bcm43xx_radio_write16(bcm, 0x0043,
+                                     (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
+                                     | 0x0009);
+       }
        bcm43xx_phy_write(bcm, 0x0058, 0x0000);
 
        for (i = 0; i < 16; i++) {
@@ -1425,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0059, 0xC810);
                bcm43xx_phy_write(bcm, 0x0058, 0x000D);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                udelay(10);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
                udelay(10);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 0)));
                bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
-               udelay(10);
+               udelay(20);
                tmp1 += bcm43xx_phy_read(bcm, 0x002D);
                bcm43xx_phy_write(bcm, 0x0058, 0x0000);
                if (phy->connected)
-                       bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                       bcm43xx_phy_write(bcm, 0x0812,
+                                         bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
                bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
        }
 
@@ -1457,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                        bcm43xx_phy_write(bcm, 0x0059, 0xC810);
                        bcm43xx_phy_write(bcm, 0x0058, 0x000D);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                        udelay(10);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
                        udelay(10);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 0)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
                        udelay(10);
                        tmp2 += bcm43xx_phy_read(bcm, 0x002D);
                        bcm43xx_phy_write(bcm, 0x0058, 0x0000);
                        if (phy->connected)
-                               bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+                               bcm43xx_phy_write(bcm, 0x0812,
+                                                 bcm43xx_get_812_value(bcm,
+                                                 LPD(1, 0, 1)));
                        bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
                }
                tmp2++;
@@ -1497,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0030, backup[2]);
                bcm43xx_write16(bcm, 0x03EC, backup[3]);
        } else {
-               bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
-                               (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
                if (phy->connected) {
+                       bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+                                       (bcm43xx_read16(bcm,
+                                       BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
                        bcm43xx_phy_write(bcm, 0x0811, backup[4]);
                        bcm43xx_phy_write(bcm, 0x0812, backup[5]);
                        bcm43xx_phy_write(bcm, 0x0814, backup[6]);
                        bcm43xx_phy_write(bcm, 0x0815, backup[7]);
                        bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
                        bcm43xx_phy_write(bcm, 0x0802, backup[9]);
+                       if (phy->rev > 1) {
+                               bcm43xx_phy_write(bcm, 0x080F, backup[19]);
+                               bcm43xx_phy_write(bcm, 0x0810, backup[20]);
+                       }
                }
        }
        if (i >= 15)
@@ -1579,7 +1723,7 @@ void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm)
        
        for (i = 0; i < 5; i++) {
                for (j = 0; j < 5; j++) {
-                       if (tmp == (data_high[i] << 4 | data_low[j])) {
+                       if (tmp == (data_high[i] | data_low[j])) {
                                bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0);
                                return;
                        }
@@ -2002,7 +2146,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
        } else
                bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
        radio->enabled = 0;
-       dprintk(KERN_INFO PFX "Radio turned off\n");
+       dprintk(KERN_INFO PFX "Radio initialized\n");
        bcm43xx_leds_update(bcm, 0);
 }