aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/phy_lp.c
diff options
context:
space:
mode:
authorGábor Stefanik <netrolller.3d@gmail.com>2009-08-13 18:15:17 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:35:51 -0400
commit1e711bee566e26f03e51d5a754e7c8a57e489f9f (patch)
tree963d8d7665d39426b0e2c1f6b6e6d5ca912520c7 /drivers/net/wireless/b43/phy_lp.c
parent588f8377c5470fab611c14ead768f7f9af87da94 (diff)
b43: LP-PHY: Implement channel switching for rev0/1/B2062 radio
-Move pdiv from lpphy_2062_init to struct b43_phy_lp. -Add channel table for the B2062 radio. -Add code for tuning the B2062 radio to channel. -Add error handling to op_switch_channel, and use it for both radios. Rev0/1/B2062 will now hopefully show some signs of life, though it won't work at full performance, as calibration is still missing. Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/phy_lp.c')
-rw-r--r--drivers/net/wireless/b43/phy_lp.c297
1 files changed, 282 insertions, 15 deletions
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 86da8281d929..e010268b9879 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -455,8 +455,9 @@ struct b2062_freqdata {
455/* Initialize the 2062 radio. */ 455/* Initialize the 2062 radio. */
456static void lpphy_2062_init(struct b43_wldev *dev) 456static void lpphy_2062_init(struct b43_wldev *dev)
457{ 457{
458 struct b43_phy_lp *lpphy = dev->phy.lp;
458 struct ssb_bus *bus = dev->dev->bus; 459 struct ssb_bus *bus = dev->dev->bus;
459 u32 crystalfreq, pdiv, tmp, ref; 460 u32 crystalfreq, tmp, ref;
460 unsigned int i; 461 unsigned int i;
461 const struct b2062_freqdata *fd = NULL; 462 const struct b2062_freqdata *fd = NULL;
462 463
@@ -496,22 +497,24 @@ static void lpphy_2062_init(struct b43_wldev *dev)
496 B43_WARN_ON(crystalfreq == 0); 497 B43_WARN_ON(crystalfreq == 0);
497 498
498 if (crystalfreq >= 30000000) { 499 if (crystalfreq >= 30000000) {
499 pdiv = 1; 500 lpphy->pdiv = 1;
500 b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB); 501 b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB);
501 } else { 502 } else {
502 pdiv = 2; 503 lpphy->pdiv = 2;
503 b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4); 504 b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4);
504 } 505 }
505 506
506 tmp = (800000000 * pdiv + crystalfreq) / (32000000 * pdiv); 507 tmp = (800000000 * lpphy->pdiv + crystalfreq) /
508 (32000000 * lpphy->pdiv);
507 tmp = (tmp - 1) & 0xFF; 509 tmp = (tmp - 1) & 0xFF;
508 b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp); 510 b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp);
509 511
510 tmp = (2 * crystalfreq + 1000000 * pdiv) / (2000000 * pdiv); 512 tmp = (2 * crystalfreq + 1000000 * lpphy->pdiv) /
513 (2000000 * lpphy->pdiv);
511 tmp = ((tmp & 0xFF) - 1) & 0xFFFF; 514 tmp = ((tmp & 0xFF) - 1) & 0xFFFF;
512 b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp); 515 b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp);
513 516
514 ref = (1000 * pdiv + 2 * crystalfreq) / (2000 * pdiv); 517 ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv);
515 ref &= 0xFFFF; 518 ref &= 0xFFFF;
516 for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) { 519 for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) {
517 if (ref < freqdata_tab[i].freq) { 520 if (ref < freqdata_tab[i].freq) {
@@ -1431,6 +1434,162 @@ struct b206x_channel {
1431 u8 data[12]; 1434 u8 data[12];
1432}; 1435};
1433 1436
1437static const struct b206x_channel b2062_chantbl[] = {
1438 { .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF,
1439 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1440 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1441 { .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF,
1442 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1443 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1444 { .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF,
1445 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1446 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1447 { .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF,
1448 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1449 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1450 { .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF,
1451 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1452 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1453 { .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF,
1454 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1455 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1456 { .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF,
1457 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1458 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1459 { .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF,
1460 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1461 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1462 { .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF,
1463 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1464 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1465 { .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF,
1466 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1467 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1468 { .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF,
1469 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1470 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1471 { .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF,
1472 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1473 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1474 { .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF,
1475 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1476 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1477 { .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF,
1478 .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
1479 .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
1480 { .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22,
1481 .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
1482 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1483 { .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11,
1484 .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
1485 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1486 { .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11,
1487 .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
1488 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1489 { .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00,
1490 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
1491 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1492 { .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11,
1493 .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
1494 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1495 { .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11,
1496 .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
1497 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1498 { .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11,
1499 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
1500 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1501 { .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00,
1502 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
1503 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1504 { .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00,
1505 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
1506 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1507 { .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00,
1508 .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
1509 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1510 { .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00,
1511 .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77,
1512 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1513 { .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00,
1514 .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77,
1515 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1516 { .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00,
1517 .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77,
1518 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1519 { .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00,
1520 .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
1521 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1522 { .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00,
1523 .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
1524 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1525 { .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00,
1526 .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
1527 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1528 { .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00,
1529 .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77,
1530 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1531 { .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00,
1532 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1533 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1534 { .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00,
1535 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1536 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1537 { .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00,
1538 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1539 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1540 { .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00,
1541 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1542 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1543 { .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00,
1544 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1545 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1546 { .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00,
1547 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1548 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1549 { .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00,
1550 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1551 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1552 { .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00,
1553 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1554 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1555 { .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00,
1556 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1557 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1558 { .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00,
1559 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1560 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1561 { .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00,
1562 .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
1563 .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
1564 { .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77,
1565 .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77,
1566 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
1567 { .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77,
1568 .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
1569 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
1570 { .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66,
1571 .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
1572 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
1573 { .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66,
1574 .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
1575 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
1576 { .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55,
1577 .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77,
1578 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
1579 { .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55,
1580 .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
1581 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
1582 { .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44,
1583 .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
1584 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
1585 { .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44,
1586 .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77,
1587 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1588 { .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44,
1589 .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77,
1590 .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
1591};
1592
1434static const struct b206x_channel b2063_chantbl[] = { 1593static const struct b206x_channel b2063_chantbl[] = {
1435 { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C, 1594 { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C,
1436 .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05, 1595 .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
@@ -1638,10 +1797,110 @@ static const struct b206x_channel b2063_chantbl[] = {
1638 .data[10] = 0x40, .data[11] = 0x00, }, 1797 .data[10] = 0x40, .data[11] = 0x00, },
1639}; 1798};
1640 1799
1641static void lpphy_b2062_tune(struct b43_wldev *dev, 1800static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
1642 unsigned int channel)
1643{ 1801{
1644 //TODO 1802 struct ssb_bus *bus = dev->dev->bus;
1803
1804 b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
1805 udelay(20);
1806 if (bus->chip_id == 0x5354) {
1807 b43_radio_write(dev, B2062_N_COMM1, 4);
1808 b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4);
1809 } else {
1810 b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0);
1811 }
1812 udelay(5);
1813}
1814
1815static void lpphy_b2062_vco_calib(struct b43_wldev *dev)
1816{
1817 b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x42);
1818 b43_phy_write(dev, B2062_S_RFPLL_CTL21, 0x62);
1819 udelay(200);
1820}
1821
1822static int lpphy_b2062_tune(struct b43_wldev *dev,
1823 unsigned int channel)
1824{
1825 struct b43_phy_lp *lpphy = dev->phy.lp;
1826 struct ssb_bus *bus = dev->dev->bus;
1827 static const struct b206x_channel *chandata = NULL;
1828 u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
1829 u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
1830 int i, err = 0;
1831
1832 for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) {
1833 if (b2063_chantbl[i].channel == channel) {
1834 chandata = &b2063_chantbl[i];
1835 break;
1836 }
1837 }
1838
1839 if (B43_WARN_ON(!chandata))
1840 return -EINVAL;
1841
1842 b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04);
1843 b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]);
1844 b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]);
1845 b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]);
1846 b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]);
1847 b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]);
1848 b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]);
1849 b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]);
1850 b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]);
1851 b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]);
1852
1853 tmp1 = crystal_freq / 1000;
1854 tmp2 = lpphy->pdiv * 1000;
1855 b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC);
1856 b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07);
1857 lpphy_b2062_reset_pll_bias(dev);
1858 tmp3 = tmp2 * channel2freq_lp(channel);
1859 if (channel2freq_lp(channel) < 4000)
1860 tmp3 *= 2;
1861 tmp4 = 48 * tmp1;
1862 tmp6 = tmp3 / tmp4;
1863 tmp7 = tmp3 % tmp4;
1864 b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6);
1865 tmp5 = tmp7 * 0x100;
1866 tmp6 = tmp5 / tmp4;
1867 tmp7 = tmp5 % tmp4;
1868 b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6);
1869 tmp5 = tmp7 * 0x100;
1870 tmp6 = tmp5 / tmp4;
1871 tmp7 = tmp5 % tmp4;
1872 b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
1873 tmp8 = b43_phy_read(dev, B2062_S_RFPLL_CTL19);
1874 tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
1875 b43_radio_write(dev, B2062_S_RFPLL_CTL23, tmp9 >> 8);
1876 b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
1877
1878 lpphy_b2062_vco_calib(dev);
1879 if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) {
1880 b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC);
1881 b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0);
1882 lpphy_b2062_reset_pll_bias(dev);
1883 lpphy_b2062_vco_calib(dev);
1884 if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10)
1885 err = -EINVAL;
1886 }
1887
1888 b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04);
1889 return err;
1890}
1891
1892static void lpphy_japan_filter(struct b43_wldev *dev, int channel)
1893{
1894 struct b43_phy_lp *lpphy = dev->phy.lp;
1895 u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
1896
1897 if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
1898 b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
1899 if ((dev->phy.rev == 1) && (lpphy->rc_cap))
1900 lpphy_set_rc_cap(dev);
1901 } else {
1902 b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
1903 }
1645} 1904}
1646 1905
1647static void lpphy_b2063_vco_calib(struct b43_wldev *dev) 1906static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
@@ -1661,8 +1920,8 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
1661 b43_phy_set(dev, B2063_PLL_SP1, 0x40); 1920 b43_phy_set(dev, B2063_PLL_SP1, 0x40);
1662} 1921}
1663 1922
1664static void lpphy_b2063_tune(struct b43_wldev *dev, 1923static int lpphy_b2063_tune(struct b43_wldev *dev,
1665 unsigned int channel) 1924 unsigned int channel)
1666{ 1925{
1667 struct ssb_bus *bus = dev->dev->bus; 1926 struct ssb_bus *bus = dev->dev->bus;
1668 1927
@@ -1681,7 +1940,7 @@ static void lpphy_b2063_tune(struct b43_wldev *dev,
1681 } 1940 }
1682 1941
1683 if (B43_WARN_ON(!chandata)) 1942 if (B43_WARN_ON(!chandata))
1684 return; 1943 return -EINVAL;
1685 1944
1686 b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]); 1945 b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]);
1687 b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]); 1946 b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]);
@@ -1780,18 +2039,26 @@ static void lpphy_b2063_tune(struct b43_wldev *dev,
1780 b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC); 2039 b43_phy_mask(dev, B2063_PLL_SP2, 0xFFFC);
1781 lpphy_b2063_vco_calib(dev); 2040 lpphy_b2063_vco_calib(dev);
1782 b43_radio_write(dev, B2063_COMM15, old_comm15); 2041 b43_radio_write(dev, B2063_COMM15, old_comm15);
2042
2043 return 0;
1783} 2044}
1784 2045
1785static int b43_lpphy_op_switch_channel(struct b43_wldev *dev, 2046static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
1786 unsigned int new_channel) 2047 unsigned int new_channel)
1787{ 2048{
2049 int err;
2050
1788 b43_write16(dev, B43_MMIO_CHANNEL, new_channel); 2051 b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
1789 2052
1790 if (dev->phy.radio_ver == 0x2063) { 2053 if (dev->phy.radio_ver == 0x2063) {
1791 lpphy_b2063_tune(dev, new_channel); 2054 err = lpphy_b2063_tune(dev, new_channel);
2055 if (err)
2056 return err;
1792 } else { 2057 } else {
1793 lpphy_b2062_tune(dev, new_channel); 2058 err = lpphy_b2062_tune(dev, new_channel);
1794 //TODO Japan filter 2059 if (err)
2060 return err;
2061 lpphy_japan_filter(dev, new_channel);
1795 } 2062 }
1796 2063
1797 lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel)); 2064 lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));