1ca47d344SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
258619b14SKalle Valo /*
358619b14SKalle Valo
458619b14SKalle Valo Broadcom B43 wireless driver
558619b14SKalle Valo IEEE 802.11a/g LP-PHY driver
658619b14SKalle Valo
758619b14SKalle Valo Copyright (c) 2008-2009 Michael Buesch <m@bues.ch>
858619b14SKalle Valo Copyright (c) 2009 Gábor Stefanik <netrolller.3d@gmail.com>
958619b14SKalle Valo
1058619b14SKalle Valo
1158619b14SKalle Valo */
1258619b14SKalle Valo
13d5a43355SPriit Laes #include <linux/cordic.h>
1458619b14SKalle Valo #include <linux/slab.h>
1558619b14SKalle Valo
1658619b14SKalle Valo #include "b43.h"
1758619b14SKalle Valo #include "main.h"
1858619b14SKalle Valo #include "phy_lp.h"
1958619b14SKalle Valo #include "phy_common.h"
2058619b14SKalle Valo #include "tables_lpphy.h"
2158619b14SKalle Valo
2258619b14SKalle Valo
channel2freq_lp(u8 channel)2358619b14SKalle Valo static inline u16 channel2freq_lp(u8 channel)
2458619b14SKalle Valo {
2558619b14SKalle Valo if (channel < 14)
2658619b14SKalle Valo return (2407 + 5 * channel);
2758619b14SKalle Valo else if (channel == 14)
2858619b14SKalle Valo return 2484;
2958619b14SKalle Valo else if (channel < 184)
3058619b14SKalle Valo return (5000 + 5 * channel);
3158619b14SKalle Valo else
3258619b14SKalle Valo return (4000 + 5 * channel);
3358619b14SKalle Valo }
3458619b14SKalle Valo
b43_lpphy_op_get_default_chan(struct b43_wldev * dev)3558619b14SKalle Valo static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
3658619b14SKalle Valo {
3757fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
3858619b14SKalle Valo return 1;
3958619b14SKalle Valo return 36;
4058619b14SKalle Valo }
4158619b14SKalle Valo
b43_lpphy_op_allocate(struct b43_wldev * dev)4258619b14SKalle Valo static int b43_lpphy_op_allocate(struct b43_wldev *dev)
4358619b14SKalle Valo {
4458619b14SKalle Valo struct b43_phy_lp *lpphy;
4558619b14SKalle Valo
4658619b14SKalle Valo lpphy = kzalloc(sizeof(*lpphy), GFP_KERNEL);
4758619b14SKalle Valo if (!lpphy)
4858619b14SKalle Valo return -ENOMEM;
4958619b14SKalle Valo dev->phy.lp = lpphy;
5058619b14SKalle Valo
5158619b14SKalle Valo return 0;
5258619b14SKalle Valo }
5358619b14SKalle Valo
b43_lpphy_op_prepare_structs(struct b43_wldev * dev)5458619b14SKalle Valo static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
5558619b14SKalle Valo {
5658619b14SKalle Valo struct b43_phy *phy = &dev->phy;
5758619b14SKalle Valo struct b43_phy_lp *lpphy = phy->lp;
5858619b14SKalle Valo
5958619b14SKalle Valo memset(lpphy, 0, sizeof(*lpphy));
6058619b14SKalle Valo lpphy->antenna = B43_ANTENNA_DEFAULT;
6158619b14SKalle Valo
6258619b14SKalle Valo //TODO
6358619b14SKalle Valo }
6458619b14SKalle Valo
b43_lpphy_op_free(struct b43_wldev * dev)6558619b14SKalle Valo static void b43_lpphy_op_free(struct b43_wldev *dev)
6658619b14SKalle Valo {
6758619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
6858619b14SKalle Valo
6958619b14SKalle Valo kfree(lpphy);
7058619b14SKalle Valo dev->phy.lp = NULL;
7158619b14SKalle Valo }
7258619b14SKalle Valo
73*2d96c1edSAlexander A. Klimov /* https://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */
lpphy_read_band_sprom(struct b43_wldev * dev)7458619b14SKalle Valo static void lpphy_read_band_sprom(struct b43_wldev *dev)
7558619b14SKalle Valo {
7658619b14SKalle Valo struct ssb_sprom *sprom = dev->dev->bus_sprom;
7758619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
7858619b14SKalle Valo u16 cckpo, maxpwr;
7958619b14SKalle Valo u32 ofdmpo;
8058619b14SKalle Valo int i;
8158619b14SKalle Valo
8257fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
8358619b14SKalle Valo lpphy->tx_isolation_med_band = sprom->tri2g;
8458619b14SKalle Valo lpphy->bx_arch = sprom->bxa2g;
8558619b14SKalle Valo lpphy->rx_pwr_offset = sprom->rxpo2g;
8658619b14SKalle Valo lpphy->rssi_vf = sprom->rssismf2g;
8758619b14SKalle Valo lpphy->rssi_vc = sprom->rssismc2g;
8858619b14SKalle Valo lpphy->rssi_gs = sprom->rssisav2g;
8958619b14SKalle Valo lpphy->txpa[0] = sprom->pa0b0;
9058619b14SKalle Valo lpphy->txpa[1] = sprom->pa0b1;
9158619b14SKalle Valo lpphy->txpa[2] = sprom->pa0b2;
9258619b14SKalle Valo maxpwr = sprom->maxpwr_bg;
9358619b14SKalle Valo lpphy->max_tx_pwr_med_band = maxpwr;
9458619b14SKalle Valo cckpo = sprom->cck2gpo;
9558619b14SKalle Valo if (cckpo) {
9658619b14SKalle Valo ofdmpo = sprom->ofdm2gpo;
9758619b14SKalle Valo for (i = 0; i < 4; i++) {
9858619b14SKalle Valo lpphy->tx_max_rate[i] =
9958619b14SKalle Valo maxpwr - (ofdmpo & 0xF) * 2;
10058619b14SKalle Valo ofdmpo >>= 4;
10158619b14SKalle Valo }
10258619b14SKalle Valo ofdmpo = sprom->ofdm2gpo;
10358619b14SKalle Valo for (i = 4; i < 15; i++) {
10458619b14SKalle Valo lpphy->tx_max_rate[i] =
10558619b14SKalle Valo maxpwr - (ofdmpo & 0xF) * 2;
10658619b14SKalle Valo ofdmpo >>= 4;
10758619b14SKalle Valo }
10858619b14SKalle Valo } else {
10958619b14SKalle Valo u8 opo = sprom->opo;
11058619b14SKalle Valo for (i = 0; i < 4; i++)
11158619b14SKalle Valo lpphy->tx_max_rate[i] = maxpwr;
11258619b14SKalle Valo for (i = 4; i < 15; i++)
11358619b14SKalle Valo lpphy->tx_max_rate[i] = maxpwr - opo;
11458619b14SKalle Valo }
11558619b14SKalle Valo } else { /* 5GHz */
11658619b14SKalle Valo lpphy->tx_isolation_low_band = sprom->tri5gl;
11758619b14SKalle Valo lpphy->tx_isolation_med_band = sprom->tri5g;
11858619b14SKalle Valo lpphy->tx_isolation_hi_band = sprom->tri5gh;
11958619b14SKalle Valo lpphy->bx_arch = sprom->bxa5g;
12058619b14SKalle Valo lpphy->rx_pwr_offset = sprom->rxpo5g;
12158619b14SKalle Valo lpphy->rssi_vf = sprom->rssismf5g;
12258619b14SKalle Valo lpphy->rssi_vc = sprom->rssismc5g;
12358619b14SKalle Valo lpphy->rssi_gs = sprom->rssisav5g;
12458619b14SKalle Valo lpphy->txpa[0] = sprom->pa1b0;
12558619b14SKalle Valo lpphy->txpa[1] = sprom->pa1b1;
12658619b14SKalle Valo lpphy->txpa[2] = sprom->pa1b2;
12758619b14SKalle Valo lpphy->txpal[0] = sprom->pa1lob0;
12858619b14SKalle Valo lpphy->txpal[1] = sprom->pa1lob1;
12958619b14SKalle Valo lpphy->txpal[2] = sprom->pa1lob2;
13058619b14SKalle Valo lpphy->txpah[0] = sprom->pa1hib0;
13158619b14SKalle Valo lpphy->txpah[1] = sprom->pa1hib1;
13258619b14SKalle Valo lpphy->txpah[2] = sprom->pa1hib2;
13358619b14SKalle Valo maxpwr = sprom->maxpwr_al;
13458619b14SKalle Valo ofdmpo = sprom->ofdm5glpo;
13558619b14SKalle Valo lpphy->max_tx_pwr_low_band = maxpwr;
13658619b14SKalle Valo for (i = 4; i < 12; i++) {
13758619b14SKalle Valo lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2;
13858619b14SKalle Valo ofdmpo >>= 4;
13958619b14SKalle Valo }
14058619b14SKalle Valo maxpwr = sprom->maxpwr_a;
14158619b14SKalle Valo ofdmpo = sprom->ofdm5gpo;
14258619b14SKalle Valo lpphy->max_tx_pwr_med_band = maxpwr;
14358619b14SKalle Valo for (i = 4; i < 12; i++) {
14458619b14SKalle Valo lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2;
14558619b14SKalle Valo ofdmpo >>= 4;
14658619b14SKalle Valo }
14758619b14SKalle Valo maxpwr = sprom->maxpwr_ah;
14858619b14SKalle Valo ofdmpo = sprom->ofdm5ghpo;
14958619b14SKalle Valo lpphy->max_tx_pwr_hi_band = maxpwr;
15058619b14SKalle Valo for (i = 4; i < 12; i++) {
15158619b14SKalle Valo lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2;
15258619b14SKalle Valo ofdmpo >>= 4;
15358619b14SKalle Valo }
15458619b14SKalle Valo }
15558619b14SKalle Valo }
15658619b14SKalle Valo
lpphy_adjust_gain_table(struct b43_wldev * dev,u32 freq)15758619b14SKalle Valo static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq)
15858619b14SKalle Valo {
15958619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
16058619b14SKalle Valo u16 temp[3];
16158619b14SKalle Valo u16 isolation;
16258619b14SKalle Valo
16358619b14SKalle Valo B43_WARN_ON(dev->phy.rev >= 2);
16458619b14SKalle Valo
16557fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
16658619b14SKalle Valo isolation = lpphy->tx_isolation_med_band;
16758619b14SKalle Valo else if (freq <= 5320)
16858619b14SKalle Valo isolation = lpphy->tx_isolation_low_band;
16958619b14SKalle Valo else if (freq <= 5700)
17058619b14SKalle Valo isolation = lpphy->tx_isolation_med_band;
17158619b14SKalle Valo else
17258619b14SKalle Valo isolation = lpphy->tx_isolation_hi_band;
17358619b14SKalle Valo
17458619b14SKalle Valo temp[0] = ((isolation - 26) / 12) << 12;
17558619b14SKalle Valo temp[1] = temp[0] + 0x1000;
17658619b14SKalle Valo temp[2] = temp[0] + 0x2000;
17758619b14SKalle Valo
17858619b14SKalle Valo b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp);
17958619b14SKalle Valo b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp);
18058619b14SKalle Valo }
18158619b14SKalle Valo
lpphy_table_init(struct b43_wldev * dev)18258619b14SKalle Valo static void lpphy_table_init(struct b43_wldev *dev)
18358619b14SKalle Valo {
18458619b14SKalle Valo u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev));
18558619b14SKalle Valo
18658619b14SKalle Valo if (dev->phy.rev < 2)
18758619b14SKalle Valo lpphy_rev0_1_table_init(dev);
18858619b14SKalle Valo else
18958619b14SKalle Valo lpphy_rev2plus_table_init(dev);
19058619b14SKalle Valo
19158619b14SKalle Valo lpphy_init_tx_gain_table(dev);
19258619b14SKalle Valo
19358619b14SKalle Valo if (dev->phy.rev < 2)
19458619b14SKalle Valo lpphy_adjust_gain_table(dev, freq);
19558619b14SKalle Valo }
19658619b14SKalle Valo
lpphy_baseband_rev0_1_init(struct b43_wldev * dev)19758619b14SKalle Valo static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
19858619b14SKalle Valo {
19958619b14SKalle Valo struct ssb_bus *bus = dev->dev->sdev->bus;
20058619b14SKalle Valo struct ssb_sprom *sprom = dev->dev->bus_sprom;
20158619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
20258619b14SKalle Valo u16 tmp, tmp2;
20358619b14SKalle Valo
20458619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF);
20558619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0);
20658619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
20758619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
20858619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
20958619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004);
21058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078);
21158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
21258619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016);
21358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004);
21458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400);
21558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400);
21658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
21758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006);
21858619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE);
21958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005);
22058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180);
22158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00);
22258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005);
22358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A);
22458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3);
22558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
22658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB,
22758619b14SKalle Valo 0xFF00, lpphy->rx_pwr_offset);
22858619b14SKalle Valo if ((sprom->boardflags_lo & B43_BFL_FEM) &&
22957fbcce3SJohannes Berg ((b43_current_band(dev->wl) == NL80211_BAND_5GHZ) ||
23058619b14SKalle Valo (sprom->boardflags_hi & B43_BFH_PAREF))) {
23158619b14SKalle Valo ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28);
23258619b14SKalle Valo ssb_pmu_set_ldo_paref(&bus->chipco, true);
23358619b14SKalle Valo if (dev->phy.rev == 0) {
23458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
23558619b14SKalle Valo 0xFFCF, 0x0010);
23658619b14SKalle Valo }
23758619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB16(11, 7), 60);
23858619b14SKalle Valo } else {
23958619b14SKalle Valo ssb_pmu_set_ldo_paref(&bus->chipco, false);
24058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
24158619b14SKalle Valo 0xFFCF, 0x0020);
24258619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB16(11, 7), 100);
24358619b14SKalle Valo }
24458619b14SKalle Valo tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000;
24558619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp);
24658619b14SKalle Valo if (sprom->boardflags_hi & B43_BFH_RSSIINV)
24758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA);
24858619b14SKalle Valo else
24958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA);
25058619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB16(11, 1), 24);
25158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL,
25258619b14SKalle Valo 0xFFF9, (lpphy->bx_arch << 1));
25358619b14SKalle Valo if (dev->phy.rev == 1 &&
25458619b14SKalle Valo (sprom->boardflags_hi & B43_BFH_FEM_BT)) {
25558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
25658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900);
25758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
25858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
25958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A);
26058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400);
26158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A);
26258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00);
26358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A);
26458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900);
26558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A);
26658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00);
26758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A);
26858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900);
26958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
27058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
27157fbcce3SJohannes Berg } else if (b43_current_band(dev->wl) == NL80211_BAND_5GHZ ||
27258619b14SKalle Valo (dev->dev->board_type == SSB_BOARD_BU4312) ||
27358619b14SKalle Valo (dev->phy.rev == 0 && (sprom->boardflags_lo & B43_BFL_FEM))) {
27458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
27558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
27658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
27758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500);
27858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
27958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800);
28058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
28158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00);
28258619b14SKalle Valo } else if (dev->phy.rev == 1 ||
28358619b14SKalle Valo (sprom->boardflags_lo & B43_BFL_FEM)) {
28458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004);
28558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800);
28658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004);
28758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00);
28858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
28958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100);
29058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
29158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300);
29258619b14SKalle Valo } else {
29358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
29458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900);
29558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
29658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
29758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006);
29858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500);
29958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
30058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
30158619b14SKalle Valo }
30258619b14SKalle Valo if (dev->phy.rev == 1 && (sprom->boardflags_hi & B43_BFH_PAREF)) {
30358619b14SKalle Valo b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1);
30458619b14SKalle Valo b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2);
30558619b14SKalle Valo b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3);
30658619b14SKalle Valo b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4);
30758619b14SKalle Valo }
30858619b14SKalle Valo if ((sprom->boardflags_hi & B43_BFH_FEM_BT) &&
30958619b14SKalle Valo (dev->dev->chip_id == 0x5354) &&
31058619b14SKalle Valo (dev->dev->chip_pkg == SSB_CHIPPACK_BCM4712S)) {
31158619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
31258619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
31358619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
31458619b14SKalle Valo //FIXME the Broadcom driver caches & delays this HF write!
31558619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W);
31658619b14SKalle Valo }
31757fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
31858619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000);
31958619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040);
32058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400);
32158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00);
32258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007);
32358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003);
32458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020);
32558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
32658619b14SKalle Valo } else { /* 5GHz */
32758619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF);
32858619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF);
32958619b14SKalle Valo }
33058619b14SKalle Valo if (dev->phy.rev == 1) {
33158619b14SKalle Valo tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH);
33258619b14SKalle Valo tmp2 = (tmp & 0x03E0) >> 5;
33358619b14SKalle Valo tmp2 |= tmp2 << 5;
33458619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_4C3, tmp2);
33558619b14SKalle Valo tmp = b43_phy_read(dev, B43_LPPHY_GAINDIRECTMISMATCH);
33658619b14SKalle Valo tmp2 = (tmp & 0x1F00) >> 8;
33758619b14SKalle Valo tmp2 |= tmp2 << 5;
33858619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_4C4, tmp2);
33958619b14SKalle Valo tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB);
34058619b14SKalle Valo tmp2 = tmp & 0x00FF;
34158619b14SKalle Valo tmp2 |= tmp << 8;
34258619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_4C5, tmp2);
34358619b14SKalle Valo }
34458619b14SKalle Valo }
34558619b14SKalle Valo
lpphy_save_dig_flt_state(struct b43_wldev * dev)34658619b14SKalle Valo static void lpphy_save_dig_flt_state(struct b43_wldev *dev)
34758619b14SKalle Valo {
34858619b14SKalle Valo static const u16 addr[] = {
34958619b14SKalle Valo B43_PHY_OFDM(0xC1),
35058619b14SKalle Valo B43_PHY_OFDM(0xC2),
35158619b14SKalle Valo B43_PHY_OFDM(0xC3),
35258619b14SKalle Valo B43_PHY_OFDM(0xC4),
35358619b14SKalle Valo B43_PHY_OFDM(0xC5),
35458619b14SKalle Valo B43_PHY_OFDM(0xC6),
35558619b14SKalle Valo B43_PHY_OFDM(0xC7),
35658619b14SKalle Valo B43_PHY_OFDM(0xC8),
35758619b14SKalle Valo B43_PHY_OFDM(0xCF),
35858619b14SKalle Valo };
35958619b14SKalle Valo
36058619b14SKalle Valo static const u16 coefs[] = {
36158619b14SKalle Valo 0xDE5E, 0xE832, 0xE331, 0x4D26,
36258619b14SKalle Valo 0x0026, 0x1420, 0x0020, 0xFE08,
36358619b14SKalle Valo 0x0008,
36458619b14SKalle Valo };
36558619b14SKalle Valo
36658619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
36758619b14SKalle Valo int i;
36858619b14SKalle Valo
36958619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(addr); i++) {
37058619b14SKalle Valo lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]);
37158619b14SKalle Valo b43_phy_write(dev, addr[i], coefs[i]);
37258619b14SKalle Valo }
37358619b14SKalle Valo }
37458619b14SKalle Valo
lpphy_restore_dig_flt_state(struct b43_wldev * dev)37558619b14SKalle Valo static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
37658619b14SKalle Valo {
37758619b14SKalle Valo static const u16 addr[] = {
37858619b14SKalle Valo B43_PHY_OFDM(0xC1),
37958619b14SKalle Valo B43_PHY_OFDM(0xC2),
38058619b14SKalle Valo B43_PHY_OFDM(0xC3),
38158619b14SKalle Valo B43_PHY_OFDM(0xC4),
38258619b14SKalle Valo B43_PHY_OFDM(0xC5),
38358619b14SKalle Valo B43_PHY_OFDM(0xC6),
38458619b14SKalle Valo B43_PHY_OFDM(0xC7),
38558619b14SKalle Valo B43_PHY_OFDM(0xC8),
38658619b14SKalle Valo B43_PHY_OFDM(0xCF),
38758619b14SKalle Valo };
38858619b14SKalle Valo
38958619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
39058619b14SKalle Valo int i;
39158619b14SKalle Valo
39258619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(addr); i++)
39358619b14SKalle Valo b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
39458619b14SKalle Valo }
39558619b14SKalle Valo
lpphy_baseband_rev2plus_init(struct b43_wldev * dev)39658619b14SKalle Valo static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
39758619b14SKalle Valo {
39858619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
39958619b14SKalle Valo
40058619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50);
40158619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0x8800);
40258619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
40358619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0);
40458619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
40558619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
40658619b14SKalle Valo b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0);
40758619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0);
40858619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10);
40958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4);
41058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200);
41158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F);
41258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40);
41358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_PREAMBLECONFIRMTO, 0xFF00, 0x2);
41458619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000);
41558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000);
41658619b14SKalle Valo b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1);
41758619b14SKalle Valo if (dev->dev->board_rev >= 0x18) {
41858619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC);
41958619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14);
42058619b14SKalle Valo } else {
42158619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10);
42258619b14SKalle Valo }
42358619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4);
42458619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100);
42558619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48);
42658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0xFF00, 0x46);
42758619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xE4), 0xFF00, 0x10);
42858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9);
42958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF);
43058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500);
43158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0);
43258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300);
43358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00);
43458619b14SKalle Valo if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
43558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
43658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xA);
43758619b14SKalle Valo } else {
43858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x1E00);
43958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xD);
44058619b14SKalle Valo }
44158619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFE), 0xFFE0, 0x1F);
44258619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0xFFE0, 0xC);
44358619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0x100), 0xFF00, 0x19);
44458619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0x03FF, 0x3C00);
44558619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFE), 0xFC1F, 0x3E0);
44658619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0xFFE0, 0xC);
44758619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0x100), 0x00FF, 0x1900);
44858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
44958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12);
45058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000);
45158619b14SKalle Valo
45258619b14SKalle Valo if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
45358619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
45458619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
45558619b14SKalle Valo }
45658619b14SKalle Valo
45757fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
45858619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40);
45958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0xB00);
46058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6);
46158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00);
46258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1);
46358619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
46458619b14SKalle Valo } else /* 5GHz */
46558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40);
46658619b14SKalle Valo
46758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0xB3);
46858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
46958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB, 0xFF00, lpphy->rx_pwr_offset);
47058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RESET_CTL, 0x44);
47158619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RESET_CTL, 0x80);
47258619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, 0xA954);
47358619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1,
47458619b14SKalle Valo 0x2000 | ((u16)lpphy->rssi_gs << 10) |
47558619b14SKalle Valo ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf);
47658619b14SKalle Valo
47758619b14SKalle Valo if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
47858619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C);
47958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800);
48058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400);
48158619b14SKalle Valo }
48258619b14SKalle Valo
48358619b14SKalle Valo lpphy_save_dig_flt_state(dev);
48458619b14SKalle Valo }
48558619b14SKalle Valo
lpphy_baseband_init(struct b43_wldev * dev)48658619b14SKalle Valo static void lpphy_baseband_init(struct b43_wldev *dev)
48758619b14SKalle Valo {
48858619b14SKalle Valo lpphy_table_init(dev);
48958619b14SKalle Valo if (dev->phy.rev >= 2)
49058619b14SKalle Valo lpphy_baseband_rev2plus_init(dev);
49158619b14SKalle Valo else
49258619b14SKalle Valo lpphy_baseband_rev0_1_init(dev);
49358619b14SKalle Valo }
49458619b14SKalle Valo
49558619b14SKalle Valo struct b2062_freqdata {
49658619b14SKalle Valo u16 freq;
49758619b14SKalle Valo u8 data[6];
49858619b14SKalle Valo };
49958619b14SKalle Valo
50058619b14SKalle Valo /* Initialize the 2062 radio. */
lpphy_2062_init(struct b43_wldev * dev)50158619b14SKalle Valo static void lpphy_2062_init(struct b43_wldev *dev)
50258619b14SKalle Valo {
50358619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
50458619b14SKalle Valo struct ssb_bus *bus = dev->dev->sdev->bus;
50558619b14SKalle Valo u32 crystalfreq, tmp, ref;
50658619b14SKalle Valo unsigned int i;
50758619b14SKalle Valo const struct b2062_freqdata *fd = NULL;
50858619b14SKalle Valo
50958619b14SKalle Valo static const struct b2062_freqdata freqdata_tab[] = {
51058619b14SKalle Valo { .freq = 12000, .data[0] = 6, .data[1] = 6, .data[2] = 6,
51158619b14SKalle Valo .data[3] = 6, .data[4] = 10, .data[5] = 6, },
51258619b14SKalle Valo { .freq = 13000, .data[0] = 4, .data[1] = 4, .data[2] = 4,
51358619b14SKalle Valo .data[3] = 4, .data[4] = 11, .data[5] = 7, },
51458619b14SKalle Valo { .freq = 14400, .data[0] = 3, .data[1] = 3, .data[2] = 3,
51558619b14SKalle Valo .data[3] = 3, .data[4] = 12, .data[5] = 7, },
51658619b14SKalle Valo { .freq = 16200, .data[0] = 3, .data[1] = 3, .data[2] = 3,
51758619b14SKalle Valo .data[3] = 3, .data[4] = 13, .data[5] = 8, },
51858619b14SKalle Valo { .freq = 18000, .data[0] = 2, .data[1] = 2, .data[2] = 2,
51958619b14SKalle Valo .data[3] = 2, .data[4] = 14, .data[5] = 8, },
52058619b14SKalle Valo { .freq = 19200, .data[0] = 1, .data[1] = 1, .data[2] = 1,
52158619b14SKalle Valo .data[3] = 1, .data[4] = 14, .data[5] = 9, },
52258619b14SKalle Valo };
52358619b14SKalle Valo
52458619b14SKalle Valo b2062_upload_init_table(dev);
52558619b14SKalle Valo
52658619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_CTL3, 0);
52758619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_CTL4, 0);
52858619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_CTL5, 0);
52958619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_CTL6, 0);
53058619b14SKalle Valo b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40);
53158619b14SKalle Valo b43_radio_write(dev, B2062_N_PDN_CTL0, 0);
53258619b14SKalle Valo b43_radio_write(dev, B2062_N_CALIB_TS, 0x10);
53358619b14SKalle Valo b43_radio_write(dev, B2062_N_CALIB_TS, 0);
53458619b14SKalle Valo if (dev->phy.rev > 0) {
53558619b14SKalle Valo b43_radio_write(dev, B2062_S_BG_CTL1,
53658619b14SKalle Valo (b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80);
53758619b14SKalle Valo }
53857fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
53958619b14SKalle Valo b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1);
54058619b14SKalle Valo else
54158619b14SKalle Valo b43_radio_mask(dev, B2062_N_TSSI_CTL0, ~0x1);
54258619b14SKalle Valo
54358619b14SKalle Valo /* Get the crystal freq, in Hz. */
54458619b14SKalle Valo crystalfreq = bus->chipco.pmu.crystalfreq * 1000;
54558619b14SKalle Valo
54658619b14SKalle Valo B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU));
54758619b14SKalle Valo B43_WARN_ON(crystalfreq == 0);
54858619b14SKalle Valo
54958619b14SKalle Valo if (crystalfreq <= 30000000) {
55058619b14SKalle Valo lpphy->pdiv = 1;
55158619b14SKalle Valo b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB);
55258619b14SKalle Valo } else {
55358619b14SKalle Valo lpphy->pdiv = 2;
55458619b14SKalle Valo b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4);
55558619b14SKalle Valo }
55658619b14SKalle Valo
55758619b14SKalle Valo tmp = (((800000000 * lpphy->pdiv + crystalfreq) /
55858619b14SKalle Valo (2 * crystalfreq)) - 8) & 0xFF;
55958619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp);
56058619b14SKalle Valo
56158619b14SKalle Valo tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) /
56258619b14SKalle Valo (32000000 * lpphy->pdiv)) - 1) & 0xFF;
56358619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp);
56458619b14SKalle Valo
56558619b14SKalle Valo tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) /
56658619b14SKalle Valo (2000000 * lpphy->pdiv)) - 1) & 0xFF;
56758619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp);
56858619b14SKalle Valo
56958619b14SKalle Valo ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv);
57058619b14SKalle Valo ref &= 0xFFFF;
57158619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) {
57258619b14SKalle Valo if (ref < freqdata_tab[i].freq) {
57358619b14SKalle Valo fd = &freqdata_tab[i];
57458619b14SKalle Valo break;
57558619b14SKalle Valo }
57658619b14SKalle Valo }
57758619b14SKalle Valo if (!fd)
57858619b14SKalle Valo fd = &freqdata_tab[ARRAY_SIZE(freqdata_tab) - 1];
57958619b14SKalle Valo b43dbg(dev->wl, "b2062: Using crystal tab entry %u kHz.\n",
58058619b14SKalle Valo fd->freq); /* FIXME: Keep this printk until the code is fully debugged. */
58158619b14SKalle Valo
58258619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL8,
58358619b14SKalle Valo ((u16)(fd->data[1]) << 4) | fd->data[0]);
58458619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL9,
58558619b14SKalle Valo ((u16)(fd->data[3]) << 4) | fd->data[2]);
58658619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL10, fd->data[4]);
58758619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL11, fd->data[5]);
58858619b14SKalle Valo }
58958619b14SKalle Valo
59058619b14SKalle Valo /* Initialize the 2063 radio. */
lpphy_2063_init(struct b43_wldev * dev)59158619b14SKalle Valo static void lpphy_2063_init(struct b43_wldev *dev)
59258619b14SKalle Valo {
59358619b14SKalle Valo b2063_upload_init_table(dev);
59458619b14SKalle Valo b43_radio_write(dev, B2063_LOGEN_SP5, 0);
59558619b14SKalle Valo b43_radio_set(dev, B2063_COMM8, 0x38);
59658619b14SKalle Valo b43_radio_write(dev, B2063_REG_SP1, 0x56);
59758619b14SKalle Valo b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2);
59858619b14SKalle Valo b43_radio_write(dev, B2063_PA_SP7, 0);
59958619b14SKalle Valo b43_radio_write(dev, B2063_TX_RF_SP6, 0x20);
60058619b14SKalle Valo b43_radio_write(dev, B2063_TX_RF_SP9, 0x40);
60158619b14SKalle Valo if (dev->phy.rev == 2) {
60258619b14SKalle Valo b43_radio_write(dev, B2063_PA_SP3, 0xa0);
60358619b14SKalle Valo b43_radio_write(dev, B2063_PA_SP4, 0xa0);
60458619b14SKalle Valo b43_radio_write(dev, B2063_PA_SP2, 0x18);
60558619b14SKalle Valo } else {
60658619b14SKalle Valo b43_radio_write(dev, B2063_PA_SP3, 0x20);
60758619b14SKalle Valo b43_radio_write(dev, B2063_PA_SP2, 0x20);
60858619b14SKalle Valo }
60958619b14SKalle Valo }
61058619b14SKalle Valo
61158619b14SKalle Valo struct lpphy_stx_table_entry {
61258619b14SKalle Valo u16 phy_offset;
61358619b14SKalle Valo u16 phy_shift;
61458619b14SKalle Valo u16 rf_addr;
61558619b14SKalle Valo u16 rf_shift;
61658619b14SKalle Valo u16 mask;
61758619b14SKalle Valo };
61858619b14SKalle Valo
61958619b14SKalle Valo static const struct lpphy_stx_table_entry lpphy_stx_table[] = {
62058619b14SKalle Valo { .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, },
62158619b14SKalle Valo { .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, },
62258619b14SKalle Valo { .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, },
62358619b14SKalle Valo { .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, },
62458619b14SKalle Valo { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, },
62558619b14SKalle Valo { .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, },
62658619b14SKalle Valo { .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, },
62758619b14SKalle Valo { .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, },
62858619b14SKalle Valo { .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, },
62958619b14SKalle Valo { .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, },
63058619b14SKalle Valo { .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, },
63158619b14SKalle Valo { .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, },
63258619b14SKalle Valo { .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, },
63358619b14SKalle Valo { .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, },
63458619b14SKalle Valo { .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, },
63558619b14SKalle Valo { .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, },
63658619b14SKalle Valo { .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, },
63758619b14SKalle Valo { .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, },
63858619b14SKalle Valo { .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, },
63958619b14SKalle Valo { .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, },
64058619b14SKalle Valo { .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, },
64158619b14SKalle Valo { .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, },
64258619b14SKalle Valo { .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, },
64358619b14SKalle Valo { .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, },
64458619b14SKalle Valo { .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, },
64558619b14SKalle Valo { .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, },
64658619b14SKalle Valo { .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, },
64758619b14SKalle Valo { .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, },
64858619b14SKalle Valo { .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, },
64958619b14SKalle Valo };
65058619b14SKalle Valo
lpphy_sync_stx(struct b43_wldev * dev)65158619b14SKalle Valo static void lpphy_sync_stx(struct b43_wldev *dev)
65258619b14SKalle Valo {
65358619b14SKalle Valo const struct lpphy_stx_table_entry *e;
65458619b14SKalle Valo unsigned int i;
65558619b14SKalle Valo u16 tmp;
65658619b14SKalle Valo
65758619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) {
65858619b14SKalle Valo e = &lpphy_stx_table[i];
65958619b14SKalle Valo tmp = b43_radio_read(dev, e->rf_addr);
66058619b14SKalle Valo tmp >>= e->rf_shift;
66158619b14SKalle Valo tmp <<= e->phy_shift;
66258619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset),
66358619b14SKalle Valo ~(e->mask << e->phy_shift), tmp);
66458619b14SKalle Valo }
66558619b14SKalle Valo }
66658619b14SKalle Valo
lpphy_radio_init(struct b43_wldev * dev)66758619b14SKalle Valo static void lpphy_radio_init(struct b43_wldev *dev)
66858619b14SKalle Valo {
66958619b14SKalle Valo /* The radio is attached through the 4wire bus. */
67058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_FOURWIRE_CTL, 0x2);
67158619b14SKalle Valo udelay(1);
67258619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD);
67358619b14SKalle Valo udelay(1);
67458619b14SKalle Valo
67558619b14SKalle Valo if (dev->phy.radio_ver == 0x2062) {
67658619b14SKalle Valo lpphy_2062_init(dev);
67758619b14SKalle Valo } else {
67858619b14SKalle Valo lpphy_2063_init(dev);
67958619b14SKalle Valo lpphy_sync_stx(dev);
68058619b14SKalle Valo b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
68158619b14SKalle Valo b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
68258619b14SKalle Valo if (dev->dev->chip_id == 0x4325) {
68358619b14SKalle Valo // TODO SSB PMU recalibration
68458619b14SKalle Valo }
68558619b14SKalle Valo }
68658619b14SKalle Valo }
68758619b14SKalle Valo
68858619b14SKalle Valo struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; };
68958619b14SKalle Valo
lpphy_set_rc_cap(struct b43_wldev * dev)69058619b14SKalle Valo static void lpphy_set_rc_cap(struct b43_wldev *dev)
69158619b14SKalle Valo {
69258619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
69358619b14SKalle Valo
69458619b14SKalle Valo u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1;
69558619b14SKalle Valo
69658619b14SKalle Valo if (dev->phy.rev == 1) //FIXME check channel 14!
69758619b14SKalle Valo rc_cap = min_t(u8, rc_cap + 5, 15);
69858619b14SKalle Valo
69958619b14SKalle Valo b43_radio_write(dev, B2062_N_RXBB_CALIB2,
70058619b14SKalle Valo max_t(u8, lpphy->rc_cap - 4, 0x80));
70158619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80);
70258619b14SKalle Valo b43_radio_write(dev, B2062_S_RXG_CNT16,
70358619b14SKalle Valo ((lpphy->rc_cap & 0x1F) >> 2) | 0x80);
70458619b14SKalle Valo }
70558619b14SKalle Valo
lpphy_get_bb_mult(struct b43_wldev * dev)70658619b14SKalle Valo static u8 lpphy_get_bb_mult(struct b43_wldev *dev)
70758619b14SKalle Valo {
70858619b14SKalle Valo return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8;
70958619b14SKalle Valo }
71058619b14SKalle Valo
lpphy_set_bb_mult(struct b43_wldev * dev,u8 bb_mult)71158619b14SKalle Valo static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult)
71258619b14SKalle Valo {
71358619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8);
71458619b14SKalle Valo }
71558619b14SKalle Valo
lpphy_set_deaf(struct b43_wldev * dev,bool user)71658619b14SKalle Valo static void lpphy_set_deaf(struct b43_wldev *dev, bool user)
71758619b14SKalle Valo {
71858619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
71958619b14SKalle Valo
72058619b14SKalle Valo if (user)
72158619b14SKalle Valo lpphy->crs_usr_disable = true;
72258619b14SKalle Valo else
72358619b14SKalle Valo lpphy->crs_sys_disable = true;
72458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80);
72558619b14SKalle Valo }
72658619b14SKalle Valo
lpphy_clear_deaf(struct b43_wldev * dev,bool user)72758619b14SKalle Valo static void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
72858619b14SKalle Valo {
72958619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
73058619b14SKalle Valo
73158619b14SKalle Valo if (user)
73258619b14SKalle Valo lpphy->crs_usr_disable = false;
73358619b14SKalle Valo else
73458619b14SKalle Valo lpphy->crs_sys_disable = false;
73558619b14SKalle Valo
73658619b14SKalle Valo if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) {
73757fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
73858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
73958619b14SKalle Valo 0xFF1F, 0x60);
74058619b14SKalle Valo else
74158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
74258619b14SKalle Valo 0xFF1F, 0x20);
74358619b14SKalle Valo }
74458619b14SKalle Valo }
74558619b14SKalle Valo
lpphy_set_trsw_over(struct b43_wldev * dev,bool tx,bool rx)74658619b14SKalle Valo static void lpphy_set_trsw_over(struct b43_wldev *dev, bool tx, bool rx)
74758619b14SKalle Valo {
74858619b14SKalle Valo u16 trsw = (tx << 1) | rx;
74958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, trsw);
75058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
75158619b14SKalle Valo }
75258619b14SKalle Valo
lpphy_disable_crs(struct b43_wldev * dev,bool user)75358619b14SKalle Valo static void lpphy_disable_crs(struct b43_wldev *dev, bool user)
75458619b14SKalle Valo {
75558619b14SKalle Valo lpphy_set_deaf(dev, user);
75658619b14SKalle Valo lpphy_set_trsw_over(dev, false, true);
75758619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
75858619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
75958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);
76058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
76158619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10);
76258619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
76358619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF);
76458619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
76558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF);
76658619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
76758619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7);
76858619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38);
76958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F);
77058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100);
77158619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF);
77258619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0);
77358619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1);
77458619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20);
77558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF);
77658619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF);
77758619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
77858619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF);
77958619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF);
78058619b14SKalle Valo }
78158619b14SKalle Valo
lpphy_restore_crs(struct b43_wldev * dev,bool user)78258619b14SKalle Valo static void lpphy_restore_crs(struct b43_wldev *dev, bool user)
78358619b14SKalle Valo {
78458619b14SKalle Valo lpphy_clear_deaf(dev, user);
78558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80);
78658619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00);
78758619b14SKalle Valo }
78858619b14SKalle Valo
78958619b14SKalle Valo struct lpphy_tx_gains { u16 gm, pga, pad, dac; };
79058619b14SKalle Valo
lpphy_disable_rx_gain_override(struct b43_wldev * dev)79158619b14SKalle Valo static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
79258619b14SKalle Valo {
79358619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
79458619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
79558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
79658619b14SKalle Valo if (dev->phy.rev >= 2) {
79758619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
79857fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
79958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
80058619b14SKalle Valo b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
80158619b14SKalle Valo }
80258619b14SKalle Valo } else {
80358619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
80458619b14SKalle Valo }
80558619b14SKalle Valo }
80658619b14SKalle Valo
lpphy_enable_rx_gain_override(struct b43_wldev * dev)80758619b14SKalle Valo static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
80858619b14SKalle Valo {
80958619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
81058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
81158619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
81258619b14SKalle Valo if (dev->phy.rev >= 2) {
81358619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
81457fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
81558619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
81658619b14SKalle Valo b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
81758619b14SKalle Valo }
81858619b14SKalle Valo } else {
81958619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
82058619b14SKalle Valo }
82158619b14SKalle Valo }
82258619b14SKalle Valo
lpphy_disable_tx_gain_override(struct b43_wldev * dev)82358619b14SKalle Valo static void lpphy_disable_tx_gain_override(struct b43_wldev *dev)
82458619b14SKalle Valo {
82558619b14SKalle Valo if (dev->phy.rev < 2)
82658619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
82758619b14SKalle Valo else {
82858619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F);
82958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF);
83058619b14SKalle Valo }
83158619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF);
83258619b14SKalle Valo }
83358619b14SKalle Valo
lpphy_enable_tx_gain_override(struct b43_wldev * dev)83458619b14SKalle Valo static void lpphy_enable_tx_gain_override(struct b43_wldev *dev)
83558619b14SKalle Valo {
83658619b14SKalle Valo if (dev->phy.rev < 2)
83758619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
83858619b14SKalle Valo else {
83958619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x80);
84058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x4000);
84158619b14SKalle Valo }
84258619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x40);
84358619b14SKalle Valo }
84458619b14SKalle Valo
lpphy_get_tx_gains(struct b43_wldev * dev)84558619b14SKalle Valo static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
84658619b14SKalle Valo {
84758619b14SKalle Valo struct lpphy_tx_gains gains;
84858619b14SKalle Valo u16 tmp;
84958619b14SKalle Valo
85058619b14SKalle Valo gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7;
85158619b14SKalle Valo if (dev->phy.rev < 2) {
85258619b14SKalle Valo tmp = b43_phy_read(dev,
85358619b14SKalle Valo B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF;
85458619b14SKalle Valo gains.gm = tmp & 0x0007;
85558619b14SKalle Valo gains.pga = (tmp & 0x0078) >> 3;
85658619b14SKalle Valo gains.pad = (tmp & 0x780) >> 7;
85758619b14SKalle Valo } else {
85858619b14SKalle Valo tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL);
85958619b14SKalle Valo gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF;
86058619b14SKalle Valo gains.gm = tmp & 0xFF;
86158619b14SKalle Valo gains.pga = (tmp >> 8) & 0xFF;
86258619b14SKalle Valo }
86358619b14SKalle Valo
86458619b14SKalle Valo return gains;
86558619b14SKalle Valo }
86658619b14SKalle Valo
lpphy_set_dac_gain(struct b43_wldev * dev,u16 dac)86758619b14SKalle Valo static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
86858619b14SKalle Valo {
86958619b14SKalle Valo u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F;
87058619b14SKalle Valo ctl |= dac << 7;
87158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
87258619b14SKalle Valo }
87358619b14SKalle Valo
lpphy_get_pa_gain(struct b43_wldev * dev)87458619b14SKalle Valo static u16 lpphy_get_pa_gain(struct b43_wldev *dev)
87558619b14SKalle Valo {
87658619b14SKalle Valo return b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F;
87758619b14SKalle Valo }
87858619b14SKalle Valo
lpphy_set_pa_gain(struct b43_wldev * dev,u16 gain)87958619b14SKalle Valo static void lpphy_set_pa_gain(struct b43_wldev *dev, u16 gain)
88058619b14SKalle Valo {
88158619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0xE03F, gain << 6);
88258619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), 0x80FF, gain << 8);
88358619b14SKalle Valo }
88458619b14SKalle Valo
lpphy_set_tx_gains(struct b43_wldev * dev,struct lpphy_tx_gains gains)88558619b14SKalle Valo static void lpphy_set_tx_gains(struct b43_wldev *dev,
88658619b14SKalle Valo struct lpphy_tx_gains gains)
88758619b14SKalle Valo {
88858619b14SKalle Valo u16 rf_gain, pa_gain;
88958619b14SKalle Valo
89058619b14SKalle Valo if (dev->phy.rev < 2) {
89158619b14SKalle Valo rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm;
89258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
89358619b14SKalle Valo 0xF800, rf_gain);
89458619b14SKalle Valo } else {
89558619b14SKalle Valo pa_gain = lpphy_get_pa_gain(dev);
89658619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
89758619b14SKalle Valo (gains.pga << 8) | gains.gm);
89858619b14SKalle Valo /*
89958619b14SKalle Valo * SPEC FIXME The spec calls for (pa_gain << 8) here, but that
90058619b14SKalle Valo * conflicts with the spec for set_pa_gain! Vendor driver bug?
90158619b14SKalle Valo */
90258619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
90358619b14SKalle Valo 0x8000, gains.pad | (pa_gain << 6));
90458619b14SKalle Valo b43_phy_write(dev, B43_PHY_OFDM(0xFC),
90558619b14SKalle Valo (gains.pga << 8) | gains.gm);
90658619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xFD),
90758619b14SKalle Valo 0x8000, gains.pad | (pa_gain << 8));
90858619b14SKalle Valo }
90958619b14SKalle Valo lpphy_set_dac_gain(dev, gains.dac);
91058619b14SKalle Valo lpphy_enable_tx_gain_override(dev);
91158619b14SKalle Valo }
91258619b14SKalle Valo
lpphy_rev0_1_set_rx_gain(struct b43_wldev * dev,u32 gain)91358619b14SKalle Valo static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
91458619b14SKalle Valo {
91558619b14SKalle Valo u16 trsw = gain & 0x1;
91658619b14SKalle Valo u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2);
91758619b14SKalle Valo u16 ext_lna = (gain & 2) >> 1;
91858619b14SKalle Valo
91958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
92058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
92158619b14SKalle Valo 0xFBFF, ext_lna << 10);
92258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
92358619b14SKalle Valo 0xF7FF, ext_lna << 11);
92458619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
92558619b14SKalle Valo }
92658619b14SKalle Valo
lpphy_rev2plus_set_rx_gain(struct b43_wldev * dev,u32 gain)92758619b14SKalle Valo static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
92858619b14SKalle Valo {
92958619b14SKalle Valo u16 low_gain = gain & 0xFFFF;
93058619b14SKalle Valo u16 high_gain = (gain >> 16) & 0xF;
93158619b14SKalle Valo u16 ext_lna = (gain >> 21) & 0x1;
93258619b14SKalle Valo u16 trsw = ~(gain >> 20) & 0x1;
93358619b14SKalle Valo u16 tmp;
93458619b14SKalle Valo
93558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
93658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
93758619b14SKalle Valo 0xFDFF, ext_lna << 9);
93858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
93958619b14SKalle Valo 0xFBFF, ext_lna << 10);
94058619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
94158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain);
94257fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
94358619b14SKalle Valo tmp = (gain >> 2) & 0x3;
94458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
94558619b14SKalle Valo 0xE7FF, tmp<<11);
94658619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3);
94758619b14SKalle Valo }
94858619b14SKalle Valo }
94958619b14SKalle Valo
lpphy_set_rx_gain(struct b43_wldev * dev,u32 gain)95058619b14SKalle Valo static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)
95158619b14SKalle Valo {
95258619b14SKalle Valo if (dev->phy.rev < 2)
95358619b14SKalle Valo lpphy_rev0_1_set_rx_gain(dev, gain);
95458619b14SKalle Valo else
95558619b14SKalle Valo lpphy_rev2plus_set_rx_gain(dev, gain);
95658619b14SKalle Valo lpphy_enable_rx_gain_override(dev);
95758619b14SKalle Valo }
95858619b14SKalle Valo
lpphy_set_rx_gain_by_index(struct b43_wldev * dev,u16 idx)95958619b14SKalle Valo static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx)
96058619b14SKalle Valo {
96158619b14SKalle Valo u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx));
96258619b14SKalle Valo lpphy_set_rx_gain(dev, gain);
96358619b14SKalle Valo }
96458619b14SKalle Valo
lpphy_stop_ddfs(struct b43_wldev * dev)96558619b14SKalle Valo static void lpphy_stop_ddfs(struct b43_wldev *dev)
96658619b14SKalle Valo {
96758619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD);
96858619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF);
96958619b14SKalle Valo }
97058619b14SKalle Valo
lpphy_run_ddfs(struct b43_wldev * dev,int i_on,int q_on,int incr1,int incr2,int scale_idx)97158619b14SKalle Valo static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on,
97258619b14SKalle Valo int incr1, int incr2, int scale_idx)
97358619b14SKalle Valo {
97458619b14SKalle Valo lpphy_stop_ddfs(dev);
97558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80);
97658619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF);
97758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1);
97858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8);
97958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3);
98058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4);
98158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5);
98258619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB);
98358619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2);
98458619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x20);
98558619b14SKalle Valo }
98658619b14SKalle Valo
lpphy_rx_iq_est(struct b43_wldev * dev,u16 samples,u8 time,struct lpphy_iq_est * iq_est)98758619b14SKalle Valo static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
98858619b14SKalle Valo struct lpphy_iq_est *iq_est)
98958619b14SKalle Valo {
99058619b14SKalle Valo int i;
99158619b14SKalle Valo
99258619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7);
99358619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples);
99458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time);
99558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF);
99658619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
99758619b14SKalle Valo
99858619b14SKalle Valo for (i = 0; i < 500; i++) {
99958619b14SKalle Valo if (!(b43_phy_read(dev,
100058619b14SKalle Valo B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
100158619b14SKalle Valo break;
100258619b14SKalle Valo msleep(1);
100358619b14SKalle Valo }
100458619b14SKalle Valo
100558619b14SKalle Valo if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
100658619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
100758619b14SKalle Valo return false;
100858619b14SKalle Valo }
100958619b14SKalle Valo
101058619b14SKalle Valo iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR);
101158619b14SKalle Valo iq_est->iq_prod <<= 16;
101258619b14SKalle Valo iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR);
101358619b14SKalle Valo
101458619b14SKalle Valo iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR);
101558619b14SKalle Valo iq_est->i_pwr <<= 16;
101658619b14SKalle Valo iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR);
101758619b14SKalle Valo
101858619b14SKalle Valo iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR);
101958619b14SKalle Valo iq_est->q_pwr <<= 16;
102058619b14SKalle Valo iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR);
102158619b14SKalle Valo
102258619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
102358619b14SKalle Valo return true;
102458619b14SKalle Valo }
102558619b14SKalle Valo
lpphy_loopback(struct b43_wldev * dev)102658619b14SKalle Valo static int lpphy_loopback(struct b43_wldev *dev)
102758619b14SKalle Valo {
102858619b14SKalle Valo struct lpphy_iq_est iq_est;
102958619b14SKalle Valo int i, index = -1;
103058619b14SKalle Valo u32 tmp;
103158619b14SKalle Valo
103258619b14SKalle Valo memset(&iq_est, 0, sizeof(iq_est));
103358619b14SKalle Valo
103458619b14SKalle Valo lpphy_set_trsw_over(dev, true, true);
103558619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
103658619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
103758619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
103858619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
103958619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
104058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8);
104158619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80);
104258619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80);
104358619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80);
104458619b14SKalle Valo for (i = 0; i < 32; i++) {
104558619b14SKalle Valo lpphy_set_rx_gain_by_index(dev, i);
104658619b14SKalle Valo lpphy_run_ddfs(dev, 1, 1, 5, 5, 0);
104758619b14SKalle Valo if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
104858619b14SKalle Valo continue;
104958619b14SKalle Valo tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000;
105058619b14SKalle Valo if ((tmp > 4000) && (tmp < 10000)) {
105158619b14SKalle Valo index = i;
105258619b14SKalle Valo break;
105358619b14SKalle Valo }
105458619b14SKalle Valo }
105558619b14SKalle Valo lpphy_stop_ddfs(dev);
105658619b14SKalle Valo return index;
105758619b14SKalle Valo }
105858619b14SKalle Valo
105958619b14SKalle Valo /* Fixed-point division algorithm using only integer math. */
lpphy_qdiv_roundup(u32 dividend,u32 divisor,u8 precision)106058619b14SKalle Valo static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
106158619b14SKalle Valo {
106258619b14SKalle Valo u32 quotient, remainder;
106358619b14SKalle Valo
106458619b14SKalle Valo if (divisor == 0)
106558619b14SKalle Valo return 0;
106658619b14SKalle Valo
106758619b14SKalle Valo quotient = dividend / divisor;
106858619b14SKalle Valo remainder = dividend % divisor;
106958619b14SKalle Valo
107058619b14SKalle Valo while (precision > 0) {
107158619b14SKalle Valo quotient <<= 1;
107258619b14SKalle Valo if (remainder << 1 >= divisor) {
107358619b14SKalle Valo quotient++;
107458619b14SKalle Valo remainder = (remainder << 1) - divisor;
107558619b14SKalle Valo }
107658619b14SKalle Valo precision--;
107758619b14SKalle Valo }
107858619b14SKalle Valo
107958619b14SKalle Valo if (remainder << 1 >= divisor)
108058619b14SKalle Valo quotient++;
108158619b14SKalle Valo
108258619b14SKalle Valo return quotient;
108358619b14SKalle Valo }
108458619b14SKalle Valo
108558619b14SKalle Valo /* Read the TX power control mode from hardware. */
lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev * dev)108658619b14SKalle Valo static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev)
108758619b14SKalle Valo {
108858619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
108958619b14SKalle Valo u16 ctl;
109058619b14SKalle Valo
109158619b14SKalle Valo ctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD);
109258619b14SKalle Valo switch (ctl & B43_LPPHY_TX_PWR_CTL_CMD_MODE) {
109358619b14SKalle Valo case B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF:
109458619b14SKalle Valo lpphy->txpctl_mode = B43_LPPHY_TXPCTL_OFF;
109558619b14SKalle Valo break;
109658619b14SKalle Valo case B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW:
109758619b14SKalle Valo lpphy->txpctl_mode = B43_LPPHY_TXPCTL_SW;
109858619b14SKalle Valo break;
109958619b14SKalle Valo case B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW:
110058619b14SKalle Valo lpphy->txpctl_mode = B43_LPPHY_TXPCTL_HW;
110158619b14SKalle Valo break;
110258619b14SKalle Valo default:
110358619b14SKalle Valo lpphy->txpctl_mode = B43_LPPHY_TXPCTL_UNKNOWN;
110458619b14SKalle Valo B43_WARN_ON(1);
110558619b14SKalle Valo break;
110658619b14SKalle Valo }
110758619b14SKalle Valo }
110858619b14SKalle Valo
110958619b14SKalle Valo /* Set the TX power control mode in hardware. */
lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev * dev)111058619b14SKalle Valo static void lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev *dev)
111158619b14SKalle Valo {
111258619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
111358619b14SKalle Valo u16 ctl;
111458619b14SKalle Valo
111558619b14SKalle Valo switch (lpphy->txpctl_mode) {
111658619b14SKalle Valo case B43_LPPHY_TXPCTL_OFF:
111758619b14SKalle Valo ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF;
111858619b14SKalle Valo break;
111958619b14SKalle Valo case B43_LPPHY_TXPCTL_HW:
112058619b14SKalle Valo ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW;
112158619b14SKalle Valo break;
112258619b14SKalle Valo case B43_LPPHY_TXPCTL_SW:
112358619b14SKalle Valo ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW;
112458619b14SKalle Valo break;
112558619b14SKalle Valo default:
112658619b14SKalle Valo ctl = 0;
112758619b14SKalle Valo B43_WARN_ON(1);
112858619b14SKalle Valo }
112958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
113058619b14SKalle Valo ~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF, ctl);
113158619b14SKalle Valo }
113258619b14SKalle Valo
lpphy_set_tx_power_control(struct b43_wldev * dev,enum b43_lpphy_txpctl_mode mode)113358619b14SKalle Valo static void lpphy_set_tx_power_control(struct b43_wldev *dev,
113458619b14SKalle Valo enum b43_lpphy_txpctl_mode mode)
113558619b14SKalle Valo {
113658619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
113758619b14SKalle Valo enum b43_lpphy_txpctl_mode oldmode;
113858619b14SKalle Valo
113958619b14SKalle Valo lpphy_read_tx_pctl_mode_from_hardware(dev);
114058619b14SKalle Valo oldmode = lpphy->txpctl_mode;
114158619b14SKalle Valo if (oldmode == mode)
114258619b14SKalle Valo return;
114358619b14SKalle Valo lpphy->txpctl_mode = mode;
114458619b14SKalle Valo
114558619b14SKalle Valo if (oldmode == B43_LPPHY_TXPCTL_HW) {
114658619b14SKalle Valo //TODO Update TX Power NPT
114758619b14SKalle Valo //TODO Clear all TX Power offsets
114858619b14SKalle Valo } else {
114958619b14SKalle Valo if (mode == B43_LPPHY_TXPCTL_HW) {
115058619b14SKalle Valo //TODO Recalculate target TX power
115158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
115258619b14SKalle Valo 0xFF80, lpphy->tssi_idx);
115358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
115458619b14SKalle Valo 0x8FFF, ((u16)lpphy->tssi_npt << 16));
115558619b14SKalle Valo //TODO Set "TSSI Transmit Count" variable to total transmitted frame count
115658619b14SKalle Valo lpphy_disable_tx_gain_override(dev);
115758619b14SKalle Valo lpphy->tx_pwr_idx_over = -1;
115858619b14SKalle Valo }
115958619b14SKalle Valo }
116058619b14SKalle Valo if (dev->phy.rev >= 2) {
116158619b14SKalle Valo if (mode == B43_LPPHY_TXPCTL_HW)
116258619b14SKalle Valo b43_phy_set(dev, B43_PHY_OFDM(0xD0), 0x2);
116358619b14SKalle Valo else
116458619b14SKalle Valo b43_phy_mask(dev, B43_PHY_OFDM(0xD0), 0xFFFD);
116558619b14SKalle Valo }
116658619b14SKalle Valo lpphy_write_tx_pctl_mode_to_hardware(dev);
116758619b14SKalle Valo }
116858619b14SKalle Valo
116958619b14SKalle Valo static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
117058619b14SKalle Valo unsigned int new_channel);
117158619b14SKalle Valo
lpphy_rev0_1_rc_calib(struct b43_wldev * dev)117258619b14SKalle Valo static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
117358619b14SKalle Valo {
117458619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
117558619b14SKalle Valo struct lpphy_iq_est iq_est;
117658619b14SKalle Valo struct lpphy_tx_gains tx_gains;
117758619b14SKalle Valo static const u32 ideal_pwr_table[21] = {
117858619b14SKalle Valo 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
117958619b14SKalle Valo 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
118058619b14SKalle Valo 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
118158619b14SKalle Valo 0x0004c, 0x0002c, 0x0001a,
118258619b14SKalle Valo };
118358619b14SKalle Valo bool old_txg_ovr;
118458619b14SKalle Valo u8 old_bbmult;
118558619b14SKalle Valo u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval,
118658619b14SKalle Valo old_rf2_ovr, old_rf2_ovrval, old_phy_ctl;
118758619b14SKalle Valo enum b43_lpphy_txpctl_mode old_txpctl;
118858619b14SKalle Valo u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0;
118958619b14SKalle Valo int loopback, i, j, inner_sum, err;
119058619b14SKalle Valo
119158619b14SKalle Valo memset(&iq_est, 0, sizeof(iq_est));
119258619b14SKalle Valo
119358619b14SKalle Valo err = b43_lpphy_op_switch_channel(dev, 7);
119458619b14SKalle Valo if (err) {
119558619b14SKalle Valo b43dbg(dev->wl,
119658619b14SKalle Valo "RC calib: Failed to switch to channel 7, error = %d\n",
119758619b14SKalle Valo err);
119858619b14SKalle Valo }
119958619b14SKalle Valo old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40);
120058619b14SKalle Valo old_bbmult = lpphy_get_bb_mult(dev);
120158619b14SKalle Valo if (old_txg_ovr)
120258619b14SKalle Valo tx_gains = lpphy_get_tx_gains(dev);
120358619b14SKalle Valo old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0);
120458619b14SKalle Valo old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0);
120558619b14SKalle Valo old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR);
120658619b14SKalle Valo old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL);
120758619b14SKalle Valo old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2);
120858619b14SKalle Valo old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL);
120958619b14SKalle Valo old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL);
121058619b14SKalle Valo lpphy_read_tx_pctl_mode_from_hardware(dev);
121158619b14SKalle Valo old_txpctl = lpphy->txpctl_mode;
121258619b14SKalle Valo
121358619b14SKalle Valo lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
121458619b14SKalle Valo lpphy_disable_crs(dev, true);
121558619b14SKalle Valo loopback = lpphy_loopback(dev);
121658619b14SKalle Valo if (loopback == -1)
121758619b14SKalle Valo goto finish;
121858619b14SKalle Valo lpphy_set_rx_gain_by_index(dev, loopback);
121958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40);
122058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1);
122158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8);
122258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0);
122358619b14SKalle Valo for (i = 128; i <= 159; i++) {
122458619b14SKalle Valo b43_radio_write(dev, B2062_N_RXBB_CALIB2, i);
122558619b14SKalle Valo inner_sum = 0;
122658619b14SKalle Valo for (j = 5; j <= 25; j++) {
122758619b14SKalle Valo lpphy_run_ddfs(dev, 1, 1, j, j, 0);
122858619b14SKalle Valo if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
122958619b14SKalle Valo goto finish;
123058619b14SKalle Valo mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr;
123158619b14SKalle Valo if (j == 5)
123258619b14SKalle Valo tmp = mean_sq_pwr;
123358619b14SKalle Valo ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1;
123458619b14SKalle Valo normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12);
123558619b14SKalle Valo mean_sq_pwr = ideal_pwr - normal_pwr;
123658619b14SKalle Valo mean_sq_pwr *= mean_sq_pwr;
123758619b14SKalle Valo inner_sum += mean_sq_pwr;
123858619b14SKalle Valo if ((i == 128) || (inner_sum < mean_sq_pwr_min)) {
123958619b14SKalle Valo lpphy->rc_cap = i;
124058619b14SKalle Valo mean_sq_pwr_min = inner_sum;
124158619b14SKalle Valo }
124258619b14SKalle Valo }
124358619b14SKalle Valo }
124458619b14SKalle Valo lpphy_stop_ddfs(dev);
124558619b14SKalle Valo
124658619b14SKalle Valo finish:
124758619b14SKalle Valo lpphy_restore_crs(dev, true);
124858619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval);
124958619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr);
125058619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval);
125158619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr);
125258619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval);
125358619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr);
125458619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl);
125558619b14SKalle Valo
125658619b14SKalle Valo lpphy_set_bb_mult(dev, old_bbmult);
125758619b14SKalle Valo if (old_txg_ovr) {
125858619b14SKalle Valo /*
125958619b14SKalle Valo * SPEC FIXME: The specs say "get_tx_gains" here, which is
126058619b14SKalle Valo * illogical. According to lwfinger, vendor driver v4.150.10.5
126158619b14SKalle Valo * has a Set here, while v4.174.64.19 has a Get - regression in
126258619b14SKalle Valo * the vendor driver? This should be tested this once the code
126358619b14SKalle Valo * is testable.
126458619b14SKalle Valo */
126558619b14SKalle Valo lpphy_set_tx_gains(dev, tx_gains);
126658619b14SKalle Valo }
126758619b14SKalle Valo lpphy_set_tx_power_control(dev, old_txpctl);
126858619b14SKalle Valo if (lpphy->rc_cap)
126958619b14SKalle Valo lpphy_set_rc_cap(dev);
127058619b14SKalle Valo }
127158619b14SKalle Valo
lpphy_rev2plus_rc_calib(struct b43_wldev * dev)127258619b14SKalle Valo static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
127358619b14SKalle Valo {
127458619b14SKalle Valo struct ssb_bus *bus = dev->dev->sdev->bus;
127558619b14SKalle Valo u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
127658619b14SKalle Valo u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
127758619b14SKalle Valo int i;
127858619b14SKalle Valo
127958619b14SKalle Valo b43_radio_write(dev, B2063_RX_BB_SP8, 0x0);
128058619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
128158619b14SKalle Valo b43_radio_mask(dev, B2063_PLL_SP1, 0xF7);
128258619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
128358619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15);
128458619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70);
128558619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52);
128658619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
128758619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D);
128858619b14SKalle Valo
128958619b14SKalle Valo for (i = 0; i < 10000; i++) {
129058619b14SKalle Valo if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
129158619b14SKalle Valo break;
129258619b14SKalle Valo msleep(1);
129358619b14SKalle Valo }
129458619b14SKalle Valo
129558619b14SKalle Valo if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
129658619b14SKalle Valo b43_radio_write(dev, B2063_RX_BB_SP8, tmp);
129758619b14SKalle Valo
129858619b14SKalle Valo tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF;
129958619b14SKalle Valo
130058619b14SKalle Valo b43_radio_write(dev, B2063_TX_BB_SP3, 0x0);
130158619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
130258619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
130358619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55);
130458619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76);
130558619b14SKalle Valo
130658619b14SKalle Valo if (crystal_freq == 24000000) {
130758619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC);
130858619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0);
130958619b14SKalle Valo } else {
131058619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13);
131158619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
131258619b14SKalle Valo }
131358619b14SKalle Valo
131458619b14SKalle Valo b43_radio_write(dev, B2063_PA_SP7, 0x7D);
131558619b14SKalle Valo
131658619b14SKalle Valo for (i = 0; i < 10000; i++) {
131758619b14SKalle Valo if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
131858619b14SKalle Valo break;
131958619b14SKalle Valo msleep(1);
132058619b14SKalle Valo }
132158619b14SKalle Valo
132258619b14SKalle Valo if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
132358619b14SKalle Valo b43_radio_write(dev, B2063_TX_BB_SP3, tmp);
132458619b14SKalle Valo
132558619b14SKalle Valo b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
132658619b14SKalle Valo }
132758619b14SKalle Valo
lpphy_calibrate_rc(struct b43_wldev * dev)132858619b14SKalle Valo static void lpphy_calibrate_rc(struct b43_wldev *dev)
132958619b14SKalle Valo {
133058619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
133158619b14SKalle Valo
133258619b14SKalle Valo if (dev->phy.rev >= 2) {
133358619b14SKalle Valo lpphy_rev2plus_rc_calib(dev);
133458619b14SKalle Valo } else if (!lpphy->rc_cap) {
133557fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
133658619b14SKalle Valo lpphy_rev0_1_rc_calib(dev);
133758619b14SKalle Valo } else {
133858619b14SKalle Valo lpphy_set_rc_cap(dev);
133958619b14SKalle Valo }
134058619b14SKalle Valo }
134158619b14SKalle Valo
b43_lpphy_op_set_rx_antenna(struct b43_wldev * dev,int antenna)134258619b14SKalle Valo static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
134358619b14SKalle Valo {
134458619b14SKalle Valo if (dev->phy.rev >= 2)
134558619b14SKalle Valo return; // rev2+ doesn't support antenna diversity
134658619b14SKalle Valo
134758619b14SKalle Valo if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
134858619b14SKalle Valo return;
134958619b14SKalle Valo
135058619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
135158619b14SKalle Valo
135258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
135358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
135458619b14SKalle Valo
135558619b14SKalle Valo b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
135658619b14SKalle Valo
135758619b14SKalle Valo dev->phy.lp->antenna = antenna;
135858619b14SKalle Valo }
135958619b14SKalle Valo
lpphy_set_tx_iqcc(struct b43_wldev * dev,u16 a,u16 b)136058619b14SKalle Valo static void lpphy_set_tx_iqcc(struct b43_wldev *dev, u16 a, u16 b)
136158619b14SKalle Valo {
136258619b14SKalle Valo u16 tmp[2];
136358619b14SKalle Valo
136458619b14SKalle Valo tmp[0] = a;
136558619b14SKalle Valo tmp[1] = b;
136658619b14SKalle Valo b43_lptab_write_bulk(dev, B43_LPTAB16(0, 80), 2, tmp);
136758619b14SKalle Valo }
136858619b14SKalle Valo
lpphy_set_tx_power_by_index(struct b43_wldev * dev,u8 index)136958619b14SKalle Valo static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
137058619b14SKalle Valo {
137158619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
137258619b14SKalle Valo struct lpphy_tx_gains gains;
137358619b14SKalle Valo u32 iq_comp, tx_gain, coeff, rf_power;
137458619b14SKalle Valo
137558619b14SKalle Valo lpphy->tx_pwr_idx_over = index;
137658619b14SKalle Valo lpphy_read_tx_pctl_mode_from_hardware(dev);
137758619b14SKalle Valo if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
137858619b14SKalle Valo lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);
137958619b14SKalle Valo if (dev->phy.rev >= 2) {
138058619b14SKalle Valo iq_comp = b43_lptab_read(dev, B43_LPTAB32(7, index + 320));
138158619b14SKalle Valo tx_gain = b43_lptab_read(dev, B43_LPTAB32(7, index + 192));
138258619b14SKalle Valo gains.pad = (tx_gain >> 16) & 0xFF;
138358619b14SKalle Valo gains.gm = tx_gain & 0xFF;
138458619b14SKalle Valo gains.pga = (tx_gain >> 8) & 0xFF;
138558619b14SKalle Valo gains.dac = (iq_comp >> 28) & 0xFF;
138658619b14SKalle Valo lpphy_set_tx_gains(dev, gains);
138758619b14SKalle Valo } else {
138858619b14SKalle Valo iq_comp = b43_lptab_read(dev, B43_LPTAB32(10, index + 320));
138958619b14SKalle Valo tx_gain = b43_lptab_read(dev, B43_LPTAB32(10, index + 192));
139058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
139158619b14SKalle Valo 0xF800, (tx_gain >> 4) & 0x7FFF);
139258619b14SKalle Valo lpphy_set_dac_gain(dev, tx_gain & 0x7);
139358619b14SKalle Valo lpphy_set_pa_gain(dev, (tx_gain >> 24) & 0x7F);
139458619b14SKalle Valo }
139558619b14SKalle Valo lpphy_set_bb_mult(dev, (iq_comp >> 20) & 0xFF);
139658619b14SKalle Valo lpphy_set_tx_iqcc(dev, (iq_comp >> 10) & 0x3FF, iq_comp & 0x3FF);
139758619b14SKalle Valo if (dev->phy.rev >= 2) {
139858619b14SKalle Valo coeff = b43_lptab_read(dev, B43_LPTAB32(7, index + 448));
139958619b14SKalle Valo } else {
140058619b14SKalle Valo coeff = b43_lptab_read(dev, B43_LPTAB32(10, index + 448));
140158619b14SKalle Valo }
140258619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB16(0, 85), coeff & 0xFFFF);
140358619b14SKalle Valo if (dev->phy.rev >= 2) {
140458619b14SKalle Valo rf_power = b43_lptab_read(dev, B43_LPTAB32(7, index + 576));
140558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00,
140658619b14SKalle Valo rf_power & 0xFFFF);//SPEC FIXME mask & set != 0
140758619b14SKalle Valo }
140858619b14SKalle Valo lpphy_enable_tx_gain_override(dev);
140958619b14SKalle Valo }
141058619b14SKalle Valo
lpphy_btcoex_override(struct b43_wldev * dev)141158619b14SKalle Valo static void lpphy_btcoex_override(struct b43_wldev *dev)
141258619b14SKalle Valo {
141358619b14SKalle Valo b43_write16(dev, B43_MMIO_BTCOEX_CTL, 0x3);
141458619b14SKalle Valo b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
141558619b14SKalle Valo }
141658619b14SKalle Valo
b43_lpphy_op_software_rfkill(struct b43_wldev * dev,bool blocked)141758619b14SKalle Valo static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
141858619b14SKalle Valo bool blocked)
141958619b14SKalle Valo {
142058619b14SKalle Valo //TODO check MAC control register
142158619b14SKalle Valo if (blocked) {
142258619b14SKalle Valo if (dev->phy.rev >= 2) {
142358619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x83FF);
142458619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
142558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0x80FF);
142658619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xDFFF);
142758619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0808);
142858619b14SKalle Valo } else {
142958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xE0FF);
143058619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
143158619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFCFF);
143258619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0018);
143358619b14SKalle Valo }
143458619b14SKalle Valo } else {
143558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xE0FF);
143658619b14SKalle Valo if (dev->phy.rev >= 2)
143758619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xF7F7);
143858619b14SKalle Valo else
143958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFE7);
144058619b14SKalle Valo }
144158619b14SKalle Valo }
144258619b14SKalle Valo
144358619b14SKalle Valo /* This was previously called lpphy_japan_filter */
lpphy_set_analog_filter(struct b43_wldev * dev,int channel)144458619b14SKalle Valo static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
144558619b14SKalle Valo {
144658619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
144758619b14SKalle Valo u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
144858619b14SKalle Valo
144958619b14SKalle Valo if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
145058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
145158619b14SKalle Valo if ((dev->phy.rev == 1) && (lpphy->rc_cap))
145258619b14SKalle Valo lpphy_set_rc_cap(dev);
145358619b14SKalle Valo } else {
145458619b14SKalle Valo b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
145558619b14SKalle Valo }
145658619b14SKalle Valo }
145758619b14SKalle Valo
lpphy_set_tssi_mux(struct b43_wldev * dev,enum tssi_mux_mode mode)145858619b14SKalle Valo static void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode)
145958619b14SKalle Valo {
146058619b14SKalle Valo if (mode != TSSI_MUX_EXT) {
146158619b14SKalle Valo b43_radio_set(dev, B2063_PA_SP1, 0x2);
146258619b14SKalle Valo b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000);
146358619b14SKalle Valo b43_radio_write(dev, B2063_PA_CTL10, 0x51);
146458619b14SKalle Valo if (mode == TSSI_MUX_POSTPA) {
146558619b14SKalle Valo b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE);
146658619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7);
146758619b14SKalle Valo } else {
146858619b14SKalle Valo b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1);
146958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL,
147058619b14SKalle Valo 0xFFC7, 0x20);
147158619b14SKalle Valo }
147258619b14SKalle Valo } else {
147358619b14SKalle Valo B43_WARN_ON(1);
147458619b14SKalle Valo }
147558619b14SKalle Valo }
147658619b14SKalle Valo
lpphy_tx_pctl_init_hw(struct b43_wldev * dev)147758619b14SKalle Valo static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev)
147858619b14SKalle Valo {
147958619b14SKalle Valo u16 tmp;
148058619b14SKalle Valo int i;
148158619b14SKalle Valo
148258619b14SKalle Valo //SPEC TODO Call LP PHY Clear TX Power offsets
148358619b14SKalle Valo for (i = 0; i < 64; i++) {
148458619b14SKalle Valo if (dev->phy.rev >= 2)
148558619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i);
148658619b14SKalle Valo else
148758619b14SKalle Valo b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i);
148858619b14SKalle Valo }
148958619b14SKalle Valo
149058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF);
149158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000);
149258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F);
149358619b14SKalle Valo if (dev->phy.rev < 2) {
149458619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF);
149558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000);
149658619b14SKalle Valo } else {
149758619b14SKalle Valo b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE);
149858619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4);
149958619b14SKalle Valo b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10);
150058619b14SKalle Valo b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1);
150158619b14SKalle Valo lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA);
150258619b14SKalle Valo }
150358619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000);
150458619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF);
150558619b14SKalle Valo b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA);
150658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
150758619b14SKalle Valo ~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
150858619b14SKalle Valo B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
150958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF);
151058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
151158619b14SKalle Valo ~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
151258619b14SKalle Valo B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW);
151358619b14SKalle Valo
151458619b14SKalle Valo if (dev->phy.rev < 2) {
151558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000);
151658619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF);
151758619b14SKalle Valo } else {
151858619b14SKalle Valo lpphy_set_tx_power_by_index(dev, 0x7F);
151958619b14SKalle Valo }
152058619b14SKalle Valo
152158619b14SKalle Valo b43_dummy_transmission(dev, true, true);
152258619b14SKalle Valo
152358619b14SKalle Valo tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT);
152458619b14SKalle Valo if (tmp & 0x8000) {
152558619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI,
152658619b14SKalle Valo 0xFFC0, (tmp & 0xFF) - 32);
152758619b14SKalle Valo }
152858619b14SKalle Valo
152958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF);
153058619b14SKalle Valo
153158619b14SKalle Valo // (SPEC?) TODO Set "Target TX frequency" variable to 0
153258619b14SKalle Valo // SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8!
153358619b14SKalle Valo }
153458619b14SKalle Valo
lpphy_tx_pctl_init_sw(struct b43_wldev * dev)153558619b14SKalle Valo static void lpphy_tx_pctl_init_sw(struct b43_wldev *dev)
153658619b14SKalle Valo {
153758619b14SKalle Valo struct lpphy_tx_gains gains;
153858619b14SKalle Valo
153957fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
154058619b14SKalle Valo gains.gm = 4;
154158619b14SKalle Valo gains.pad = 12;
154258619b14SKalle Valo gains.pga = 12;
154358619b14SKalle Valo gains.dac = 0;
154458619b14SKalle Valo } else {
154558619b14SKalle Valo gains.gm = 7;
154658619b14SKalle Valo gains.pad = 14;
154758619b14SKalle Valo gains.pga = 15;
154858619b14SKalle Valo gains.dac = 0;
154958619b14SKalle Valo }
155058619b14SKalle Valo lpphy_set_tx_gains(dev, gains);
155158619b14SKalle Valo lpphy_set_bb_mult(dev, 150);
155258619b14SKalle Valo }
155358619b14SKalle Valo
155458619b14SKalle Valo /* Initialize TX power control */
lpphy_tx_pctl_init(struct b43_wldev * dev)155558619b14SKalle Valo static void lpphy_tx_pctl_init(struct b43_wldev *dev)
155658619b14SKalle Valo {
155758619b14SKalle Valo if (0/*FIXME HWPCTL capable */) {
155858619b14SKalle Valo lpphy_tx_pctl_init_hw(dev);
155958619b14SKalle Valo } else { /* This device is only software TX power control capable. */
156058619b14SKalle Valo lpphy_tx_pctl_init_sw(dev);
156158619b14SKalle Valo }
156258619b14SKalle Valo }
156358619b14SKalle Valo
lpphy_pr41573_workaround(struct b43_wldev * dev)156458619b14SKalle Valo static void lpphy_pr41573_workaround(struct b43_wldev *dev)
156558619b14SKalle Valo {
156658619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
156758619b14SKalle Valo u32 *saved_tab;
156858619b14SKalle Valo const unsigned int saved_tab_size = 256;
156958619b14SKalle Valo enum b43_lpphy_txpctl_mode txpctl_mode;
157058619b14SKalle Valo s8 tx_pwr_idx_over;
157158619b14SKalle Valo u16 tssi_npt, tssi_idx;
157258619b14SKalle Valo
157358619b14SKalle Valo saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL);
157458619b14SKalle Valo if (!saved_tab) {
157558619b14SKalle Valo b43err(dev->wl, "PR41573 failed. Out of memory!\n");
157658619b14SKalle Valo return;
157758619b14SKalle Valo }
157858619b14SKalle Valo
157958619b14SKalle Valo lpphy_read_tx_pctl_mode_from_hardware(dev);
158058619b14SKalle Valo txpctl_mode = lpphy->txpctl_mode;
158158619b14SKalle Valo tx_pwr_idx_over = lpphy->tx_pwr_idx_over;
158258619b14SKalle Valo tssi_npt = lpphy->tssi_npt;
158358619b14SKalle Valo tssi_idx = lpphy->tssi_idx;
158458619b14SKalle Valo
158558619b14SKalle Valo if (dev->phy.rev < 2) {
158658619b14SKalle Valo b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140),
158758619b14SKalle Valo saved_tab_size, saved_tab);
158858619b14SKalle Valo } else {
158958619b14SKalle Valo b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
159058619b14SKalle Valo saved_tab_size, saved_tab);
159158619b14SKalle Valo }
159258619b14SKalle Valo //FIXME PHY reset
159358619b14SKalle Valo lpphy_table_init(dev); //FIXME is table init needed?
159458619b14SKalle Valo lpphy_baseband_init(dev);
159558619b14SKalle Valo lpphy_tx_pctl_init(dev);
159658619b14SKalle Valo b43_lpphy_op_software_rfkill(dev, false);
159758619b14SKalle Valo lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
159858619b14SKalle Valo if (dev->phy.rev < 2) {
159958619b14SKalle Valo b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
160058619b14SKalle Valo saved_tab_size, saved_tab);
160158619b14SKalle Valo } else {
160258619b14SKalle Valo b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
160358619b14SKalle Valo saved_tab_size, saved_tab);
160458619b14SKalle Valo }
160558619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
160658619b14SKalle Valo lpphy->tssi_npt = tssi_npt;
160758619b14SKalle Valo lpphy->tssi_idx = tssi_idx;
160858619b14SKalle Valo lpphy_set_analog_filter(dev, lpphy->channel);
160958619b14SKalle Valo if (tx_pwr_idx_over != -1)
161058619b14SKalle Valo lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
161158619b14SKalle Valo if (lpphy->rc_cap)
161258619b14SKalle Valo lpphy_set_rc_cap(dev);
161358619b14SKalle Valo b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
161458619b14SKalle Valo lpphy_set_tx_power_control(dev, txpctl_mode);
161558619b14SKalle Valo kfree(saved_tab);
161658619b14SKalle Valo }
161758619b14SKalle Valo
161858619b14SKalle Valo struct lpphy_rx_iq_comp { u8 chan; s8 c1, c0; };
161958619b14SKalle Valo
162058619b14SKalle Valo static const struct lpphy_rx_iq_comp lpphy_5354_iq_table[] = {
162158619b14SKalle Valo { .chan = 1, .c1 = -66, .c0 = 15, },
162258619b14SKalle Valo { .chan = 2, .c1 = -66, .c0 = 15, },
162358619b14SKalle Valo { .chan = 3, .c1 = -66, .c0 = 15, },
162458619b14SKalle Valo { .chan = 4, .c1 = -66, .c0 = 15, },
162558619b14SKalle Valo { .chan = 5, .c1 = -66, .c0 = 15, },
162658619b14SKalle Valo { .chan = 6, .c1 = -66, .c0 = 15, },
162758619b14SKalle Valo { .chan = 7, .c1 = -66, .c0 = 14, },
162858619b14SKalle Valo { .chan = 8, .c1 = -66, .c0 = 14, },
162958619b14SKalle Valo { .chan = 9, .c1 = -66, .c0 = 14, },
163058619b14SKalle Valo { .chan = 10, .c1 = -66, .c0 = 14, },
163158619b14SKalle Valo { .chan = 11, .c1 = -66, .c0 = 14, },
163258619b14SKalle Valo { .chan = 12, .c1 = -66, .c0 = 13, },
163358619b14SKalle Valo { .chan = 13, .c1 = -66, .c0 = 13, },
163458619b14SKalle Valo { .chan = 14, .c1 = -66, .c0 = 13, },
163558619b14SKalle Valo };
163658619b14SKalle Valo
163758619b14SKalle Valo static const struct lpphy_rx_iq_comp lpphy_rev0_1_iq_table[] = {
163858619b14SKalle Valo { .chan = 1, .c1 = -64, .c0 = 13, },
163958619b14SKalle Valo { .chan = 2, .c1 = -64, .c0 = 13, },
164058619b14SKalle Valo { .chan = 3, .c1 = -64, .c0 = 13, },
164158619b14SKalle Valo { .chan = 4, .c1 = -64, .c0 = 13, },
164258619b14SKalle Valo { .chan = 5, .c1 = -64, .c0 = 12, },
164358619b14SKalle Valo { .chan = 6, .c1 = -64, .c0 = 12, },
164458619b14SKalle Valo { .chan = 7, .c1 = -64, .c0 = 12, },
164558619b14SKalle Valo { .chan = 8, .c1 = -64, .c0 = 12, },
164658619b14SKalle Valo { .chan = 9, .c1 = -64, .c0 = 12, },
164758619b14SKalle Valo { .chan = 10, .c1 = -64, .c0 = 11, },
164858619b14SKalle Valo { .chan = 11, .c1 = -64, .c0 = 11, },
164958619b14SKalle Valo { .chan = 12, .c1 = -64, .c0 = 11, },
165058619b14SKalle Valo { .chan = 13, .c1 = -64, .c0 = 11, },
165158619b14SKalle Valo { .chan = 14, .c1 = -64, .c0 = 10, },
165258619b14SKalle Valo { .chan = 34, .c1 = -62, .c0 = 24, },
165358619b14SKalle Valo { .chan = 38, .c1 = -62, .c0 = 24, },
165458619b14SKalle Valo { .chan = 42, .c1 = -62, .c0 = 24, },
165558619b14SKalle Valo { .chan = 46, .c1 = -62, .c0 = 23, },
165658619b14SKalle Valo { .chan = 36, .c1 = -62, .c0 = 24, },
165758619b14SKalle Valo { .chan = 40, .c1 = -62, .c0 = 24, },
165858619b14SKalle Valo { .chan = 44, .c1 = -62, .c0 = 23, },
165958619b14SKalle Valo { .chan = 48, .c1 = -62, .c0 = 23, },
166058619b14SKalle Valo { .chan = 52, .c1 = -62, .c0 = 23, },
166158619b14SKalle Valo { .chan = 56, .c1 = -62, .c0 = 22, },
166258619b14SKalle Valo { .chan = 60, .c1 = -62, .c0 = 22, },
166358619b14SKalle Valo { .chan = 64, .c1 = -62, .c0 = 22, },
166458619b14SKalle Valo { .chan = 100, .c1 = -62, .c0 = 16, },
166558619b14SKalle Valo { .chan = 104, .c1 = -62, .c0 = 16, },
166658619b14SKalle Valo { .chan = 108, .c1 = -62, .c0 = 15, },
166758619b14SKalle Valo { .chan = 112, .c1 = -62, .c0 = 14, },
166858619b14SKalle Valo { .chan = 116, .c1 = -62, .c0 = 14, },
166958619b14SKalle Valo { .chan = 120, .c1 = -62, .c0 = 13, },
167058619b14SKalle Valo { .chan = 124, .c1 = -62, .c0 = 12, },
167158619b14SKalle Valo { .chan = 128, .c1 = -62, .c0 = 12, },
167258619b14SKalle Valo { .chan = 132, .c1 = -62, .c0 = 12, },
167358619b14SKalle Valo { .chan = 136, .c1 = -62, .c0 = 11, },
167458619b14SKalle Valo { .chan = 140, .c1 = -62, .c0 = 10, },
167558619b14SKalle Valo { .chan = 149, .c1 = -61, .c0 = 9, },
167658619b14SKalle Valo { .chan = 153, .c1 = -61, .c0 = 9, },
167758619b14SKalle Valo { .chan = 157, .c1 = -61, .c0 = 9, },
167858619b14SKalle Valo { .chan = 161, .c1 = -61, .c0 = 8, },
167958619b14SKalle Valo { .chan = 165, .c1 = -61, .c0 = 8, },
168058619b14SKalle Valo { .chan = 184, .c1 = -62, .c0 = 25, },
168158619b14SKalle Valo { .chan = 188, .c1 = -62, .c0 = 25, },
168258619b14SKalle Valo { .chan = 192, .c1 = -62, .c0 = 25, },
168358619b14SKalle Valo { .chan = 196, .c1 = -62, .c0 = 25, },
168458619b14SKalle Valo { .chan = 200, .c1 = -62, .c0 = 25, },
168558619b14SKalle Valo { .chan = 204, .c1 = -62, .c0 = 25, },
168658619b14SKalle Valo { .chan = 208, .c1 = -62, .c0 = 25, },
168758619b14SKalle Valo { .chan = 212, .c1 = -62, .c0 = 25, },
168858619b14SKalle Valo { .chan = 216, .c1 = -62, .c0 = 26, },
168958619b14SKalle Valo };
169058619b14SKalle Valo
169158619b14SKalle Valo static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
169258619b14SKalle Valo .chan = 0,
169358619b14SKalle Valo .c1 = -64,
169458619b14SKalle Valo .c0 = 0,
169558619b14SKalle Valo };
169658619b14SKalle Valo
lpphy_calc_rx_iq_comp(struct b43_wldev * dev,u16 samples)169758619b14SKalle Valo static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
169858619b14SKalle Valo {
169958619b14SKalle Valo struct lpphy_iq_est iq_est;
170058619b14SKalle Valo u16 c0, c1;
170158619b14SKalle Valo int prod, ipwr, qpwr, prod_msb, q_msb, tmp1, tmp2, tmp3, tmp4, ret;
170258619b14SKalle Valo
170358619b14SKalle Valo c1 = b43_phy_read(dev, B43_LPPHY_RX_COMP_COEFF_S);
170458619b14SKalle Valo c0 = c1 >> 8;
170558619b14SKalle Valo c1 |= 0xFF;
170658619b14SKalle Valo
170758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, 0x00C0);
170858619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF);
170958619b14SKalle Valo
171058619b14SKalle Valo ret = lpphy_rx_iq_est(dev, samples, 32, &iq_est);
171158619b14SKalle Valo if (!ret)
171258619b14SKalle Valo goto out;
171358619b14SKalle Valo
171458619b14SKalle Valo prod = iq_est.iq_prod;
171558619b14SKalle Valo ipwr = iq_est.i_pwr;
171658619b14SKalle Valo qpwr = iq_est.q_pwr;
171758619b14SKalle Valo
171858619b14SKalle Valo if (ipwr + qpwr < 2) {
171958619b14SKalle Valo ret = 0;
172058619b14SKalle Valo goto out;
172158619b14SKalle Valo }
172258619b14SKalle Valo
172358619b14SKalle Valo prod_msb = fls(abs(prod));
172458619b14SKalle Valo q_msb = fls(abs(qpwr));
172558619b14SKalle Valo tmp1 = prod_msb - 20;
172658619b14SKalle Valo
172758619b14SKalle Valo if (tmp1 >= 0) {
172858619b14SKalle Valo tmp3 = ((prod << (30 - prod_msb)) + (ipwr >> (1 + tmp1))) /
172958619b14SKalle Valo (ipwr >> tmp1);
173058619b14SKalle Valo } else {
173158619b14SKalle Valo tmp3 = ((prod << (30 - prod_msb)) + (ipwr << (-1 - tmp1))) /
173258619b14SKalle Valo (ipwr << -tmp1);
173358619b14SKalle Valo }
173458619b14SKalle Valo
173558619b14SKalle Valo tmp2 = q_msb - 11;
173658619b14SKalle Valo
173758619b14SKalle Valo if (tmp2 >= 0)
173858619b14SKalle Valo tmp4 = (qpwr << (31 - q_msb)) / (ipwr >> tmp2);
173958619b14SKalle Valo else
174058619b14SKalle Valo tmp4 = (qpwr << (31 - q_msb)) / (ipwr << -tmp2);
174158619b14SKalle Valo
174258619b14SKalle Valo tmp4 -= tmp3 * tmp3;
174358619b14SKalle Valo tmp4 = -int_sqrt(tmp4);
174458619b14SKalle Valo
174558619b14SKalle Valo c0 = tmp3 >> 3;
174658619b14SKalle Valo c1 = tmp4 >> 4;
174758619b14SKalle Valo
174858619b14SKalle Valo out:
174958619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, c1);
175058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF, c0 << 8);
175158619b14SKalle Valo return ret;
175258619b14SKalle Valo }
175358619b14SKalle Valo
lpphy_run_samples(struct b43_wldev * dev,u16 samples,u16 loops,u16 wait)175458619b14SKalle Valo static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
175558619b14SKalle Valo u16 wait)
175658619b14SKalle Valo {
175758619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL,
175858619b14SKalle Valo 0xFFC0, samples - 1);
175958619b14SKalle Valo if (loops != 0xFFFF)
176058619b14SKalle Valo loops--;
176158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000, loops);
176258619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL, 0x3F, wait << 6);
176358619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_A_PHY_CTL_ADDR, 0x1);
176458619b14SKalle Valo }
176558619b14SKalle Valo
176658619b14SKalle Valo //SPEC FIXME what does a negative freq mean?
lpphy_start_tx_tone(struct b43_wldev * dev,s32 freq,u16 max)176758619b14SKalle Valo static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
176858619b14SKalle Valo {
176958619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
177058619b14SKalle Valo u16 buf[64];
1771d5a43355SPriit Laes int i, samples = 0, theta = 0;
177258619b14SKalle Valo int rotation = (((36 * freq) / 20) << 16) / 100;
1773d5a43355SPriit Laes struct cordic_iq sample;
177458619b14SKalle Valo
177558619b14SKalle Valo lpphy->tx_tone_freq = freq;
177658619b14SKalle Valo
177758619b14SKalle Valo if (freq) {
177858619b14SKalle Valo /* Find i for which abs(freq) integrally divides 20000 * i */
177958619b14SKalle Valo for (i = 1; samples * abs(freq) != 20000 * i; i++) {
178058619b14SKalle Valo samples = (20000 * i) / abs(freq);
178158619b14SKalle Valo if(B43_WARN_ON(samples > 63))
178258619b14SKalle Valo return;
178358619b14SKalle Valo }
178458619b14SKalle Valo } else {
178558619b14SKalle Valo samples = 2;
178658619b14SKalle Valo }
178758619b14SKalle Valo
178858619b14SKalle Valo for (i = 0; i < samples; i++) {
1789d5a43355SPriit Laes sample = cordic_calc_iq(CORDIC_FIXED(theta));
1790d5a43355SPriit Laes theta += rotation;
1791d5a43355SPriit Laes buf[i] = CORDIC_FLOAT((sample.i * max) & 0xFF) << 8;
1792d5a43355SPriit Laes buf[i] |= CORDIC_FLOAT((sample.q * max) & 0xFF);
179358619b14SKalle Valo }
179458619b14SKalle Valo
179558619b14SKalle Valo b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
179658619b14SKalle Valo
179758619b14SKalle Valo lpphy_run_samples(dev, samples, 0xFFFF, 0);
179858619b14SKalle Valo }
179958619b14SKalle Valo
lpphy_stop_tx_tone(struct b43_wldev * dev)180058619b14SKalle Valo static void lpphy_stop_tx_tone(struct b43_wldev *dev)
180158619b14SKalle Valo {
180258619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
180358619b14SKalle Valo int i;
180458619b14SKalle Valo
180558619b14SKalle Valo lpphy->tx_tone_freq = 0;
180658619b14SKalle Valo
180758619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000);
180858619b14SKalle Valo for (i = 0; i < 31; i++) {
180958619b14SKalle Valo if (!(b43_phy_read(dev, B43_LPPHY_A_PHY_CTL_ADDR) & 0x1))
181058619b14SKalle Valo break;
181158619b14SKalle Valo udelay(100);
181258619b14SKalle Valo }
181358619b14SKalle Valo }
181458619b14SKalle Valo
181558619b14SKalle Valo
lpphy_papd_cal_txpwr(struct b43_wldev * dev)181658619b14SKalle Valo static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
181758619b14SKalle Valo {
181858619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
1819d825db34SArnd Bergmann struct lpphy_tx_gains oldgains;
182058619b14SKalle Valo int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
182158619b14SKalle Valo
182258619b14SKalle Valo lpphy_read_tx_pctl_mode_from_hardware(dev);
182358619b14SKalle Valo old_txpctl = lpphy->txpctl_mode;
182458619b14SKalle Valo old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
182558619b14SKalle Valo if (old_afe_ovr)
182658619b14SKalle Valo oldgains = lpphy_get_tx_gains(dev);
182758619b14SKalle Valo old_rf = b43_phy_read(dev, B43_LPPHY_RF_PWR_OVERRIDE) & 0xFF;
182858619b14SKalle Valo old_bbmult = lpphy_get_bb_mult(dev);
182958619b14SKalle Valo
183058619b14SKalle Valo lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
183158619b14SKalle Valo
183258619b14SKalle Valo if (old_afe_ovr)
183358619b14SKalle Valo lpphy_set_tx_gains(dev, oldgains);
183458619b14SKalle Valo lpphy_set_bb_mult(dev, old_bbmult);
183558619b14SKalle Valo lpphy_set_tx_power_control(dev, old_txpctl);
183658619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00, old_rf);
183758619b14SKalle Valo }
183858619b14SKalle Valo
lpphy_rx_iq_cal(struct b43_wldev * dev,bool noise,bool tx,bool rx,bool pa,struct lpphy_tx_gains * gains)183958619b14SKalle Valo static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
184058619b14SKalle Valo bool rx, bool pa, struct lpphy_tx_gains *gains)
184158619b14SKalle Valo {
184258619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
184358619b14SKalle Valo const struct lpphy_rx_iq_comp *iqcomp = NULL;
184458619b14SKalle Valo struct lpphy_tx_gains nogains, oldgains;
184558619b14SKalle Valo u16 tmp;
184658619b14SKalle Valo int i, ret;
184758619b14SKalle Valo
184858619b14SKalle Valo memset(&nogains, 0, sizeof(nogains));
184958619b14SKalle Valo memset(&oldgains, 0, sizeof(oldgains));
185058619b14SKalle Valo
185158619b14SKalle Valo if (dev->dev->chip_id == 0x5354) {
185258619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
185358619b14SKalle Valo if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
185458619b14SKalle Valo iqcomp = &lpphy_5354_iq_table[i];
185558619b14SKalle Valo }
185658619b14SKalle Valo }
185758619b14SKalle Valo } else if (dev->phy.rev >= 2) {
185858619b14SKalle Valo iqcomp = &lpphy_rev2plus_iq_comp;
185958619b14SKalle Valo } else {
186058619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(lpphy_rev0_1_iq_table); i++) {
186158619b14SKalle Valo if (lpphy_rev0_1_iq_table[i].chan == lpphy->channel) {
186258619b14SKalle Valo iqcomp = &lpphy_rev0_1_iq_table[i];
186358619b14SKalle Valo }
186458619b14SKalle Valo }
186558619b14SKalle Valo }
186658619b14SKalle Valo
186758619b14SKalle Valo if (B43_WARN_ON(!iqcomp))
186858619b14SKalle Valo return 0;
186958619b14SKalle Valo
187058619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, iqcomp->c1);
187158619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S,
187258619b14SKalle Valo 0x00FF, iqcomp->c0 << 8);
187358619b14SKalle Valo
187458619b14SKalle Valo if (noise) {
187558619b14SKalle Valo tx = true;
187658619b14SKalle Valo rx = false;
187758619b14SKalle Valo pa = false;
187858619b14SKalle Valo }
187958619b14SKalle Valo
188058619b14SKalle Valo lpphy_set_trsw_over(dev, tx, rx);
188158619b14SKalle Valo
188257fbcce3SJohannes Berg if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
188358619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
188458619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
188558619b14SKalle Valo 0xFFF7, pa << 3);
188658619b14SKalle Valo } else {
188758619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
188858619b14SKalle Valo b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
188958619b14SKalle Valo 0xFFDF, pa << 5);
189058619b14SKalle Valo }
189158619b14SKalle Valo
189258619b14SKalle Valo tmp = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
189358619b14SKalle Valo
189458619b14SKalle Valo if (noise)
189558619b14SKalle Valo lpphy_set_rx_gain(dev, 0x2D5D);
189658619b14SKalle Valo else {
189758619b14SKalle Valo if (tmp)
189858619b14SKalle Valo oldgains = lpphy_get_tx_gains(dev);
189958619b14SKalle Valo if (!gains)
190058619b14SKalle Valo gains = &nogains;
190158619b14SKalle Valo lpphy_set_tx_gains(dev, *gains);
190258619b14SKalle Valo }
190358619b14SKalle Valo
190458619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
190558619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
190658619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
190758619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
190858619b14SKalle Valo lpphy_set_deaf(dev, false);
190958619b14SKalle Valo if (noise)
191058619b14SKalle Valo ret = lpphy_calc_rx_iq_comp(dev, 0xFFF0);
191158619b14SKalle Valo else {
191258619b14SKalle Valo lpphy_start_tx_tone(dev, 4000, 100);
191358619b14SKalle Valo ret = lpphy_calc_rx_iq_comp(dev, 0x4000);
191458619b14SKalle Valo lpphy_stop_tx_tone(dev);
191558619b14SKalle Valo }
191658619b14SKalle Valo lpphy_clear_deaf(dev, false);
191758619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFC);
191858619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
191958619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFDF);
192058619b14SKalle Valo if (!noise) {
192158619b14SKalle Valo if (tmp)
192258619b14SKalle Valo lpphy_set_tx_gains(dev, oldgains);
192358619b14SKalle Valo else
192458619b14SKalle Valo lpphy_disable_tx_gain_override(dev);
192558619b14SKalle Valo }
192658619b14SKalle Valo lpphy_disable_rx_gain_override(dev);
192758619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
192858619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xF7FF);
192958619b14SKalle Valo return ret;
193058619b14SKalle Valo }
193158619b14SKalle Valo
lpphy_calibration(struct b43_wldev * dev)193258619b14SKalle Valo static void lpphy_calibration(struct b43_wldev *dev)
193358619b14SKalle Valo {
193458619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
193558619b14SKalle Valo enum b43_lpphy_txpctl_mode saved_pctl_mode;
193658619b14SKalle Valo bool full_cal = false;
193758619b14SKalle Valo
193858619b14SKalle Valo if (lpphy->full_calib_chan != lpphy->channel) {
193958619b14SKalle Valo full_cal = true;
194058619b14SKalle Valo lpphy->full_calib_chan = lpphy->channel;
194158619b14SKalle Valo }
194258619b14SKalle Valo
194358619b14SKalle Valo b43_mac_suspend(dev);
194458619b14SKalle Valo
194558619b14SKalle Valo lpphy_btcoex_override(dev);
194658619b14SKalle Valo if (dev->phy.rev >= 2)
194758619b14SKalle Valo lpphy_save_dig_flt_state(dev);
194858619b14SKalle Valo lpphy_read_tx_pctl_mode_from_hardware(dev);
194958619b14SKalle Valo saved_pctl_mode = lpphy->txpctl_mode;
195058619b14SKalle Valo lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
195158619b14SKalle Valo //TODO Perform transmit power table I/Q LO calibration
195258619b14SKalle Valo if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
195358619b14SKalle Valo lpphy_pr41573_workaround(dev);
195458619b14SKalle Valo if ((dev->phy.rev >= 2) && full_cal) {
195558619b14SKalle Valo lpphy_papd_cal_txpwr(dev);
195658619b14SKalle Valo }
195758619b14SKalle Valo lpphy_set_tx_power_control(dev, saved_pctl_mode);
195858619b14SKalle Valo if (dev->phy.rev >= 2)
195958619b14SKalle Valo lpphy_restore_dig_flt_state(dev);
196058619b14SKalle Valo lpphy_rx_iq_cal(dev, true, true, false, false, NULL);
196158619b14SKalle Valo
196258619b14SKalle Valo b43_mac_enable(dev);
196358619b14SKalle Valo }
196458619b14SKalle Valo
b43_lpphy_op_maskset(struct b43_wldev * dev,u16 reg,u16 mask,u16 set)196558619b14SKalle Valo static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
196658619b14SKalle Valo u16 set)
196758619b14SKalle Valo {
196858619b14SKalle Valo b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
196958619b14SKalle Valo b43_write16(dev, B43_MMIO_PHY_DATA,
197058619b14SKalle Valo (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
197158619b14SKalle Valo }
197258619b14SKalle Valo
b43_lpphy_op_radio_read(struct b43_wldev * dev,u16 reg)197358619b14SKalle Valo static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
197458619b14SKalle Valo {
197558619b14SKalle Valo /* Register 1 is a 32-bit register. */
197658619b14SKalle Valo B43_WARN_ON(reg == 1);
197758619b14SKalle Valo /* LP-PHY needs a special bit set for read access */
197858619b14SKalle Valo if (dev->phy.rev < 2) {
197958619b14SKalle Valo if (reg != 0x4001)
198058619b14SKalle Valo reg |= 0x100;
198158619b14SKalle Valo } else
198258619b14SKalle Valo reg |= 0x200;
198358619b14SKalle Valo
198458619b14SKalle Valo b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
198558619b14SKalle Valo return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
198658619b14SKalle Valo }
198758619b14SKalle Valo
b43_lpphy_op_radio_write(struct b43_wldev * dev,u16 reg,u16 value)198858619b14SKalle Valo static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
198958619b14SKalle Valo {
199058619b14SKalle Valo /* Register 1 is a 32-bit register. */
199158619b14SKalle Valo B43_WARN_ON(reg == 1);
199258619b14SKalle Valo
199358619b14SKalle Valo b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
199458619b14SKalle Valo b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
199558619b14SKalle Valo }
199658619b14SKalle Valo
199758619b14SKalle Valo struct b206x_channel {
199858619b14SKalle Valo u8 channel;
199958619b14SKalle Valo u16 freq;
200058619b14SKalle Valo u8 data[12];
200158619b14SKalle Valo };
200258619b14SKalle Valo
200358619b14SKalle Valo static const struct b206x_channel b2062_chantbl[] = {
200458619b14SKalle Valo { .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF,
200558619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
200658619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
200758619b14SKalle Valo { .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF,
200858619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
200958619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
201058619b14SKalle Valo { .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF,
201158619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
201258619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
201358619b14SKalle Valo { .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF,
201458619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
201558619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
201658619b14SKalle Valo { .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF,
201758619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
201858619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
201958619b14SKalle Valo { .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF,
202058619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
202158619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
202258619b14SKalle Valo { .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF,
202358619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
202458619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
202558619b14SKalle Valo { .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF,
202658619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
202758619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
202858619b14SKalle Valo { .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF,
202958619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
203058619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
203158619b14SKalle Valo { .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF,
203258619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
203358619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
203458619b14SKalle Valo { .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF,
203558619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
203658619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
203758619b14SKalle Valo { .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF,
203858619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
203958619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
204058619b14SKalle Valo { .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF,
204158619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
204258619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
204358619b14SKalle Valo { .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF,
204458619b14SKalle Valo .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
204558619b14SKalle Valo .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
204658619b14SKalle Valo { .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22,
204758619b14SKalle Valo .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
204858619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
204958619b14SKalle Valo { .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11,
205058619b14SKalle Valo .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
205158619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
205258619b14SKalle Valo { .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11,
205358619b14SKalle Valo .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
205458619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
205558619b14SKalle Valo { .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00,
205658619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
205758619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
205858619b14SKalle Valo { .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11,
205958619b14SKalle Valo .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
206058619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
206158619b14SKalle Valo { .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11,
206258619b14SKalle Valo .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
206358619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
206458619b14SKalle Valo { .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11,
206558619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
206658619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
206758619b14SKalle Valo { .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00,
206858619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
206958619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
207058619b14SKalle Valo { .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00,
207158619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
207258619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
207358619b14SKalle Valo { .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00,
207458619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
207558619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
207658619b14SKalle Valo { .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00,
207758619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77,
207858619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
207958619b14SKalle Valo { .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00,
208058619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77,
208158619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
208258619b14SKalle Valo { .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00,
208358619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77,
208458619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
208558619b14SKalle Valo { .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00,
208658619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
208758619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
208858619b14SKalle Valo { .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00,
208958619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
209058619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
209158619b14SKalle Valo { .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00,
209258619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
209358619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
209458619b14SKalle Valo { .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00,
209558619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77,
209658619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
209758619b14SKalle Valo { .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00,
209858619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
209958619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
210058619b14SKalle Valo { .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00,
210158619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
210258619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
210358619b14SKalle Valo { .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00,
210458619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
210558619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
210658619b14SKalle Valo { .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00,
210758619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
210858619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
210958619b14SKalle Valo { .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00,
211058619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
211158619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
211258619b14SKalle Valo { .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00,
211358619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
211458619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
211558619b14SKalle Valo { .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00,
211658619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
211758619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
211858619b14SKalle Valo { .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00,
211958619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
212058619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
212158619b14SKalle Valo { .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00,
212258619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
212358619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
212458619b14SKalle Valo { .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00,
212558619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
212658619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
212758619b14SKalle Valo { .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00,
212858619b14SKalle Valo .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
212958619b14SKalle Valo .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
213058619b14SKalle Valo { .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77,
213158619b14SKalle Valo .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77,
213258619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
213358619b14SKalle Valo { .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77,
213458619b14SKalle Valo .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
213558619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
213658619b14SKalle Valo { .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66,
213758619b14SKalle Valo .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
213858619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
213958619b14SKalle Valo { .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66,
214058619b14SKalle Valo .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
214158619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
214258619b14SKalle Valo { .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55,
214358619b14SKalle Valo .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77,
214458619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
214558619b14SKalle Valo { .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55,
214658619b14SKalle Valo .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
214758619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
214858619b14SKalle Valo { .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44,
214958619b14SKalle Valo .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
215058619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
215158619b14SKalle Valo { .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44,
215258619b14SKalle Valo .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77,
215358619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
215458619b14SKalle Valo { .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44,
215558619b14SKalle Valo .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77,
215658619b14SKalle Valo .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
215758619b14SKalle Valo };
215858619b14SKalle Valo
215958619b14SKalle Valo static const struct b206x_channel b2063_chantbl[] = {
216058619b14SKalle Valo { .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C,
216158619b14SKalle Valo .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
216258619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
216358619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
216458619b14SKalle Valo { .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C,
216558619b14SKalle Valo .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
216658619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
216758619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
216858619b14SKalle Valo { .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C,
216958619b14SKalle Valo .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
217058619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
217158619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
217258619b14SKalle Valo { .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C,
217358619b14SKalle Valo .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
217458619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
217558619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
217658619b14SKalle Valo { .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C,
217758619b14SKalle Valo .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
217858619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
217958619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
218058619b14SKalle Valo { .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C,
218158619b14SKalle Valo .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
218258619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
218358619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
218458619b14SKalle Valo { .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C,
218558619b14SKalle Valo .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
218658619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
218758619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
218858619b14SKalle Valo { .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C,
218958619b14SKalle Valo .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
219058619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
219158619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
219258619b14SKalle Valo { .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C,
219358619b14SKalle Valo .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
219458619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
219558619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
219658619b14SKalle Valo { .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C,
219758619b14SKalle Valo .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
219858619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
219958619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
220058619b14SKalle Valo { .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C,
220158619b14SKalle Valo .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
220258619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
220358619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
220458619b14SKalle Valo { .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C,
220558619b14SKalle Valo .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
220658619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
220758619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
220858619b14SKalle Valo { .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C,
220958619b14SKalle Valo .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
221058619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
221158619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
221258619b14SKalle Valo { .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C,
221358619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
221458619b14SKalle Valo .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
221558619b14SKalle Valo .data[10] = 0x80, .data[11] = 0x70, },
221658619b14SKalle Valo { .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C,
221758619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05,
221858619b14SKalle Valo .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80,
221958619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
222058619b14SKalle Valo { .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C,
222158619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05,
222258619b14SKalle Valo .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
222358619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
222458619b14SKalle Valo { .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C,
222558619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
222658619b14SKalle Valo .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
222758619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
222858619b14SKalle Valo { .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C,
222958619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
223058619b14SKalle Valo .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
223158619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
223258619b14SKalle Valo { .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C,
223358619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
223458619b14SKalle Valo .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
223558619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
223658619b14SKalle Valo { .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C,
223758619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04,
223858619b14SKalle Valo .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
223958619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
224058619b14SKalle Valo { .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C,
224158619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
224258619b14SKalle Valo .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
224358619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
224458619b14SKalle Valo { .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C,
224558619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
224658619b14SKalle Valo .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60,
224758619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
224858619b14SKalle Valo { .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C,
224958619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02,
225058619b14SKalle Valo .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60,
225158619b14SKalle Valo .data[10] = 0x20, .data[11] = 0x00, },
225258619b14SKalle Valo { .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C,
225358619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
225458619b14SKalle Valo .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
225558619b14SKalle Valo .data[10] = 0x10, .data[11] = 0x00, },
225658619b14SKalle Valo { .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C,
225758619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
225858619b14SKalle Valo .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
225958619b14SKalle Valo .data[10] = 0x10, .data[11] = 0x00, },
226058619b14SKalle Valo { .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C,
226158619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
226258619b14SKalle Valo .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
226358619b14SKalle Valo .data[10] = 0x10, .data[11] = 0x00, },
226458619b14SKalle Valo { .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C,
226558619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
226658619b14SKalle Valo .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
226758619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
226858619b14SKalle Valo { .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C,
226958619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
227058619b14SKalle Valo .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
227158619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
227258619b14SKalle Valo { .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C,
227358619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
227458619b14SKalle Valo .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
227558619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
227658619b14SKalle Valo { .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C,
227758619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
227858619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
227958619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
228058619b14SKalle Valo { .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C,
228158619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
228258619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
228358619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
228458619b14SKalle Valo { .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C,
228558619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
228658619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
228758619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
228858619b14SKalle Valo { .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C,
228958619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
229058619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
229158619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
229258619b14SKalle Valo { .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C,
229358619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
229458619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
229558619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
229658619b14SKalle Valo { .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C,
229758619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
229858619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
229958619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
230058619b14SKalle Valo { .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C,
230158619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
230258619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
230358619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
230458619b14SKalle Valo { .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C,
230558619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
230658619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
230758619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
230858619b14SKalle Valo { .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C,
230958619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
231058619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
231158619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
231258619b14SKalle Valo { .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C,
231358619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
231458619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
231558619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
231658619b14SKalle Valo { .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C,
231758619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
231858619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
231958619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
232058619b14SKalle Valo { .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C,
232158619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
232258619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
232358619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
232458619b14SKalle Valo { .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C,
232558619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
232658619b14SKalle Valo .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
232758619b14SKalle Valo .data[10] = 0x00, .data[11] = 0x00, },
232858619b14SKalle Valo { .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C,
232958619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E,
233058619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0,
233158619b14SKalle Valo .data[10] = 0x50, .data[11] = 0x00, },
233258619b14SKalle Valo { .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C,
233358619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D,
233458619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
233558619b14SKalle Valo .data[10] = 0x50, .data[11] = 0x00, },
233658619b14SKalle Valo { .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C,
233758619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
233858619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
233958619b14SKalle Valo .data[10] = 0x50, .data[11] = 0x00, },
234058619b14SKalle Valo { .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C,
234158619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
234258619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
234358619b14SKalle Valo .data[10] = 0x40, .data[11] = 0x00, },
234458619b14SKalle Valo { .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C,
234558619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B,
234658619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
234758619b14SKalle Valo .data[10] = 0x40, .data[11] = 0x00, },
234858619b14SKalle Valo { .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C,
234958619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A,
235058619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
235158619b14SKalle Valo .data[10] = 0x40, .data[11] = 0x00, },
235258619b14SKalle Valo { .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C,
235358619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09,
235458619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
235558619b14SKalle Valo .data[10] = 0x40, .data[11] = 0x00, },
235658619b14SKalle Valo { .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C,
235758619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08,
235858619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
235958619b14SKalle Valo .data[10] = 0x40, .data[11] = 0x00, },
236058619b14SKalle Valo { .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C,
236158619b14SKalle Valo .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08,
236258619b14SKalle Valo .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
236358619b14SKalle Valo .data[10] = 0x40, .data[11] = 0x00, },
236458619b14SKalle Valo };
236558619b14SKalle Valo
lpphy_b2062_reset_pll_bias(struct b43_wldev * dev)236658619b14SKalle Valo static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
236758619b14SKalle Valo {
236858619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
236958619b14SKalle Valo udelay(20);
237058619b14SKalle Valo if (dev->dev->chip_id == 0x5354) {
237158619b14SKalle Valo b43_radio_write(dev, B2062_N_COMM1, 4);
237258619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4);
237358619b14SKalle Valo } else {
237458619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0);
237558619b14SKalle Valo }
237658619b14SKalle Valo udelay(5);
237758619b14SKalle Valo }
237858619b14SKalle Valo
lpphy_b2062_vco_calib(struct b43_wldev * dev)237958619b14SKalle Valo static void lpphy_b2062_vco_calib(struct b43_wldev *dev)
238058619b14SKalle Valo {
238158619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x42);
238258619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x62);
238358619b14SKalle Valo udelay(200);
238458619b14SKalle Valo }
238558619b14SKalle Valo
lpphy_b2062_tune(struct b43_wldev * dev,unsigned int channel)238658619b14SKalle Valo static int lpphy_b2062_tune(struct b43_wldev *dev,
238758619b14SKalle Valo unsigned int channel)
238858619b14SKalle Valo {
238958619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
239058619b14SKalle Valo struct ssb_bus *bus = dev->dev->sdev->bus;
239158619b14SKalle Valo const struct b206x_channel *chandata = NULL;
239258619b14SKalle Valo u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
239358619b14SKalle Valo u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
239458619b14SKalle Valo int i, err = 0;
239558619b14SKalle Valo
239658619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) {
239758619b14SKalle Valo if (b2062_chantbl[i].channel == channel) {
239858619b14SKalle Valo chandata = &b2062_chantbl[i];
239958619b14SKalle Valo break;
240058619b14SKalle Valo }
240158619b14SKalle Valo }
240258619b14SKalle Valo
240358619b14SKalle Valo if (B43_WARN_ON(!chandata))
240458619b14SKalle Valo return -EINVAL;
240558619b14SKalle Valo
240658619b14SKalle Valo b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04);
240758619b14SKalle Valo b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]);
240858619b14SKalle Valo b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]);
240958619b14SKalle Valo b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]);
241058619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]);
241158619b14SKalle Valo b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]);
241258619b14SKalle Valo b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]);
241358619b14SKalle Valo b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]);
241458619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]);
241558619b14SKalle Valo b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]);
241658619b14SKalle Valo
241758619b14SKalle Valo tmp1 = crystal_freq / 1000;
241858619b14SKalle Valo tmp2 = lpphy->pdiv * 1000;
241958619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC);
242058619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07);
242158619b14SKalle Valo lpphy_b2062_reset_pll_bias(dev);
242258619b14SKalle Valo tmp3 = tmp2 * channel2freq_lp(channel);
242358619b14SKalle Valo if (channel2freq_lp(channel) < 4000)
242458619b14SKalle Valo tmp3 *= 2;
242558619b14SKalle Valo tmp4 = 48 * tmp1;
242658619b14SKalle Valo tmp6 = tmp3 / tmp4;
242758619b14SKalle Valo tmp7 = tmp3 % tmp4;
242858619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6);
242958619b14SKalle Valo tmp5 = tmp7 * 0x100;
243058619b14SKalle Valo tmp6 = tmp5 / tmp4;
243158619b14SKalle Valo tmp7 = tmp5 % tmp4;
243258619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6);
243358619b14SKalle Valo tmp5 = tmp7 * 0x100;
243458619b14SKalle Valo tmp6 = tmp5 / tmp4;
243558619b14SKalle Valo tmp7 = tmp5 % tmp4;
243658619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6);
243758619b14SKalle Valo tmp5 = tmp7 * 0x100;
243858619b14SKalle Valo tmp6 = tmp5 / tmp4;
243958619b14SKalle Valo tmp7 = tmp5 % tmp4;
244058619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
244158619b14SKalle Valo tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19);
244258619b14SKalle Valo tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
244358619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16);
244458619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
244558619b14SKalle Valo
244658619b14SKalle Valo lpphy_b2062_vco_calib(dev);
244758619b14SKalle Valo if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) {
244858619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC);
244958619b14SKalle Valo b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0);
245058619b14SKalle Valo lpphy_b2062_reset_pll_bias(dev);
245158619b14SKalle Valo lpphy_b2062_vco_calib(dev);
245258619b14SKalle Valo if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10)
245358619b14SKalle Valo err = -EIO;
245458619b14SKalle Valo }
245558619b14SKalle Valo
245658619b14SKalle Valo b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04);
245758619b14SKalle Valo return err;
245858619b14SKalle Valo }
245958619b14SKalle Valo
lpphy_b2063_vco_calib(struct b43_wldev * dev)246058619b14SKalle Valo static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
246158619b14SKalle Valo {
246258619b14SKalle Valo u16 tmp;
246358619b14SKalle Valo
246458619b14SKalle Valo b43_radio_mask(dev, B2063_PLL_SP1, ~0x40);
246558619b14SKalle Valo tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
246658619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp);
246758619b14SKalle Valo udelay(1);
246858619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
246958619b14SKalle Valo udelay(1);
247058619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
247158619b14SKalle Valo udelay(1);
247258619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
247358619b14SKalle Valo udelay(300);
247458619b14SKalle Valo b43_radio_set(dev, B2063_PLL_SP1, 0x40);
247558619b14SKalle Valo }
247658619b14SKalle Valo
lpphy_b2063_tune(struct b43_wldev * dev,unsigned int channel)247758619b14SKalle Valo static int lpphy_b2063_tune(struct b43_wldev *dev,
247858619b14SKalle Valo unsigned int channel)
247958619b14SKalle Valo {
248058619b14SKalle Valo struct ssb_bus *bus = dev->dev->sdev->bus;
248158619b14SKalle Valo
248258619b14SKalle Valo static const struct b206x_channel *chandata = NULL;
248358619b14SKalle Valo u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
248458619b14SKalle Valo u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count;
248558619b14SKalle Valo u16 old_comm15, scale;
248658619b14SKalle Valo u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
248758619b14SKalle Valo int i, div = (crystal_freq <= 26000000 ? 1 : 2);
248858619b14SKalle Valo
248958619b14SKalle Valo for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) {
249058619b14SKalle Valo if (b2063_chantbl[i].channel == channel) {
249158619b14SKalle Valo chandata = &b2063_chantbl[i];
249258619b14SKalle Valo break;
249358619b14SKalle Valo }
249458619b14SKalle Valo }
249558619b14SKalle Valo
249658619b14SKalle Valo if (B43_WARN_ON(!chandata))
249758619b14SKalle Valo return -EINVAL;
249858619b14SKalle Valo
249958619b14SKalle Valo b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]);
250058619b14SKalle Valo b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]);
250158619b14SKalle Valo b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]);
250258619b14SKalle Valo b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]);
250358619b14SKalle Valo b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]);
250458619b14SKalle Valo b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]);
250558619b14SKalle Valo b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]);
250658619b14SKalle Valo b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]);
250758619b14SKalle Valo b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]);
250858619b14SKalle Valo b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]);
250958619b14SKalle Valo b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]);
251058619b14SKalle Valo b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]);
251158619b14SKalle Valo
251258619b14SKalle Valo old_comm15 = b43_radio_read(dev, B2063_COMM15);
251358619b14SKalle Valo b43_radio_set(dev, B2063_COMM15, 0x1E);
251458619b14SKalle Valo
251558619b14SKalle Valo if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */
251658619b14SKalle Valo vco_freq = chandata->freq << 1;
251758619b14SKalle Valo else
251858619b14SKalle Valo vco_freq = chandata->freq << 2;
251958619b14SKalle Valo
252058619b14SKalle Valo freqref = crystal_freq * 3;
252158619b14SKalle Valo val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16);
252258619b14SKalle Valo val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16);
252358619b14SKalle Valo val3 = lpphy_qdiv_roundup(vco_freq, 3, 16);
252458619b14SKalle Valo timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1;
252558619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2);
252658619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6,
252758619b14SKalle Valo 0xFFF8, timeout >> 2);
252858619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
252958619b14SKalle Valo 0xFF9F,timeout << 5);
253058619b14SKalle Valo
253158619b14SKalle Valo timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) +
253258619b14SKalle Valo 999999) / 1000000) + 1;
253358619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref);
253458619b14SKalle Valo
253558619b14SKalle Valo count = lpphy_qdiv_roundup(val3, val2 + 16, 16);
253658619b14SKalle Valo count *= (timeout + 1) * (timeoutref + 1);
253758619b14SKalle Valo count--;
253858619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
253958619b14SKalle Valo 0xF0, count >> 8);
254058619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF);
254158619b14SKalle Valo
254258619b14SKalle Valo tmp1 = ((val3 * 62500) / freqref) << 4;
254358619b14SKalle Valo tmp2 = ((val3 * 62500) % freqref) << 4;
254458619b14SKalle Valo while (tmp2 >= freqref) {
254558619b14SKalle Valo tmp1++;
254658619b14SKalle Valo tmp2 -= freqref;
254758619b14SKalle Valo }
254858619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4);
254958619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4);
255058619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16);
255158619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF);
255258619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF);
255358619b14SKalle Valo
255458619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9);
255558619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88);
255658619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28);
255758619b14SKalle Valo b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63);
255858619b14SKalle Valo
255958619b14SKalle Valo tmp3 = ((41 * (val3 - 3000)) /1200) + 27;
256058619b14SKalle Valo tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16);
256158619b14SKalle Valo
256258619b14SKalle Valo if ((tmp4 + tmp3 - 1) / tmp3 > 60) {
256358619b14SKalle Valo scale = 1;
256458619b14SKalle Valo tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8;
256558619b14SKalle Valo } else {
256658619b14SKalle Valo scale = 0;
256758619b14SKalle Valo tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8;
256858619b14SKalle Valo }
256958619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
257058619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
257158619b14SKalle Valo
257258619b14SKalle Valo tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16);
257358619b14SKalle Valo tmp6 *= (tmp5 * 8) * (scale + 1);
257458619b14SKalle Valo if (tmp6 > 150)
257558619b14SKalle Valo tmp6 = 0;
257658619b14SKalle Valo
257758619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
257858619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
257958619b14SKalle Valo
258058619b14SKalle Valo b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
258158619b14SKalle Valo if (crystal_freq > 26000000)
258258619b14SKalle Valo b43_radio_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2);
258358619b14SKalle Valo else
258458619b14SKalle Valo b43_radio_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD);
258558619b14SKalle Valo
258658619b14SKalle Valo if (val1 == 45)
258758619b14SKalle Valo b43_radio_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2);
258858619b14SKalle Valo else
258958619b14SKalle Valo b43_radio_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD);
259058619b14SKalle Valo
259158619b14SKalle Valo b43_radio_set(dev, B2063_PLL_SP2, 0x3);
259258619b14SKalle Valo udelay(1);
259358619b14SKalle Valo b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC);
259458619b14SKalle Valo lpphy_b2063_vco_calib(dev);
259558619b14SKalle Valo b43_radio_write(dev, B2063_COMM15, old_comm15);
259658619b14SKalle Valo
259758619b14SKalle Valo return 0;
259858619b14SKalle Valo }
259958619b14SKalle Valo
b43_lpphy_op_switch_channel(struct b43_wldev * dev,unsigned int new_channel)260058619b14SKalle Valo static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
260158619b14SKalle Valo unsigned int new_channel)
260258619b14SKalle Valo {
260358619b14SKalle Valo struct b43_phy_lp *lpphy = dev->phy.lp;
260458619b14SKalle Valo int err;
260558619b14SKalle Valo
260658619b14SKalle Valo if (dev->phy.radio_ver == 0x2063) {
260758619b14SKalle Valo err = lpphy_b2063_tune(dev, new_channel);
260858619b14SKalle Valo if (err)
260958619b14SKalle Valo return err;
261058619b14SKalle Valo } else {
261158619b14SKalle Valo err = lpphy_b2062_tune(dev, new_channel);
261258619b14SKalle Valo if (err)
261358619b14SKalle Valo return err;
261458619b14SKalle Valo lpphy_set_analog_filter(dev, new_channel);
261558619b14SKalle Valo lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));
261658619b14SKalle Valo }
261758619b14SKalle Valo
261858619b14SKalle Valo lpphy->channel = new_channel;
261958619b14SKalle Valo b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
262058619b14SKalle Valo
262158619b14SKalle Valo return 0;
262258619b14SKalle Valo }
262358619b14SKalle Valo
b43_lpphy_op_init(struct b43_wldev * dev)262458619b14SKalle Valo static int b43_lpphy_op_init(struct b43_wldev *dev)
262558619b14SKalle Valo {
262658619b14SKalle Valo int err;
262758619b14SKalle Valo
262858619b14SKalle Valo if (dev->dev->bus_type != B43_BUS_SSB) {
262958619b14SKalle Valo b43err(dev->wl, "LP-PHY is supported only on SSB!\n");
263058619b14SKalle Valo return -EOPNOTSUPP;
263158619b14SKalle Valo }
263258619b14SKalle Valo
263358619b14SKalle Valo lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
263458619b14SKalle Valo lpphy_baseband_init(dev);
263558619b14SKalle Valo lpphy_radio_init(dev);
263658619b14SKalle Valo lpphy_calibrate_rc(dev);
263758619b14SKalle Valo err = b43_lpphy_op_switch_channel(dev, 7);
263858619b14SKalle Valo if (err) {
263958619b14SKalle Valo b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n",
264058619b14SKalle Valo err);
264158619b14SKalle Valo }
264258619b14SKalle Valo lpphy_tx_pctl_init(dev);
264358619b14SKalle Valo lpphy_calibration(dev);
264458619b14SKalle Valo //TODO ACI init
264558619b14SKalle Valo
264658619b14SKalle Valo return 0;
264758619b14SKalle Valo }
264858619b14SKalle Valo
b43_lpphy_op_adjust_txpower(struct b43_wldev * dev)264958619b14SKalle Valo static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
265058619b14SKalle Valo {
265158619b14SKalle Valo //TODO
265258619b14SKalle Valo }
265358619b14SKalle Valo
b43_lpphy_op_recalc_txpower(struct b43_wldev * dev,bool ignore_tssi)265458619b14SKalle Valo static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
265558619b14SKalle Valo bool ignore_tssi)
265658619b14SKalle Valo {
265758619b14SKalle Valo //TODO
265858619b14SKalle Valo return B43_TXPWR_RES_DONE;
265958619b14SKalle Valo }
266058619b14SKalle Valo
b43_lpphy_op_switch_analog(struct b43_wldev * dev,bool on)266158619b14SKalle Valo static void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
266258619b14SKalle Valo {
266358619b14SKalle Valo if (on) {
266458619b14SKalle Valo b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
266558619b14SKalle Valo } else {
266658619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0x0007);
266758619b14SKalle Valo b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x0007);
266858619b14SKalle Valo }
266958619b14SKalle Valo }
267058619b14SKalle Valo
b43_lpphy_op_pwork_15sec(struct b43_wldev * dev)267158619b14SKalle Valo static void b43_lpphy_op_pwork_15sec(struct b43_wldev *dev)
267258619b14SKalle Valo {
267358619b14SKalle Valo //TODO
267458619b14SKalle Valo }
267558619b14SKalle Valo
267658619b14SKalle Valo const struct b43_phy_operations b43_phyops_lp = {
267758619b14SKalle Valo .allocate = b43_lpphy_op_allocate,
267858619b14SKalle Valo .free = b43_lpphy_op_free,
267958619b14SKalle Valo .prepare_structs = b43_lpphy_op_prepare_structs,
268058619b14SKalle Valo .init = b43_lpphy_op_init,
268158619b14SKalle Valo .phy_maskset = b43_lpphy_op_maskset,
268258619b14SKalle Valo .radio_read = b43_lpphy_op_radio_read,
268358619b14SKalle Valo .radio_write = b43_lpphy_op_radio_write,
268458619b14SKalle Valo .software_rfkill = b43_lpphy_op_software_rfkill,
268558619b14SKalle Valo .switch_analog = b43_lpphy_op_switch_analog,
268658619b14SKalle Valo .switch_channel = b43_lpphy_op_switch_channel,
268758619b14SKalle Valo .get_default_chan = b43_lpphy_op_get_default_chan,
268858619b14SKalle Valo .set_rx_antenna = b43_lpphy_op_set_rx_antenna,
268958619b14SKalle Valo .recalc_txpower = b43_lpphy_op_recalc_txpower,
269058619b14SKalle Valo .adjust_txpower = b43_lpphy_op_adjust_txpower,
269158619b14SKalle Valo .pwork_15sec = b43_lpphy_op_pwork_15sec,
269258619b14SKalle Valo .pwork_60sec = lpphy_calibration,
269358619b14SKalle Valo };
2694