cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy_lp.c (98071B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3
      4  Broadcom B43 wireless driver
      5  IEEE 802.11a/g LP-PHY driver
      6
      7  Copyright (c) 2008-2009 Michael Buesch <m@bues.ch>
      8  Copyright (c) 2009 Gábor Stefanik <netrolller.3d@gmail.com>
      9
     10
     11*/
     12
     13#include <linux/cordic.h>
     14#include <linux/slab.h>
     15
     16#include "b43.h"
     17#include "main.h"
     18#include "phy_lp.h"
     19#include "phy_common.h"
     20#include "tables_lpphy.h"
     21
     22
     23static inline u16 channel2freq_lp(u8 channel)
     24{
     25	if (channel < 14)
     26		return (2407 + 5 * channel);
     27	else if (channel == 14)
     28		return 2484;
     29	else if (channel < 184)
     30		return (5000 + 5 * channel);
     31	else
     32		return (4000 + 5 * channel);
     33}
     34
     35static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
     36{
     37	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
     38		return 1;
     39	return 36;
     40}
     41
     42static int b43_lpphy_op_allocate(struct b43_wldev *dev)
     43{
     44	struct b43_phy_lp *lpphy;
     45
     46	lpphy = kzalloc(sizeof(*lpphy), GFP_KERNEL);
     47	if (!lpphy)
     48		return -ENOMEM;
     49	dev->phy.lp = lpphy;
     50
     51	return 0;
     52}
     53
     54static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
     55{
     56	struct b43_phy *phy = &dev->phy;
     57	struct b43_phy_lp *lpphy = phy->lp;
     58
     59	memset(lpphy, 0, sizeof(*lpphy));
     60	lpphy->antenna = B43_ANTENNA_DEFAULT;
     61
     62	//TODO
     63}
     64
     65static void b43_lpphy_op_free(struct b43_wldev *dev)
     66{
     67	struct b43_phy_lp *lpphy = dev->phy.lp;
     68
     69	kfree(lpphy);
     70	dev->phy.lp = NULL;
     71}
     72
     73/* https://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */
     74static void lpphy_read_band_sprom(struct b43_wldev *dev)
     75{
     76	struct ssb_sprom *sprom = dev->dev->bus_sprom;
     77	struct b43_phy_lp *lpphy = dev->phy.lp;
     78	u16 cckpo, maxpwr;
     79	u32 ofdmpo;
     80	int i;
     81
     82	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
     83		lpphy->tx_isolation_med_band = sprom->tri2g;
     84		lpphy->bx_arch = sprom->bxa2g;
     85		lpphy->rx_pwr_offset = sprom->rxpo2g;
     86		lpphy->rssi_vf = sprom->rssismf2g;
     87		lpphy->rssi_vc = sprom->rssismc2g;
     88		lpphy->rssi_gs = sprom->rssisav2g;
     89		lpphy->txpa[0] = sprom->pa0b0;
     90		lpphy->txpa[1] = sprom->pa0b1;
     91		lpphy->txpa[2] = sprom->pa0b2;
     92		maxpwr = sprom->maxpwr_bg;
     93		lpphy->max_tx_pwr_med_band = maxpwr;
     94		cckpo = sprom->cck2gpo;
     95		if (cckpo) {
     96			ofdmpo = sprom->ofdm2gpo;
     97			for (i = 0; i < 4; i++) {
     98				lpphy->tx_max_rate[i] =
     99					maxpwr - (ofdmpo & 0xF) * 2;
    100				ofdmpo >>= 4;
    101			}
    102			ofdmpo = sprom->ofdm2gpo;
    103			for (i = 4; i < 15; i++) {
    104				lpphy->tx_max_rate[i] =
    105					maxpwr - (ofdmpo & 0xF) * 2;
    106				ofdmpo >>= 4;
    107			}
    108		} else {
    109			u8 opo = sprom->opo;
    110			for (i = 0; i < 4; i++)
    111				lpphy->tx_max_rate[i] = maxpwr;
    112			for (i = 4; i < 15; i++)
    113				lpphy->tx_max_rate[i] = maxpwr - opo;
    114		}
    115	} else { /* 5GHz */
    116		lpphy->tx_isolation_low_band = sprom->tri5gl;
    117		lpphy->tx_isolation_med_band = sprom->tri5g;
    118		lpphy->tx_isolation_hi_band = sprom->tri5gh;
    119		lpphy->bx_arch = sprom->bxa5g;
    120		lpphy->rx_pwr_offset = sprom->rxpo5g;
    121		lpphy->rssi_vf = sprom->rssismf5g;
    122		lpphy->rssi_vc = sprom->rssismc5g;
    123		lpphy->rssi_gs = sprom->rssisav5g;
    124		lpphy->txpa[0] = sprom->pa1b0;
    125		lpphy->txpa[1] = sprom->pa1b1;
    126		lpphy->txpa[2] = sprom->pa1b2;
    127		lpphy->txpal[0] = sprom->pa1lob0;
    128		lpphy->txpal[1] = sprom->pa1lob1;
    129		lpphy->txpal[2] = sprom->pa1lob2;
    130		lpphy->txpah[0] = sprom->pa1hib0;
    131		lpphy->txpah[1] = sprom->pa1hib1;
    132		lpphy->txpah[2] = sprom->pa1hib2;
    133		maxpwr = sprom->maxpwr_al;
    134		ofdmpo = sprom->ofdm5glpo;
    135		lpphy->max_tx_pwr_low_band = maxpwr;
    136		for (i = 4; i < 12; i++) {
    137			lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2;
    138			ofdmpo >>= 4;
    139		}
    140		maxpwr = sprom->maxpwr_a;
    141		ofdmpo = sprom->ofdm5gpo;
    142		lpphy->max_tx_pwr_med_band = maxpwr;
    143		for (i = 4; i < 12; i++) {
    144			lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2;
    145			ofdmpo >>= 4;
    146		}
    147		maxpwr = sprom->maxpwr_ah;
    148		ofdmpo = sprom->ofdm5ghpo;
    149		lpphy->max_tx_pwr_hi_band = maxpwr;
    150		for (i = 4; i < 12; i++) {
    151			lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2;
    152			ofdmpo >>= 4;
    153		}
    154	}
    155}
    156
    157static void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq)
    158{
    159	struct b43_phy_lp *lpphy = dev->phy.lp;
    160	u16 temp[3];
    161	u16 isolation;
    162
    163	B43_WARN_ON(dev->phy.rev >= 2);
    164
    165	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
    166		isolation = lpphy->tx_isolation_med_band;
    167	else if (freq <= 5320)
    168		isolation = lpphy->tx_isolation_low_band;
    169	else if (freq <= 5700)
    170		isolation = lpphy->tx_isolation_med_band;
    171	else
    172		isolation = lpphy->tx_isolation_hi_band;
    173
    174	temp[0] = ((isolation - 26) / 12) << 12;
    175	temp[1] = temp[0] + 0x1000;
    176	temp[2] = temp[0] + 0x2000;
    177
    178	b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp);
    179	b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp);
    180}
    181
    182static void lpphy_table_init(struct b43_wldev *dev)
    183{
    184	u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev));
    185
    186	if (dev->phy.rev < 2)
    187		lpphy_rev0_1_table_init(dev);
    188	else
    189		lpphy_rev2plus_table_init(dev);
    190
    191	lpphy_init_tx_gain_table(dev);
    192
    193	if (dev->phy.rev < 2)
    194		lpphy_adjust_gain_table(dev, freq);
    195}
    196
    197static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
    198{
    199	struct ssb_bus *bus = dev->dev->sdev->bus;
    200	struct ssb_sprom *sprom = dev->dev->bus_sprom;
    201	struct b43_phy_lp *lpphy = dev->phy.lp;
    202	u16 tmp, tmp2;
    203
    204	b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF);
    205	b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0);
    206	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
    207	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
    208	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
    209	b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004);
    210	b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078);
    211	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
    212	b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016);
    213	b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004);
    214	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400);
    215	b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400);
    216	b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
    217	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006);
    218	b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE);
    219	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005);
    220	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180);
    221	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00);
    222	b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005);
    223	b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A);
    224	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3);
    225	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
    226	b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB,
    227			0xFF00, lpphy->rx_pwr_offset);
    228	if ((sprom->boardflags_lo & B43_BFL_FEM) &&
    229	   ((b43_current_band(dev->wl) == NL80211_BAND_5GHZ) ||
    230	   (sprom->boardflags_hi & B43_BFH_PAREF))) {
    231		ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28);
    232		ssb_pmu_set_ldo_paref(&bus->chipco, true);
    233		if (dev->phy.rev == 0) {
    234			b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
    235					0xFFCF, 0x0010);
    236		}
    237		b43_lptab_write(dev, B43_LPTAB16(11, 7), 60);
    238	} else {
    239		ssb_pmu_set_ldo_paref(&bus->chipco, false);
    240		b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
    241				0xFFCF, 0x0020);
    242		b43_lptab_write(dev, B43_LPTAB16(11, 7), 100);
    243	}
    244	tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000;
    245	b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp);
    246	if (sprom->boardflags_hi & B43_BFH_RSSIINV)
    247		b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA);
    248	else
    249		b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA);
    250	b43_lptab_write(dev, B43_LPTAB16(11, 1), 24);
    251	b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL,
    252			0xFFF9, (lpphy->bx_arch << 1));
    253	if (dev->phy.rev == 1 &&
    254	   (sprom->boardflags_hi & B43_BFH_FEM_BT)) {
    255		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
    256		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900);
    257		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
    258		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
    259		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A);
    260		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400);
    261		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A);
    262		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00);
    263		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A);
    264		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900);
    265		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A);
    266		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00);
    267		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A);
    268		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900);
    269		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
    270		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
    271	} else if (b43_current_band(dev->wl) == NL80211_BAND_5GHZ ||
    272		   (dev->dev->board_type == SSB_BOARD_BU4312) ||
    273		   (dev->phy.rev == 0 && (sprom->boardflags_lo & B43_BFL_FEM))) {
    274		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
    275		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
    276		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
    277		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500);
    278		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
    279		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800);
    280		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
    281		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00);
    282	} else if (dev->phy.rev == 1 ||
    283		  (sprom->boardflags_lo & B43_BFL_FEM)) {
    284		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004);
    285		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800);
    286		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004);
    287		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00);
    288		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
    289		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100);
    290		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
    291		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300);
    292	} else {
    293		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
    294		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900);
    295		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
    296		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
    297		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006);
    298		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500);
    299		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
    300		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
    301	}
    302	if (dev->phy.rev == 1 && (sprom->boardflags_hi & B43_BFH_PAREF)) {
    303		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1);
    304		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2);
    305		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3);
    306		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4);
    307	}
    308	if ((sprom->boardflags_hi & B43_BFH_FEM_BT) &&
    309	    (dev->dev->chip_id == 0x5354) &&
    310	    (dev->dev->chip_pkg == SSB_CHIPPACK_BCM4712S)) {
    311		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
    312		b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
    313		b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
    314		//FIXME the Broadcom driver caches & delays this HF write!
    315		b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W);
    316	}
    317	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
    318		b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000);
    319		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040);
    320		b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400);
    321		b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00);
    322		b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007);
    323		b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003);
    324		b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020);
    325		b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
    326	} else { /* 5GHz */
    327		b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF);
    328		b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF);
    329	}
    330	if (dev->phy.rev == 1) {
    331		tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH);
    332		tmp2 = (tmp & 0x03E0) >> 5;
    333		tmp2 |= tmp2 << 5;
    334		b43_phy_write(dev, B43_LPPHY_4C3, tmp2);
    335		tmp = b43_phy_read(dev, B43_LPPHY_GAINDIRECTMISMATCH);
    336		tmp2 = (tmp & 0x1F00) >> 8;
    337		tmp2 |= tmp2 << 5;
    338		b43_phy_write(dev, B43_LPPHY_4C4, tmp2);
    339		tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB);
    340		tmp2 = tmp & 0x00FF;
    341		tmp2 |= tmp << 8;
    342		b43_phy_write(dev, B43_LPPHY_4C5, tmp2);
    343	}
    344}
    345
    346static void lpphy_save_dig_flt_state(struct b43_wldev *dev)
    347{
    348	static const u16 addr[] = {
    349		B43_PHY_OFDM(0xC1),
    350		B43_PHY_OFDM(0xC2),
    351		B43_PHY_OFDM(0xC3),
    352		B43_PHY_OFDM(0xC4),
    353		B43_PHY_OFDM(0xC5),
    354		B43_PHY_OFDM(0xC6),
    355		B43_PHY_OFDM(0xC7),
    356		B43_PHY_OFDM(0xC8),
    357		B43_PHY_OFDM(0xCF),
    358	};
    359
    360	static const u16 coefs[] = {
    361		0xDE5E, 0xE832, 0xE331, 0x4D26,
    362		0x0026, 0x1420, 0x0020, 0xFE08,
    363		0x0008,
    364	};
    365
    366	struct b43_phy_lp *lpphy = dev->phy.lp;
    367	int i;
    368
    369	for (i = 0; i < ARRAY_SIZE(addr); i++) {
    370		lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]);
    371		b43_phy_write(dev, addr[i], coefs[i]);
    372	}
    373}
    374
    375static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
    376{
    377	static const u16 addr[] = {
    378		B43_PHY_OFDM(0xC1),
    379		B43_PHY_OFDM(0xC2),
    380		B43_PHY_OFDM(0xC3),
    381		B43_PHY_OFDM(0xC4),
    382		B43_PHY_OFDM(0xC5),
    383		B43_PHY_OFDM(0xC6),
    384		B43_PHY_OFDM(0xC7),
    385		B43_PHY_OFDM(0xC8),
    386		B43_PHY_OFDM(0xCF),
    387	};
    388
    389	struct b43_phy_lp *lpphy = dev->phy.lp;
    390	int i;
    391
    392	for (i = 0; i < ARRAY_SIZE(addr); i++)
    393		b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
    394}
    395
    396static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
    397{
    398	struct b43_phy_lp *lpphy = dev->phy.lp;
    399
    400	b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50);
    401	b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0x8800);
    402	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
    403	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0);
    404	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
    405	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
    406	b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0);
    407	b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0);
    408	b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10);
    409	b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4);
    410	b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200);
    411	b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F);
    412	b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40);
    413	b43_phy_maskset(dev, B43_LPPHY_PREAMBLECONFIRMTO, 0xFF00, 0x2);
    414	b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000);
    415	b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000);
    416	b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1);
    417	if (dev->dev->board_rev >= 0x18) {
    418		b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC);
    419		b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14);
    420	} else {
    421		b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10);
    422	}
    423	b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4);
    424	b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100);
    425	b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48);
    426	b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0xFF00, 0x46);
    427	b43_phy_maskset(dev, B43_PHY_OFDM(0xE4), 0xFF00, 0x10);
    428	b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9);
    429	b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF);
    430	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500);
    431	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0);
    432	b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300);
    433	b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00);
    434	if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
    435		b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
    436		b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xA);
    437	} else {
    438		b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x1E00);
    439		b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xD);
    440	}
    441	b43_phy_maskset(dev, B43_PHY_OFDM(0xFE), 0xFFE0, 0x1F);
    442	b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0xFFE0, 0xC);
    443	b43_phy_maskset(dev, B43_PHY_OFDM(0x100), 0xFF00, 0x19);
    444	b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0x03FF, 0x3C00);
    445	b43_phy_maskset(dev, B43_PHY_OFDM(0xFE), 0xFC1F, 0x3E0);
    446	b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0xFFE0, 0xC);
    447	b43_phy_maskset(dev, B43_PHY_OFDM(0x100), 0x00FF, 0x1900);
    448	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
    449	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12);
    450	b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000);
    451
    452	if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
    453		b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
    454		b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
    455	}
    456
    457	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
    458		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40);
    459		b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0xB00);
    460		b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6);
    461		b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00);
    462		b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1);
    463		b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
    464	} else /* 5GHz */
    465		b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40);
    466
    467	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0xB3);
    468	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
    469	b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB, 0xFF00, lpphy->rx_pwr_offset);
    470	b43_phy_set(dev, B43_LPPHY_RESET_CTL, 0x44);
    471	b43_phy_write(dev, B43_LPPHY_RESET_CTL, 0x80);
    472	b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, 0xA954);
    473	b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1,
    474		      0x2000 | ((u16)lpphy->rssi_gs << 10) |
    475		      ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf);
    476
    477	if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
    478		b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C);
    479		b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800);
    480		b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400);
    481	}
    482
    483	lpphy_save_dig_flt_state(dev);
    484}
    485
    486static void lpphy_baseband_init(struct b43_wldev *dev)
    487{
    488	lpphy_table_init(dev);
    489	if (dev->phy.rev >= 2)
    490		lpphy_baseband_rev2plus_init(dev);
    491	else
    492		lpphy_baseband_rev0_1_init(dev);
    493}
    494
    495struct b2062_freqdata {
    496	u16 freq;
    497	u8 data[6];
    498};
    499
    500/* Initialize the 2062 radio. */
    501static void lpphy_2062_init(struct b43_wldev *dev)
    502{
    503	struct b43_phy_lp *lpphy = dev->phy.lp;
    504	struct ssb_bus *bus = dev->dev->sdev->bus;
    505	u32 crystalfreq, tmp, ref;
    506	unsigned int i;
    507	const struct b2062_freqdata *fd = NULL;
    508
    509	static const struct b2062_freqdata freqdata_tab[] = {
    510		{ .freq = 12000, .data[0] =  6, .data[1] =  6, .data[2] =  6,
    511				 .data[3] =  6, .data[4] = 10, .data[5] =  6, },
    512		{ .freq = 13000, .data[0] =  4, .data[1] =  4, .data[2] =  4,
    513				 .data[3] =  4, .data[4] = 11, .data[5] =  7, },
    514		{ .freq = 14400, .data[0] =  3, .data[1] =  3, .data[2] =  3,
    515				 .data[3] =  3, .data[4] = 12, .data[5] =  7, },
    516		{ .freq = 16200, .data[0] =  3, .data[1] =  3, .data[2] =  3,
    517				 .data[3] =  3, .data[4] = 13, .data[5] =  8, },
    518		{ .freq = 18000, .data[0] =  2, .data[1] =  2, .data[2] =  2,
    519				 .data[3] =  2, .data[4] = 14, .data[5] =  8, },
    520		{ .freq = 19200, .data[0] =  1, .data[1] =  1, .data[2] =  1,
    521				 .data[3] =  1, .data[4] = 14, .data[5] =  9, },
    522	};
    523
    524	b2062_upload_init_table(dev);
    525
    526	b43_radio_write(dev, B2062_N_TX_CTL3, 0);
    527	b43_radio_write(dev, B2062_N_TX_CTL4, 0);
    528	b43_radio_write(dev, B2062_N_TX_CTL5, 0);
    529	b43_radio_write(dev, B2062_N_TX_CTL6, 0);
    530	b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40);
    531	b43_radio_write(dev, B2062_N_PDN_CTL0, 0);
    532	b43_radio_write(dev, B2062_N_CALIB_TS, 0x10);
    533	b43_radio_write(dev, B2062_N_CALIB_TS, 0);
    534	if (dev->phy.rev > 0) {
    535		b43_radio_write(dev, B2062_S_BG_CTL1,
    536			(b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80);
    537	}
    538	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
    539		b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1);
    540	else
    541		b43_radio_mask(dev, B2062_N_TSSI_CTL0, ~0x1);
    542
    543	/* Get the crystal freq, in Hz. */
    544	crystalfreq = bus->chipco.pmu.crystalfreq * 1000;
    545
    546	B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU));
    547	B43_WARN_ON(crystalfreq == 0);
    548
    549	if (crystalfreq <= 30000000) {
    550		lpphy->pdiv = 1;
    551		b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB);
    552	} else {
    553		lpphy->pdiv = 2;
    554		b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4);
    555	}
    556
    557	tmp = (((800000000 * lpphy->pdiv + crystalfreq) /
    558	      (2 * crystalfreq)) - 8) & 0xFF;
    559	b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp);
    560
    561	tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) /
    562	      (32000000 * lpphy->pdiv)) - 1) & 0xFF;
    563	b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp);
    564
    565	tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) /
    566	      (2000000 * lpphy->pdiv)) - 1) & 0xFF;
    567	b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp);
    568
    569	ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv);
    570	ref &= 0xFFFF;
    571	for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) {
    572		if (ref < freqdata_tab[i].freq) {
    573			fd = &freqdata_tab[i];
    574			break;
    575		}
    576	}
    577	if (!fd)
    578		fd = &freqdata_tab[ARRAY_SIZE(freqdata_tab) - 1];
    579	b43dbg(dev->wl, "b2062: Using crystal tab entry %u kHz.\n",
    580	       fd->freq); /* FIXME: Keep this printk until the code is fully debugged. */
    581
    582	b43_radio_write(dev, B2062_S_RFPLL_CTL8,
    583			((u16)(fd->data[1]) << 4) | fd->data[0]);
    584	b43_radio_write(dev, B2062_S_RFPLL_CTL9,
    585			((u16)(fd->data[3]) << 4) | fd->data[2]);
    586	b43_radio_write(dev, B2062_S_RFPLL_CTL10, fd->data[4]);
    587	b43_radio_write(dev, B2062_S_RFPLL_CTL11, fd->data[5]);
    588}
    589
    590/* Initialize the 2063 radio. */
    591static void lpphy_2063_init(struct b43_wldev *dev)
    592{
    593	b2063_upload_init_table(dev);
    594	b43_radio_write(dev, B2063_LOGEN_SP5, 0);
    595	b43_radio_set(dev, B2063_COMM8, 0x38);
    596	b43_radio_write(dev, B2063_REG_SP1, 0x56);
    597	b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2);
    598	b43_radio_write(dev, B2063_PA_SP7, 0);
    599	b43_radio_write(dev, B2063_TX_RF_SP6, 0x20);
    600	b43_radio_write(dev, B2063_TX_RF_SP9, 0x40);
    601	if (dev->phy.rev == 2) {
    602		b43_radio_write(dev, B2063_PA_SP3, 0xa0);
    603		b43_radio_write(dev, B2063_PA_SP4, 0xa0);
    604		b43_radio_write(dev, B2063_PA_SP2, 0x18);
    605	} else {
    606		b43_radio_write(dev, B2063_PA_SP3, 0x20);
    607		b43_radio_write(dev, B2063_PA_SP2, 0x20);
    608	}
    609}
    610
    611struct lpphy_stx_table_entry {
    612	u16 phy_offset;
    613	u16 phy_shift;
    614	u16 rf_addr;
    615	u16 rf_shift;
    616	u16 mask;
    617};
    618
    619static const struct lpphy_stx_table_entry lpphy_stx_table[] = {
    620	{ .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, },
    621	{ .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, },
    622	{ .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, },
    623	{ .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, },
    624	{ .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, },
    625	{ .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, },
    626	{ .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, },
    627	{ .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, },
    628	{ .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, },
    629	{ .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, },
    630	{ .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, },
    631	{ .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, },
    632	{ .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, },
    633	{ .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, },
    634	{ .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, },
    635	{ .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, },
    636	{ .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, },
    637	{ .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, },
    638	{ .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, },
    639	{ .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, },
    640	{ .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, },
    641	{ .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, },
    642	{ .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, },
    643	{ .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, },
    644	{ .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, },
    645	{ .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, },
    646	{ .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, },
    647	{ .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, },
    648	{ .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, },
    649};
    650
    651static void lpphy_sync_stx(struct b43_wldev *dev)
    652{
    653	const struct lpphy_stx_table_entry *e;
    654	unsigned int i;
    655	u16 tmp;
    656
    657	for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) {
    658		e = &lpphy_stx_table[i];
    659		tmp = b43_radio_read(dev, e->rf_addr);
    660		tmp >>= e->rf_shift;
    661		tmp <<= e->phy_shift;
    662		b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset),
    663				~(e->mask << e->phy_shift), tmp);
    664	}
    665}
    666
    667static void lpphy_radio_init(struct b43_wldev *dev)
    668{
    669	/* The radio is attached through the 4wire bus. */
    670	b43_phy_set(dev, B43_LPPHY_FOURWIRE_CTL, 0x2);
    671	udelay(1);
    672	b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD);
    673	udelay(1);
    674
    675	if (dev->phy.radio_ver == 0x2062) {
    676		lpphy_2062_init(dev);
    677	} else {
    678		lpphy_2063_init(dev);
    679		lpphy_sync_stx(dev);
    680		b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
    681		b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
    682		if (dev->dev->chip_id == 0x4325) {
    683			// TODO SSB PMU recalibration
    684		}
    685	}
    686}
    687
    688struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; };
    689
    690static void lpphy_set_rc_cap(struct b43_wldev *dev)
    691{
    692	struct b43_phy_lp *lpphy = dev->phy.lp;
    693
    694	u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1;
    695
    696	if (dev->phy.rev == 1) //FIXME check channel 14!
    697		rc_cap = min_t(u8, rc_cap + 5, 15);
    698
    699	b43_radio_write(dev, B2062_N_RXBB_CALIB2,
    700			max_t(u8, lpphy->rc_cap - 4, 0x80));
    701	b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80);
    702	b43_radio_write(dev, B2062_S_RXG_CNT16,
    703			((lpphy->rc_cap & 0x1F) >> 2) | 0x80);
    704}
    705
    706static u8 lpphy_get_bb_mult(struct b43_wldev *dev)
    707{
    708	return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8;
    709}
    710
    711static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult)
    712{
    713	b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8);
    714}
    715
    716static void lpphy_set_deaf(struct b43_wldev *dev, bool user)
    717{
    718	struct b43_phy_lp *lpphy = dev->phy.lp;
    719
    720	if (user)
    721		lpphy->crs_usr_disable = true;
    722	else
    723		lpphy->crs_sys_disable = true;
    724	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80);
    725}
    726
    727static void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
    728{
    729	struct b43_phy_lp *lpphy = dev->phy.lp;
    730
    731	if (user)
    732		lpphy->crs_usr_disable = false;
    733	else
    734		lpphy->crs_sys_disable = false;
    735
    736	if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) {
    737		if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
    738			b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
    739					0xFF1F, 0x60);
    740		else
    741			b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
    742					0xFF1F, 0x20);
    743	}
    744}
    745
    746static void lpphy_set_trsw_over(struct b43_wldev *dev, bool tx, bool rx)
    747{
    748	u16 trsw = (tx << 1) | rx;
    749	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, trsw);
    750	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
    751}
    752
    753static void lpphy_disable_crs(struct b43_wldev *dev, bool user)
    754{
    755	lpphy_set_deaf(dev, user);
    756	lpphy_set_trsw_over(dev, false, true);
    757	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
    758	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
    759	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);
    760	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
    761	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10);
    762	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
    763	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF);
    764	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
    765	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF);
    766	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
    767	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7);
    768	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38);
    769	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F);
    770	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100);
    771	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF);
    772	b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0);
    773	b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1);
    774	b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20);
    775	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF);
    776	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF);
    777	b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
    778	b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF);
    779	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF);
    780}
    781
    782static void lpphy_restore_crs(struct b43_wldev *dev, bool user)
    783{
    784	lpphy_clear_deaf(dev, user);
    785	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80);
    786	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00);
    787}
    788
    789struct lpphy_tx_gains { u16 gm, pga, pad, dac; };
    790
    791static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
    792{
    793	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
    794	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
    795	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
    796	if (dev->phy.rev >= 2) {
    797		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
    798		if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
    799			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
    800			b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
    801		}
    802	} else {
    803		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
    804	}
    805}
    806
    807static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
    808{
    809	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
    810	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
    811	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
    812	if (dev->phy.rev >= 2) {
    813		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
    814		if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
    815			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
    816			b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
    817		}
    818	} else {
    819		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
    820	}
    821}
    822
    823static void lpphy_disable_tx_gain_override(struct b43_wldev *dev)
    824{
    825	if (dev->phy.rev < 2)
    826		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
    827	else {
    828		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F);
    829		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF);
    830	}
    831	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF);
    832}
    833
    834static void lpphy_enable_tx_gain_override(struct b43_wldev *dev)
    835{
    836	if (dev->phy.rev < 2)
    837		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
    838	else {
    839		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x80);
    840		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x4000);
    841	}
    842	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x40);
    843}
    844
    845static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
    846{
    847	struct lpphy_tx_gains gains;
    848	u16 tmp;
    849
    850	gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7;
    851	if (dev->phy.rev < 2) {
    852		tmp = b43_phy_read(dev,
    853				   B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF;
    854		gains.gm = tmp & 0x0007;
    855		gains.pga = (tmp & 0x0078) >> 3;
    856		gains.pad = (tmp & 0x780) >> 7;
    857	} else {
    858		tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL);
    859		gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF;
    860		gains.gm = tmp & 0xFF;
    861		gains.pga = (tmp >> 8) & 0xFF;
    862	}
    863
    864	return gains;
    865}
    866
    867static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
    868{
    869	u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F;
    870	ctl |= dac << 7;
    871	b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
    872}
    873
    874static u16 lpphy_get_pa_gain(struct b43_wldev *dev)
    875{
    876	return b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F;
    877}
    878
    879static void lpphy_set_pa_gain(struct b43_wldev *dev, u16 gain)
    880{
    881	b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0xE03F, gain << 6);
    882	b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), 0x80FF, gain << 8);
    883}
    884
    885static void lpphy_set_tx_gains(struct b43_wldev *dev,
    886			       struct lpphy_tx_gains gains)
    887{
    888	u16 rf_gain, pa_gain;
    889
    890	if (dev->phy.rev < 2) {
    891		rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm;
    892		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
    893				0xF800, rf_gain);
    894	} else {
    895		pa_gain = lpphy_get_pa_gain(dev);
    896		b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
    897			      (gains.pga << 8) | gains.gm);
    898		/*
    899		 * SPEC FIXME The spec calls for (pa_gain << 8) here, but that
    900		 * conflicts with the spec for set_pa_gain! Vendor driver bug?
    901		 */
    902		b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
    903				0x8000, gains.pad | (pa_gain << 6));
    904		b43_phy_write(dev, B43_PHY_OFDM(0xFC),
    905			      (gains.pga << 8) | gains.gm);
    906		b43_phy_maskset(dev, B43_PHY_OFDM(0xFD),
    907				0x8000, gains.pad | (pa_gain << 8));
    908	}
    909	lpphy_set_dac_gain(dev, gains.dac);
    910	lpphy_enable_tx_gain_override(dev);
    911}
    912
    913static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
    914{
    915	u16 trsw = gain & 0x1;
    916	u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2);
    917	u16 ext_lna = (gain & 2) >> 1;
    918
    919	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
    920	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
    921			0xFBFF, ext_lna << 10);
    922	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
    923			0xF7FF, ext_lna << 11);
    924	b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
    925}
    926
    927static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
    928{
    929	u16 low_gain = gain & 0xFFFF;
    930	u16 high_gain = (gain >> 16) & 0xF;
    931	u16 ext_lna = (gain >> 21) & 0x1;
    932	u16 trsw = ~(gain >> 20) & 0x1;
    933	u16 tmp;
    934
    935	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
    936	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
    937			0xFDFF, ext_lna << 9);
    938	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
    939			0xFBFF, ext_lna << 10);
    940	b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
    941	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain);
    942	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
    943		tmp = (gain >> 2) & 0x3;
    944		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
    945				0xE7FF, tmp<<11);
    946		b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3);
    947	}
    948}
    949
    950static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)
    951{
    952	if (dev->phy.rev < 2)
    953		lpphy_rev0_1_set_rx_gain(dev, gain);
    954	else
    955		lpphy_rev2plus_set_rx_gain(dev, gain);
    956	lpphy_enable_rx_gain_override(dev);
    957}
    958
    959static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx)
    960{
    961	u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx));
    962	lpphy_set_rx_gain(dev, gain);
    963}
    964
    965static void lpphy_stop_ddfs(struct b43_wldev *dev)
    966{
    967	b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD);
    968	b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF);
    969}
    970
    971static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on,
    972			   int incr1, int incr2, int scale_idx)
    973{
    974	lpphy_stop_ddfs(dev);
    975	b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80);
    976	b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF);
    977	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1);
    978	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8);
    979	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3);
    980	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4);
    981	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5);
    982	b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB);
    983	b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2);
    984	b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x20);
    985}
    986
    987static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
    988			   struct lpphy_iq_est *iq_est)
    989{
    990	int i;
    991
    992	b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7);
    993	b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples);
    994	b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time);
    995	b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF);
    996	b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
    997
    998	for (i = 0; i < 500; i++) {
    999		if (!(b43_phy_read(dev,
   1000				B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
   1001			break;
   1002		msleep(1);
   1003	}
   1004
   1005	if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
   1006		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
   1007		return false;
   1008	}
   1009
   1010	iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR);
   1011	iq_est->iq_prod <<= 16;
   1012	iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR);
   1013
   1014	iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR);
   1015	iq_est->i_pwr <<= 16;
   1016	iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR);
   1017
   1018	iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR);
   1019	iq_est->q_pwr <<= 16;
   1020	iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR);
   1021
   1022	b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
   1023	return true;
   1024}
   1025
   1026static int lpphy_loopback(struct b43_wldev *dev)
   1027{
   1028	struct lpphy_iq_est iq_est;
   1029	int i, index = -1;
   1030	u32 tmp;
   1031
   1032	memset(&iq_est, 0, sizeof(iq_est));
   1033
   1034	lpphy_set_trsw_over(dev, true, true);
   1035	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
   1036	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
   1037	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
   1038	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
   1039	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
   1040	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8);
   1041	b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80);
   1042	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80);
   1043	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80);
   1044	for (i = 0; i < 32; i++) {
   1045		lpphy_set_rx_gain_by_index(dev, i);
   1046		lpphy_run_ddfs(dev, 1, 1, 5, 5, 0);
   1047		if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
   1048			continue;
   1049		tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000;
   1050		if ((tmp > 4000) && (tmp < 10000)) {
   1051			index = i;
   1052			break;
   1053		}
   1054	}
   1055	lpphy_stop_ddfs(dev);
   1056	return index;
   1057}
   1058
   1059/* Fixed-point division algorithm using only integer math. */
   1060static u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
   1061{
   1062	u32 quotient, remainder;
   1063
   1064	if (divisor == 0)
   1065		return 0;
   1066
   1067	quotient = dividend / divisor;
   1068	remainder = dividend % divisor;
   1069
   1070	while (precision > 0) {
   1071		quotient <<= 1;
   1072		if (remainder << 1 >= divisor) {
   1073			quotient++;
   1074			remainder = (remainder << 1) - divisor;
   1075		}
   1076		precision--;
   1077	}
   1078
   1079	if (remainder << 1 >= divisor)
   1080		quotient++;
   1081
   1082	return quotient;
   1083}
   1084
   1085/* Read the TX power control mode from hardware. */
   1086static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev)
   1087{
   1088	struct b43_phy_lp *lpphy = dev->phy.lp;
   1089	u16 ctl;
   1090
   1091	ctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD);
   1092	switch (ctl & B43_LPPHY_TX_PWR_CTL_CMD_MODE) {
   1093	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF:
   1094		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_OFF;
   1095		break;
   1096	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW:
   1097		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_SW;
   1098		break;
   1099	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW:
   1100		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_HW;
   1101		break;
   1102	default:
   1103		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_UNKNOWN;
   1104		B43_WARN_ON(1);
   1105		break;
   1106	}
   1107}
   1108
   1109/* Set the TX power control mode in hardware. */
   1110static void lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev *dev)
   1111{
   1112	struct b43_phy_lp *lpphy = dev->phy.lp;
   1113	u16 ctl;
   1114
   1115	switch (lpphy->txpctl_mode) {
   1116	case B43_LPPHY_TXPCTL_OFF:
   1117		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF;
   1118		break;
   1119	case B43_LPPHY_TXPCTL_HW:
   1120		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW;
   1121		break;
   1122	case B43_LPPHY_TXPCTL_SW:
   1123		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW;
   1124		break;
   1125	default:
   1126		ctl = 0;
   1127		B43_WARN_ON(1);
   1128	}
   1129	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
   1130			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF, ctl);
   1131}
   1132
   1133static void lpphy_set_tx_power_control(struct b43_wldev *dev,
   1134				       enum b43_lpphy_txpctl_mode mode)
   1135{
   1136	struct b43_phy_lp *lpphy = dev->phy.lp;
   1137	enum b43_lpphy_txpctl_mode oldmode;
   1138
   1139	lpphy_read_tx_pctl_mode_from_hardware(dev);
   1140	oldmode = lpphy->txpctl_mode;
   1141	if (oldmode == mode)
   1142		return;
   1143	lpphy->txpctl_mode = mode;
   1144
   1145	if (oldmode == B43_LPPHY_TXPCTL_HW) {
   1146		//TODO Update TX Power NPT
   1147		//TODO Clear all TX Power offsets
   1148	} else {
   1149		if (mode == B43_LPPHY_TXPCTL_HW) {
   1150			//TODO Recalculate target TX power
   1151			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
   1152					0xFF80, lpphy->tssi_idx);
   1153			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
   1154					0x8FFF, ((u16)lpphy->tssi_npt << 16));
   1155			//TODO Set "TSSI Transmit Count" variable to total transmitted frame count
   1156			lpphy_disable_tx_gain_override(dev);
   1157			lpphy->tx_pwr_idx_over = -1;
   1158		}
   1159	}
   1160	if (dev->phy.rev >= 2) {
   1161		if (mode == B43_LPPHY_TXPCTL_HW)
   1162			b43_phy_set(dev, B43_PHY_OFDM(0xD0), 0x2);
   1163		else
   1164			b43_phy_mask(dev, B43_PHY_OFDM(0xD0), 0xFFFD);
   1165	}
   1166	lpphy_write_tx_pctl_mode_to_hardware(dev);
   1167}
   1168
   1169static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
   1170				       unsigned int new_channel);
   1171
   1172static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
   1173{
   1174	struct b43_phy_lp *lpphy = dev->phy.lp;
   1175	struct lpphy_iq_est iq_est;
   1176	struct lpphy_tx_gains tx_gains;
   1177	static const u32 ideal_pwr_table[21] = {
   1178		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
   1179		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
   1180		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
   1181		0x0004c, 0x0002c, 0x0001a,
   1182	};
   1183	bool old_txg_ovr;
   1184	u8 old_bbmult;
   1185	u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval,
   1186	    old_rf2_ovr, old_rf2_ovrval, old_phy_ctl;
   1187	enum b43_lpphy_txpctl_mode old_txpctl;
   1188	u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0;
   1189	int loopback, i, j, inner_sum, err;
   1190
   1191	memset(&iq_est, 0, sizeof(iq_est));
   1192
   1193	err = b43_lpphy_op_switch_channel(dev, 7);
   1194	if (err) {
   1195		b43dbg(dev->wl,
   1196		       "RC calib: Failed to switch to channel 7, error = %d\n",
   1197		       err);
   1198	}
   1199	old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40);
   1200	old_bbmult = lpphy_get_bb_mult(dev);
   1201	if (old_txg_ovr)
   1202		tx_gains = lpphy_get_tx_gains(dev);
   1203	old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0);
   1204	old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0);
   1205	old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR);
   1206	old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL);
   1207	old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2);
   1208	old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL);
   1209	old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL);
   1210	lpphy_read_tx_pctl_mode_from_hardware(dev);
   1211	old_txpctl = lpphy->txpctl_mode;
   1212
   1213	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
   1214	lpphy_disable_crs(dev, true);
   1215	loopback = lpphy_loopback(dev);
   1216	if (loopback == -1)
   1217		goto finish;
   1218	lpphy_set_rx_gain_by_index(dev, loopback);
   1219	b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40);
   1220	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1);
   1221	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8);
   1222	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0);
   1223	for (i = 128; i <= 159; i++) {
   1224		b43_radio_write(dev, B2062_N_RXBB_CALIB2, i);
   1225		inner_sum = 0;
   1226		for (j = 5; j <= 25; j++) {
   1227			lpphy_run_ddfs(dev, 1, 1, j, j, 0);
   1228			if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
   1229				goto finish;
   1230			mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr;
   1231			if (j == 5)
   1232				tmp = mean_sq_pwr;
   1233			ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1;
   1234			normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12);
   1235			mean_sq_pwr = ideal_pwr - normal_pwr;
   1236			mean_sq_pwr *= mean_sq_pwr;
   1237			inner_sum += mean_sq_pwr;
   1238			if ((i == 128) || (inner_sum < mean_sq_pwr_min)) {
   1239				lpphy->rc_cap = i;
   1240				mean_sq_pwr_min = inner_sum;
   1241			}
   1242		}
   1243	}
   1244	lpphy_stop_ddfs(dev);
   1245
   1246finish:
   1247	lpphy_restore_crs(dev, true);
   1248	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval);
   1249	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr);
   1250	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval);
   1251	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr);
   1252	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval);
   1253	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr);
   1254	b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl);
   1255
   1256	lpphy_set_bb_mult(dev, old_bbmult);
   1257	if (old_txg_ovr) {
   1258		/*
   1259		 * SPEC FIXME: The specs say "get_tx_gains" here, which is
   1260		 * illogical. According to lwfinger, vendor driver v4.150.10.5
   1261		 * has a Set here, while v4.174.64.19 has a Get - regression in
   1262		 * the vendor driver? This should be tested this once the code
   1263		 * is testable.
   1264		 */
   1265		lpphy_set_tx_gains(dev, tx_gains);
   1266	}
   1267	lpphy_set_tx_power_control(dev, old_txpctl);
   1268	if (lpphy->rc_cap)
   1269		lpphy_set_rc_cap(dev);
   1270}
   1271
   1272static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
   1273{
   1274	struct ssb_bus *bus = dev->dev->sdev->bus;
   1275	u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
   1276	u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
   1277	int i;
   1278
   1279	b43_radio_write(dev, B2063_RX_BB_SP8, 0x0);
   1280	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
   1281	b43_radio_mask(dev, B2063_PLL_SP1, 0xF7);
   1282	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
   1283	b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15);
   1284	b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70);
   1285	b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52);
   1286	b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
   1287	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D);
   1288
   1289	for (i = 0; i < 10000; i++) {
   1290		if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
   1291			break;
   1292		msleep(1);
   1293	}
   1294
   1295	if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
   1296		b43_radio_write(dev, B2063_RX_BB_SP8, tmp);
   1297
   1298	tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF;
   1299
   1300	b43_radio_write(dev, B2063_TX_BB_SP3, 0x0);
   1301	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
   1302	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
   1303	b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55);
   1304	b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76);
   1305
   1306	if (crystal_freq == 24000000) {
   1307		b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC);
   1308		b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0);
   1309	} else {
   1310		b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13);
   1311		b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
   1312	}
   1313
   1314	b43_radio_write(dev, B2063_PA_SP7, 0x7D);
   1315
   1316	for (i = 0; i < 10000; i++) {
   1317		if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
   1318			break;
   1319		msleep(1);
   1320	}
   1321
   1322	if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
   1323		b43_radio_write(dev, B2063_TX_BB_SP3, tmp);
   1324
   1325	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
   1326}
   1327
   1328static void lpphy_calibrate_rc(struct b43_wldev *dev)
   1329{
   1330	struct b43_phy_lp *lpphy = dev->phy.lp;
   1331
   1332	if (dev->phy.rev >= 2) {
   1333		lpphy_rev2plus_rc_calib(dev);
   1334	} else if (!lpphy->rc_cap) {
   1335		if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
   1336			lpphy_rev0_1_rc_calib(dev);
   1337	} else {
   1338		lpphy_set_rc_cap(dev);
   1339	}
   1340}
   1341
   1342static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
   1343{
   1344	if (dev->phy.rev >= 2)
   1345		return; // rev2+ doesn't support antenna diversity
   1346
   1347	if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
   1348		return;
   1349
   1350	b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
   1351
   1352	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
   1353	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
   1354
   1355	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
   1356
   1357	dev->phy.lp->antenna = antenna;
   1358}
   1359
   1360static void lpphy_set_tx_iqcc(struct b43_wldev *dev, u16 a, u16 b)
   1361{
   1362	u16 tmp[2];
   1363
   1364	tmp[0] = a;
   1365	tmp[1] = b;
   1366	b43_lptab_write_bulk(dev, B43_LPTAB16(0, 80), 2, tmp);
   1367}
   1368
   1369static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
   1370{
   1371	struct b43_phy_lp *lpphy = dev->phy.lp;
   1372	struct lpphy_tx_gains gains;
   1373	u32 iq_comp, tx_gain, coeff, rf_power;
   1374
   1375	lpphy->tx_pwr_idx_over = index;
   1376	lpphy_read_tx_pctl_mode_from_hardware(dev);
   1377	if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
   1378		lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);
   1379	if (dev->phy.rev >= 2) {
   1380		iq_comp = b43_lptab_read(dev, B43_LPTAB32(7, index + 320));
   1381		tx_gain = b43_lptab_read(dev, B43_LPTAB32(7, index + 192));
   1382		gains.pad = (tx_gain >> 16) & 0xFF;
   1383		gains.gm = tx_gain & 0xFF;
   1384		gains.pga = (tx_gain >> 8) & 0xFF;
   1385		gains.dac = (iq_comp >> 28) & 0xFF;
   1386		lpphy_set_tx_gains(dev, gains);
   1387	} else {
   1388		iq_comp = b43_lptab_read(dev, B43_LPTAB32(10, index + 320));
   1389		tx_gain = b43_lptab_read(dev, B43_LPTAB32(10, index + 192));
   1390		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
   1391				0xF800, (tx_gain >> 4) & 0x7FFF);
   1392		lpphy_set_dac_gain(dev, tx_gain & 0x7);
   1393		lpphy_set_pa_gain(dev, (tx_gain >> 24) & 0x7F);
   1394	}
   1395	lpphy_set_bb_mult(dev, (iq_comp >> 20) & 0xFF);
   1396	lpphy_set_tx_iqcc(dev, (iq_comp >> 10) & 0x3FF, iq_comp & 0x3FF);
   1397	if (dev->phy.rev >= 2) {
   1398		coeff = b43_lptab_read(dev, B43_LPTAB32(7, index + 448));
   1399	} else {
   1400		coeff = b43_lptab_read(dev, B43_LPTAB32(10, index + 448));
   1401	}
   1402	b43_lptab_write(dev, B43_LPTAB16(0, 85), coeff & 0xFFFF);
   1403	if (dev->phy.rev >= 2) {
   1404		rf_power = b43_lptab_read(dev, B43_LPTAB32(7, index + 576));
   1405		b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00,
   1406				rf_power & 0xFFFF);//SPEC FIXME mask & set != 0
   1407	}
   1408	lpphy_enable_tx_gain_override(dev);
   1409}
   1410
   1411static void lpphy_btcoex_override(struct b43_wldev *dev)
   1412{
   1413	b43_write16(dev, B43_MMIO_BTCOEX_CTL, 0x3);
   1414	b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
   1415}
   1416
   1417static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
   1418					 bool blocked)
   1419{
   1420	//TODO check MAC control register
   1421	if (blocked) {
   1422		if (dev->phy.rev >= 2) {
   1423			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x83FF);
   1424			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
   1425			b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0x80FF);
   1426			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xDFFF);
   1427			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0808);
   1428		} else {
   1429			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xE0FF);
   1430			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
   1431			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFCFF);
   1432			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0018);
   1433		}
   1434	} else {
   1435		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xE0FF);
   1436		if (dev->phy.rev >= 2)
   1437			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xF7F7);
   1438		else
   1439			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFE7);
   1440	}
   1441}
   1442
   1443/* This was previously called lpphy_japan_filter */
   1444static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
   1445{
   1446	struct b43_phy_lp *lpphy = dev->phy.lp;
   1447	u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
   1448
   1449	if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
   1450		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
   1451		if ((dev->phy.rev == 1) && (lpphy->rc_cap))
   1452			lpphy_set_rc_cap(dev);
   1453	} else {
   1454		b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
   1455	}
   1456}
   1457
   1458static void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode)
   1459{
   1460	if (mode != TSSI_MUX_EXT) {
   1461		b43_radio_set(dev, B2063_PA_SP1, 0x2);
   1462		b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000);
   1463		b43_radio_write(dev, B2063_PA_CTL10, 0x51);
   1464		if (mode == TSSI_MUX_POSTPA) {
   1465			b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE);
   1466			b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7);
   1467		} else {
   1468			b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1);
   1469			b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL,
   1470					0xFFC7, 0x20);
   1471		}
   1472	} else {
   1473		B43_WARN_ON(1);
   1474	}
   1475}
   1476
   1477static void lpphy_tx_pctl_init_hw(struct b43_wldev *dev)
   1478{
   1479	u16 tmp;
   1480	int i;
   1481
   1482	//SPEC TODO Call LP PHY Clear TX Power offsets
   1483	for (i = 0; i < 64; i++) {
   1484		if (dev->phy.rev >= 2)
   1485			b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i);
   1486		else
   1487			b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i);
   1488	}
   1489
   1490	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF);
   1491	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000);
   1492	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F);
   1493	if (dev->phy.rev < 2) {
   1494		b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF);
   1495		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000);
   1496	} else {
   1497		b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE);
   1498		b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4);
   1499		b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10);
   1500		b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1);
   1501		lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA);
   1502	}
   1503	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000);
   1504	b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF);
   1505	b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA);
   1506	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
   1507			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
   1508			B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
   1509	b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF);
   1510	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
   1511			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
   1512			B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW);
   1513
   1514	if (dev->phy.rev < 2) {
   1515		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000);
   1516		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF);
   1517	} else {
   1518		lpphy_set_tx_power_by_index(dev, 0x7F);
   1519	}
   1520
   1521	b43_dummy_transmission(dev, true, true);
   1522
   1523	tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT);
   1524	if (tmp & 0x8000) {
   1525		b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI,
   1526				0xFFC0, (tmp & 0xFF) - 32);
   1527	}
   1528
   1529	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF);
   1530
   1531	// (SPEC?) TODO Set "Target TX frequency" variable to 0
   1532	// SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8!
   1533}
   1534
   1535static void lpphy_tx_pctl_init_sw(struct b43_wldev *dev)
   1536{
   1537	struct lpphy_tx_gains gains;
   1538
   1539	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
   1540		gains.gm = 4;
   1541		gains.pad = 12;
   1542		gains.pga = 12;
   1543		gains.dac = 0;
   1544	} else {
   1545		gains.gm = 7;
   1546		gains.pad = 14;
   1547		gains.pga = 15;
   1548		gains.dac = 0;
   1549	}
   1550	lpphy_set_tx_gains(dev, gains);
   1551	lpphy_set_bb_mult(dev, 150);
   1552}
   1553
   1554/* Initialize TX power control */
   1555static void lpphy_tx_pctl_init(struct b43_wldev *dev)
   1556{
   1557	if (0/*FIXME HWPCTL capable */) {
   1558		lpphy_tx_pctl_init_hw(dev);
   1559	} else { /* This device is only software TX power control capable. */
   1560		lpphy_tx_pctl_init_sw(dev);
   1561	}
   1562}
   1563
   1564static void lpphy_pr41573_workaround(struct b43_wldev *dev)
   1565{
   1566	struct b43_phy_lp *lpphy = dev->phy.lp;
   1567	u32 *saved_tab;
   1568	const unsigned int saved_tab_size = 256;
   1569	enum b43_lpphy_txpctl_mode txpctl_mode;
   1570	s8 tx_pwr_idx_over;
   1571	u16 tssi_npt, tssi_idx;
   1572
   1573	saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL);
   1574	if (!saved_tab) {
   1575		b43err(dev->wl, "PR41573 failed. Out of memory!\n");
   1576		return;
   1577	}
   1578
   1579	lpphy_read_tx_pctl_mode_from_hardware(dev);
   1580	txpctl_mode = lpphy->txpctl_mode;
   1581	tx_pwr_idx_over = lpphy->tx_pwr_idx_over;
   1582	tssi_npt = lpphy->tssi_npt;
   1583	tssi_idx = lpphy->tssi_idx;
   1584
   1585	if (dev->phy.rev < 2) {
   1586		b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140),
   1587				    saved_tab_size, saved_tab);
   1588	} else {
   1589		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
   1590				    saved_tab_size, saved_tab);
   1591	}
   1592	//FIXME PHY reset
   1593	lpphy_table_init(dev); //FIXME is table init needed?
   1594	lpphy_baseband_init(dev);
   1595	lpphy_tx_pctl_init(dev);
   1596	b43_lpphy_op_software_rfkill(dev, false);
   1597	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
   1598	if (dev->phy.rev < 2) {
   1599		b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
   1600				     saved_tab_size, saved_tab);
   1601	} else {
   1602		b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
   1603				     saved_tab_size, saved_tab);
   1604	}
   1605	b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
   1606	lpphy->tssi_npt = tssi_npt;
   1607	lpphy->tssi_idx = tssi_idx;
   1608	lpphy_set_analog_filter(dev, lpphy->channel);
   1609	if (tx_pwr_idx_over != -1)
   1610		lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
   1611	if (lpphy->rc_cap)
   1612		lpphy_set_rc_cap(dev);
   1613	b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
   1614	lpphy_set_tx_power_control(dev, txpctl_mode);
   1615	kfree(saved_tab);
   1616}
   1617
   1618struct lpphy_rx_iq_comp { u8 chan; s8 c1, c0; };
   1619
   1620static const struct lpphy_rx_iq_comp lpphy_5354_iq_table[] = {
   1621	{ .chan = 1, .c1 = -66, .c0 = 15, },
   1622	{ .chan = 2, .c1 = -66, .c0 = 15, },
   1623	{ .chan = 3, .c1 = -66, .c0 = 15, },
   1624	{ .chan = 4, .c1 = -66, .c0 = 15, },
   1625	{ .chan = 5, .c1 = -66, .c0 = 15, },
   1626	{ .chan = 6, .c1 = -66, .c0 = 15, },
   1627	{ .chan = 7, .c1 = -66, .c0 = 14, },
   1628	{ .chan = 8, .c1 = -66, .c0 = 14, },
   1629	{ .chan = 9, .c1 = -66, .c0 = 14, },
   1630	{ .chan = 10, .c1 = -66, .c0 = 14, },
   1631	{ .chan = 11, .c1 = -66, .c0 = 14, },
   1632	{ .chan = 12, .c1 = -66, .c0 = 13, },
   1633	{ .chan = 13, .c1 = -66, .c0 = 13, },
   1634	{ .chan = 14, .c1 = -66, .c0 = 13, },
   1635};
   1636
   1637static const struct lpphy_rx_iq_comp lpphy_rev0_1_iq_table[] = {
   1638	{ .chan = 1, .c1 = -64, .c0 = 13, },
   1639	{ .chan = 2, .c1 = -64, .c0 = 13, },
   1640	{ .chan = 3, .c1 = -64, .c0 = 13, },
   1641	{ .chan = 4, .c1 = -64, .c0 = 13, },
   1642	{ .chan = 5, .c1 = -64, .c0 = 12, },
   1643	{ .chan = 6, .c1 = -64, .c0 = 12, },
   1644	{ .chan = 7, .c1 = -64, .c0 = 12, },
   1645	{ .chan = 8, .c1 = -64, .c0 = 12, },
   1646	{ .chan = 9, .c1 = -64, .c0 = 12, },
   1647	{ .chan = 10, .c1 = -64, .c0 = 11, },
   1648	{ .chan = 11, .c1 = -64, .c0 = 11, },
   1649	{ .chan = 12, .c1 = -64, .c0 = 11, },
   1650	{ .chan = 13, .c1 = -64, .c0 = 11, },
   1651	{ .chan = 14, .c1 = -64, .c0 = 10, },
   1652	{ .chan = 34, .c1 = -62, .c0 = 24, },
   1653	{ .chan = 38, .c1 = -62, .c0 = 24, },
   1654	{ .chan = 42, .c1 = -62, .c0 = 24, },
   1655	{ .chan = 46, .c1 = -62, .c0 = 23, },
   1656	{ .chan = 36, .c1 = -62, .c0 = 24, },
   1657	{ .chan = 40, .c1 = -62, .c0 = 24, },
   1658	{ .chan = 44, .c1 = -62, .c0 = 23, },
   1659	{ .chan = 48, .c1 = -62, .c0 = 23, },
   1660	{ .chan = 52, .c1 = -62, .c0 = 23, },
   1661	{ .chan = 56, .c1 = -62, .c0 = 22, },
   1662	{ .chan = 60, .c1 = -62, .c0 = 22, },
   1663	{ .chan = 64, .c1 = -62, .c0 = 22, },
   1664	{ .chan = 100, .c1 = -62, .c0 = 16, },
   1665	{ .chan = 104, .c1 = -62, .c0 = 16, },
   1666	{ .chan = 108, .c1 = -62, .c0 = 15, },
   1667	{ .chan = 112, .c1 = -62, .c0 = 14, },
   1668	{ .chan = 116, .c1 = -62, .c0 = 14, },
   1669	{ .chan = 120, .c1 = -62, .c0 = 13, },
   1670	{ .chan = 124, .c1 = -62, .c0 = 12, },
   1671	{ .chan = 128, .c1 = -62, .c0 = 12, },
   1672	{ .chan = 132, .c1 = -62, .c0 = 12, },
   1673	{ .chan = 136, .c1 = -62, .c0 = 11, },
   1674	{ .chan = 140, .c1 = -62, .c0 = 10, },
   1675	{ .chan = 149, .c1 = -61, .c0 = 9, },
   1676	{ .chan = 153, .c1 = -61, .c0 = 9, },
   1677	{ .chan = 157, .c1 = -61, .c0 = 9, },
   1678	{ .chan = 161, .c1 = -61, .c0 = 8, },
   1679	{ .chan = 165, .c1 = -61, .c0 = 8, },
   1680	{ .chan = 184, .c1 = -62, .c0 = 25, },
   1681	{ .chan = 188, .c1 = -62, .c0 = 25, },
   1682	{ .chan = 192, .c1 = -62, .c0 = 25, },
   1683	{ .chan = 196, .c1 = -62, .c0 = 25, },
   1684	{ .chan = 200, .c1 = -62, .c0 = 25, },
   1685	{ .chan = 204, .c1 = -62, .c0 = 25, },
   1686	{ .chan = 208, .c1 = -62, .c0 = 25, },
   1687	{ .chan = 212, .c1 = -62, .c0 = 25, },
   1688	{ .chan = 216, .c1 = -62, .c0 = 26, },
   1689};
   1690
   1691static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
   1692	.chan = 0,
   1693	.c1 = -64,
   1694	.c0 = 0,
   1695};
   1696
   1697static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
   1698{
   1699	struct lpphy_iq_est iq_est;
   1700	u16 c0, c1;
   1701	int prod, ipwr, qpwr, prod_msb, q_msb, tmp1, tmp2, tmp3, tmp4, ret;
   1702
   1703	c1 = b43_phy_read(dev, B43_LPPHY_RX_COMP_COEFF_S);
   1704	c0 = c1 >> 8;
   1705	c1 |= 0xFF;
   1706
   1707	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, 0x00C0);
   1708	b43_phy_mask(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF);
   1709
   1710	ret = lpphy_rx_iq_est(dev, samples, 32, &iq_est);
   1711	if (!ret)
   1712		goto out;
   1713
   1714	prod = iq_est.iq_prod;
   1715	ipwr = iq_est.i_pwr;
   1716	qpwr = iq_est.q_pwr;
   1717
   1718	if (ipwr + qpwr < 2) {
   1719		ret = 0;
   1720		goto out;
   1721	}
   1722
   1723	prod_msb = fls(abs(prod));
   1724	q_msb = fls(abs(qpwr));
   1725	tmp1 = prod_msb - 20;
   1726
   1727	if (tmp1 >= 0) {
   1728		tmp3 = ((prod << (30 - prod_msb)) + (ipwr >> (1 + tmp1))) /
   1729			(ipwr >> tmp1);
   1730	} else {
   1731		tmp3 = ((prod << (30 - prod_msb)) + (ipwr << (-1 - tmp1))) /
   1732			(ipwr << -tmp1);
   1733	}
   1734
   1735	tmp2 = q_msb - 11;
   1736
   1737	if (tmp2 >= 0)
   1738		tmp4 = (qpwr << (31 - q_msb)) / (ipwr >> tmp2);
   1739	else
   1740		tmp4 = (qpwr << (31 - q_msb)) / (ipwr << -tmp2);
   1741
   1742	tmp4 -= tmp3 * tmp3;
   1743	tmp4 = -int_sqrt(tmp4);
   1744
   1745	c0 = tmp3 >> 3;
   1746	c1 = tmp4 >> 4;
   1747
   1748out:
   1749	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, c1);
   1750	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF, c0 << 8);
   1751	return ret;
   1752}
   1753
   1754static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
   1755			      u16 wait)
   1756{
   1757	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL,
   1758			0xFFC0, samples - 1);
   1759	if (loops != 0xFFFF)
   1760		loops--;
   1761	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000, loops);
   1762	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL, 0x3F, wait << 6);
   1763	b43_phy_set(dev, B43_LPPHY_A_PHY_CTL_ADDR, 0x1);
   1764}
   1765
   1766//SPEC FIXME what does a negative freq mean?
   1767static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
   1768{
   1769	struct b43_phy_lp *lpphy = dev->phy.lp;
   1770	u16 buf[64];
   1771	int i, samples = 0, theta = 0;
   1772	int rotation = (((36 * freq) / 20) << 16) / 100;
   1773	struct cordic_iq sample;
   1774
   1775	lpphy->tx_tone_freq = freq;
   1776
   1777	if (freq) {
   1778		/* Find i for which abs(freq) integrally divides 20000 * i */
   1779		for (i = 1; samples * abs(freq) != 20000 * i; i++) {
   1780			samples = (20000 * i) / abs(freq);
   1781			if(B43_WARN_ON(samples > 63))
   1782				return;
   1783		}
   1784	} else {
   1785		samples = 2;
   1786	}
   1787
   1788	for (i = 0; i < samples; i++) {
   1789		sample = cordic_calc_iq(CORDIC_FIXED(theta));
   1790		theta += rotation;
   1791		buf[i] = CORDIC_FLOAT((sample.i * max) & 0xFF) << 8;
   1792		buf[i] |= CORDIC_FLOAT((sample.q * max) & 0xFF);
   1793	}
   1794
   1795	b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
   1796
   1797	lpphy_run_samples(dev, samples, 0xFFFF, 0);
   1798}
   1799
   1800static void lpphy_stop_tx_tone(struct b43_wldev *dev)
   1801{
   1802	struct b43_phy_lp *lpphy = dev->phy.lp;
   1803	int i;
   1804
   1805	lpphy->tx_tone_freq = 0;
   1806
   1807	b43_phy_mask(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000);
   1808	for (i = 0; i < 31; i++) {
   1809		if (!(b43_phy_read(dev, B43_LPPHY_A_PHY_CTL_ADDR) & 0x1))
   1810			break;
   1811		udelay(100);
   1812	}
   1813}
   1814
   1815
   1816static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
   1817{
   1818	struct b43_phy_lp *lpphy = dev->phy.lp;
   1819	struct lpphy_tx_gains oldgains;
   1820	int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
   1821
   1822	lpphy_read_tx_pctl_mode_from_hardware(dev);
   1823	old_txpctl = lpphy->txpctl_mode;
   1824	old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
   1825	if (old_afe_ovr)
   1826		oldgains = lpphy_get_tx_gains(dev);
   1827	old_rf = b43_phy_read(dev, B43_LPPHY_RF_PWR_OVERRIDE) & 0xFF;
   1828	old_bbmult = lpphy_get_bb_mult(dev);
   1829
   1830	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
   1831
   1832	if (old_afe_ovr)
   1833		lpphy_set_tx_gains(dev, oldgains);
   1834	lpphy_set_bb_mult(dev, old_bbmult);
   1835	lpphy_set_tx_power_control(dev, old_txpctl);
   1836	b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00, old_rf);
   1837}
   1838
   1839static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
   1840			    bool rx, bool pa, struct lpphy_tx_gains *gains)
   1841{
   1842	struct b43_phy_lp *lpphy = dev->phy.lp;
   1843	const struct lpphy_rx_iq_comp *iqcomp = NULL;
   1844	struct lpphy_tx_gains nogains, oldgains;
   1845	u16 tmp;
   1846	int i, ret;
   1847
   1848	memset(&nogains, 0, sizeof(nogains));
   1849	memset(&oldgains, 0, sizeof(oldgains));
   1850
   1851	if (dev->dev->chip_id == 0x5354) {
   1852		for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
   1853			if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
   1854				iqcomp = &lpphy_5354_iq_table[i];
   1855			}
   1856		}
   1857	} else if (dev->phy.rev >= 2) {
   1858		iqcomp = &lpphy_rev2plus_iq_comp;
   1859	} else {
   1860		for (i = 0; i < ARRAY_SIZE(lpphy_rev0_1_iq_table); i++) {
   1861			if (lpphy_rev0_1_iq_table[i].chan == lpphy->channel) {
   1862				iqcomp = &lpphy_rev0_1_iq_table[i];
   1863			}
   1864		}
   1865	}
   1866
   1867	if (B43_WARN_ON(!iqcomp))
   1868		return 0;
   1869
   1870	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, iqcomp->c1);
   1871	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S,
   1872			0x00FF, iqcomp->c0 << 8);
   1873
   1874	if (noise) {
   1875		tx = true;
   1876		rx = false;
   1877		pa = false;
   1878	}
   1879
   1880	lpphy_set_trsw_over(dev, tx, rx);
   1881
   1882	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
   1883		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
   1884		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
   1885				0xFFF7, pa << 3);
   1886	} else {
   1887		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
   1888		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
   1889				0xFFDF, pa << 5);
   1890	}
   1891
   1892	tmp = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
   1893
   1894	if (noise)
   1895		lpphy_set_rx_gain(dev, 0x2D5D);
   1896	else {
   1897		if (tmp)
   1898			oldgains = lpphy_get_tx_gains(dev);
   1899		if (!gains)
   1900			gains = &nogains;
   1901		lpphy_set_tx_gains(dev, *gains);
   1902	}
   1903
   1904	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
   1905	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
   1906	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
   1907	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
   1908	lpphy_set_deaf(dev, false);
   1909	if (noise)
   1910		ret = lpphy_calc_rx_iq_comp(dev, 0xFFF0);
   1911	else {
   1912		lpphy_start_tx_tone(dev, 4000, 100);
   1913		ret = lpphy_calc_rx_iq_comp(dev, 0x4000);
   1914		lpphy_stop_tx_tone(dev);
   1915	}
   1916	lpphy_clear_deaf(dev, false);
   1917	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFC);
   1918	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
   1919	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFDF);
   1920	if (!noise) {
   1921		if (tmp)
   1922			lpphy_set_tx_gains(dev, oldgains);
   1923		else
   1924			lpphy_disable_tx_gain_override(dev);
   1925	}
   1926	lpphy_disable_rx_gain_override(dev);
   1927	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
   1928	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xF7FF);
   1929	return ret;
   1930}
   1931
   1932static void lpphy_calibration(struct b43_wldev *dev)
   1933{
   1934	struct b43_phy_lp *lpphy = dev->phy.lp;
   1935	enum b43_lpphy_txpctl_mode saved_pctl_mode;
   1936	bool full_cal = false;
   1937
   1938	if (lpphy->full_calib_chan != lpphy->channel) {
   1939		full_cal = true;
   1940		lpphy->full_calib_chan = lpphy->channel;
   1941	}
   1942
   1943	b43_mac_suspend(dev);
   1944
   1945	lpphy_btcoex_override(dev);
   1946	if (dev->phy.rev >= 2)
   1947		lpphy_save_dig_flt_state(dev);
   1948	lpphy_read_tx_pctl_mode_from_hardware(dev);
   1949	saved_pctl_mode = lpphy->txpctl_mode;
   1950	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
   1951	//TODO Perform transmit power table I/Q LO calibration
   1952	if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
   1953		lpphy_pr41573_workaround(dev);
   1954	if ((dev->phy.rev >= 2) && full_cal) {
   1955		lpphy_papd_cal_txpwr(dev);
   1956	}
   1957	lpphy_set_tx_power_control(dev, saved_pctl_mode);
   1958	if (dev->phy.rev >= 2)
   1959		lpphy_restore_dig_flt_state(dev);
   1960	lpphy_rx_iq_cal(dev, true, true, false, false, NULL);
   1961
   1962	b43_mac_enable(dev);
   1963}
   1964
   1965static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
   1966				 u16 set)
   1967{
   1968	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
   1969	b43_write16(dev, B43_MMIO_PHY_DATA,
   1970		    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
   1971}
   1972
   1973static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
   1974{
   1975	/* Register 1 is a 32-bit register. */
   1976	B43_WARN_ON(reg == 1);
   1977	/* LP-PHY needs a special bit set for read access */
   1978	if (dev->phy.rev < 2) {
   1979		if (reg != 0x4001)
   1980			reg |= 0x100;
   1981	} else
   1982		reg |= 0x200;
   1983
   1984	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
   1985	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
   1986}
   1987
   1988static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
   1989{
   1990	/* Register 1 is a 32-bit register. */
   1991	B43_WARN_ON(reg == 1);
   1992
   1993	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
   1994	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
   1995}
   1996
   1997struct b206x_channel {
   1998	u8 channel;
   1999	u16 freq;
   2000	u8 data[12];
   2001};
   2002
   2003static const struct b206x_channel b2062_chantbl[] = {
   2004	{ .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF,
   2005	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2006	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2007	{ .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF,
   2008	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2009	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2010	{ .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF,
   2011	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2012	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2013	{ .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF,
   2014	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2015	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2016	{ .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF,
   2017	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2018	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2019	{ .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF,
   2020	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2021	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2022	{ .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF,
   2023	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2024	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2025	{ .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF,
   2026	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2027	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2028	{ .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF,
   2029	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2030	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2031	{ .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF,
   2032	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2033	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2034	{ .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF,
   2035	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2036	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2037	{ .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF,
   2038	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2039	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2040	{ .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF,
   2041	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2042	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2043	{ .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF,
   2044	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
   2045	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
   2046	{ .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22,
   2047	  .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
   2048	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2049	{ .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11,
   2050	  .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
   2051	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2052	{ .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11,
   2053	  .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
   2054	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2055	{ .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00,
   2056	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
   2057	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2058	{ .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11,
   2059	  .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
   2060	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2061	{ .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11,
   2062	  .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
   2063	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2064	{ .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11,
   2065	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
   2066	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2067	{ .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00,
   2068	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
   2069	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2070	{ .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00,
   2071	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
   2072	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2073	{ .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00,
   2074	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
   2075	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2076	{ .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00,
   2077	  .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77,
   2078	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2079	{ .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00,
   2080	  .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77,
   2081	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2082	{ .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00,
   2083	  .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77,
   2084	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2085	{ .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00,
   2086	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
   2087	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2088	{ .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00,
   2089	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
   2090	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2091	{ .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00,
   2092	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
   2093	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2094	{ .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00,
   2095	  .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77,
   2096	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2097	{ .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00,
   2098	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2099	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2100	{ .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00,
   2101	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2102	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2103	{ .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00,
   2104	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2105	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2106	{ .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00,
   2107	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2108	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2109	{ .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00,
   2110	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2111	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2112	{ .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00,
   2113	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2114	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2115	{ .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00,
   2116	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2117	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2118	{ .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00,
   2119	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2120	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2121	{ .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00,
   2122	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2123	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2124	{ .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00,
   2125	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2126	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2127	{ .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00,
   2128	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
   2129	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
   2130	{ .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77,
   2131	  .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77,
   2132	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
   2133	{ .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77,
   2134	  .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
   2135	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
   2136	{ .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66,
   2137	  .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
   2138	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
   2139	{ .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66,
   2140	  .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
   2141	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
   2142	{ .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55,
   2143	  .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77,
   2144	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
   2145	{ .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55,
   2146	  .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
   2147	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
   2148	{ .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44,
   2149	  .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
   2150	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
   2151	{ .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44,
   2152	  .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77,
   2153	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2154	{ .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44,
   2155	  .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77,
   2156	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
   2157};
   2158
   2159static const struct b206x_channel b2063_chantbl[] = {
   2160	{ .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C,
   2161	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2162	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2163	  .data[10] = 0x80, .data[11] = 0x70, },
   2164	{ .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C,
   2165	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2166	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2167	  .data[10] = 0x80, .data[11] = 0x70, },
   2168	{ .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C,
   2169	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2170	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2171	  .data[10] = 0x80, .data[11] = 0x70, },
   2172	{ .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C,
   2173	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2174	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2175	  .data[10] = 0x80, .data[11] = 0x70, },
   2176	{ .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C,
   2177	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2178	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2179	  .data[10] = 0x80, .data[11] = 0x70, },
   2180	{ .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C,
   2181	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2182	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2183	  .data[10] = 0x80, .data[11] = 0x70, },
   2184	{ .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C,
   2185	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2186	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2187	  .data[10] = 0x80, .data[11] = 0x70, },
   2188	{ .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C,
   2189	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2190	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2191	  .data[10] = 0x80, .data[11] = 0x70, },
   2192	{ .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C,
   2193	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2194	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2195	  .data[10] = 0x80, .data[11] = 0x70, },
   2196	{ .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C,
   2197	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2198	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2199	  .data[10] = 0x80, .data[11] = 0x70, },
   2200	{ .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C,
   2201	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2202	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2203	  .data[10] = 0x80, .data[11] = 0x70, },
   2204	{ .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C,
   2205	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2206	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2207	  .data[10] = 0x80, .data[11] = 0x70, },
   2208	{ .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C,
   2209	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2210	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2211	  .data[10] = 0x80, .data[11] = 0x70, },
   2212	{ .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C,
   2213	  .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
   2214	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
   2215	  .data[10] = 0x80, .data[11] = 0x70, },
   2216	{ .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C,
   2217	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05,
   2218	  .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80,
   2219	  .data[10] = 0x20, .data[11] = 0x00, },
   2220	{ .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C,
   2221	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05,
   2222	  .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
   2223	  .data[10] = 0x20, .data[11] = 0x00, },
   2224	{ .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C,
   2225	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
   2226	  .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
   2227	  .data[10] = 0x20, .data[11] = 0x00, },
   2228	{ .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C,
   2229	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
   2230	  .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
   2231	  .data[10] = 0x20, .data[11] = 0x00, },
   2232	{ .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C,
   2233	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
   2234	  .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
   2235	  .data[10] = 0x20, .data[11] = 0x00, },
   2236	{ .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C,
   2237	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04,
   2238	  .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
   2239	  .data[10] = 0x20, .data[11] = 0x00, },
   2240	{ .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C,
   2241	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
   2242	  .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
   2243	  .data[10] = 0x20, .data[11] = 0x00, },
   2244	{ .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C,
   2245	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
   2246	  .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60,
   2247	  .data[10] = 0x20, .data[11] = 0x00, },
   2248	{ .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C,
   2249	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02,
   2250	  .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60,
   2251	  .data[10] = 0x20, .data[11] = 0x00, },
   2252	{ .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C,
   2253	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
   2254	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
   2255	  .data[10] = 0x10, .data[11] = 0x00, },
   2256	{ .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C,
   2257	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
   2258	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
   2259	  .data[10] = 0x10, .data[11] = 0x00, },
   2260	{ .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C,
   2261	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2262	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
   2263	  .data[10] = 0x10, .data[11] = 0x00, },
   2264	{ .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C,
   2265	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2266	  .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
   2267	  .data[10] = 0x00, .data[11] = 0x00, },
   2268	{ .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C,
   2269	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2270	  .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
   2271	  .data[10] = 0x00, .data[11] = 0x00, },
   2272	{ .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C,
   2273	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2274	  .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
   2275	  .data[10] = 0x00, .data[11] = 0x00, },
   2276	{ .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C,
   2277	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2278	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
   2279	  .data[10] = 0x00, .data[11] = 0x00, },
   2280	{ .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C,
   2281	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2282	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
   2283	  .data[10] = 0x00, .data[11] = 0x00, },
   2284	{ .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C,
   2285	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2286	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2287	  .data[10] = 0x00, .data[11] = 0x00, },
   2288	{ .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C,
   2289	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2290	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2291	  .data[10] = 0x00, .data[11] = 0x00, },
   2292	{ .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C,
   2293	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2294	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2295	  .data[10] = 0x00, .data[11] = 0x00, },
   2296	{ .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C,
   2297	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2298	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2299	  .data[10] = 0x00, .data[11] = 0x00, },
   2300	{ .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C,
   2301	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2302	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2303	  .data[10] = 0x00, .data[11] = 0x00, },
   2304	{ .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C,
   2305	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2306	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2307	  .data[10] = 0x00, .data[11] = 0x00, },
   2308	{ .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C,
   2309	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2310	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2311	  .data[10] = 0x00, .data[11] = 0x00, },
   2312	{ .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C,
   2313	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2314	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2315	  .data[10] = 0x00, .data[11] = 0x00, },
   2316	{ .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C,
   2317	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2318	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2319	  .data[10] = 0x00, .data[11] = 0x00, },
   2320	{ .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C,
   2321	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2322	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2323	  .data[10] = 0x00, .data[11] = 0x00, },
   2324	{ .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C,
   2325	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
   2326	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
   2327	  .data[10] = 0x00, .data[11] = 0x00, },
   2328	{ .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C,
   2329	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E,
   2330	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0,
   2331	  .data[10] = 0x50, .data[11] = 0x00, },
   2332	{ .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C,
   2333	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D,
   2334	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
   2335	  .data[10] = 0x50, .data[11] = 0x00, },
   2336	{ .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C,
   2337	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
   2338	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
   2339	  .data[10] = 0x50, .data[11] = 0x00, },
   2340	{ .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C,
   2341	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
   2342	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
   2343	  .data[10] = 0x40, .data[11] = 0x00, },
   2344	{ .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C,
   2345	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B,
   2346	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
   2347	  .data[10] = 0x40, .data[11] = 0x00, },
   2348	{ .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C,
   2349	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A,
   2350	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
   2351	  .data[10] = 0x40, .data[11] = 0x00, },
   2352	{ .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C,
   2353	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09,
   2354	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
   2355	  .data[10] = 0x40, .data[11] = 0x00, },
   2356	{ .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C,
   2357	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08,
   2358	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
   2359	  .data[10] = 0x40, .data[11] = 0x00, },
   2360	{ .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C,
   2361	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08,
   2362	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
   2363	  .data[10] = 0x40, .data[11] = 0x00, },
   2364};
   2365
   2366static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
   2367{
   2368	b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
   2369	udelay(20);
   2370	if (dev->dev->chip_id == 0x5354) {
   2371		b43_radio_write(dev, B2062_N_COMM1, 4);
   2372		b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4);
   2373	} else {
   2374		b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0);
   2375	}
   2376	udelay(5);
   2377}
   2378
   2379static void lpphy_b2062_vco_calib(struct b43_wldev *dev)
   2380{
   2381	b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x42);
   2382	b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x62);
   2383	udelay(200);
   2384}
   2385
   2386static int lpphy_b2062_tune(struct b43_wldev *dev,
   2387			    unsigned int channel)
   2388{
   2389	struct b43_phy_lp *lpphy = dev->phy.lp;
   2390	struct ssb_bus *bus = dev->dev->sdev->bus;
   2391	const struct b206x_channel *chandata = NULL;
   2392	u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
   2393	u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
   2394	int i, err = 0;
   2395
   2396	for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) {
   2397		if (b2062_chantbl[i].channel == channel) {
   2398			chandata = &b2062_chantbl[i];
   2399			break;
   2400		}
   2401	}
   2402
   2403	if (B43_WARN_ON(!chandata))
   2404		return -EINVAL;
   2405
   2406	b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04);
   2407	b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]);
   2408	b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]);
   2409	b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]);
   2410	b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]);
   2411	b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]);
   2412	b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]);
   2413	b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]);
   2414	b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]);
   2415	b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]);
   2416
   2417	tmp1 = crystal_freq / 1000;
   2418	tmp2 = lpphy->pdiv * 1000;
   2419	b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC);
   2420	b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07);
   2421	lpphy_b2062_reset_pll_bias(dev);
   2422	tmp3 = tmp2 * channel2freq_lp(channel);
   2423	if (channel2freq_lp(channel) < 4000)
   2424		tmp3 *= 2;
   2425	tmp4 = 48 * tmp1;
   2426	tmp6 = tmp3 / tmp4;
   2427	tmp7 = tmp3 % tmp4;
   2428	b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6);
   2429	tmp5 = tmp7 * 0x100;
   2430	tmp6 = tmp5 / tmp4;
   2431	tmp7 = tmp5 % tmp4;
   2432	b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6);
   2433	tmp5 = tmp7 * 0x100;
   2434	tmp6 = tmp5 / tmp4;
   2435	tmp7 = tmp5 % tmp4;
   2436	b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6);
   2437	tmp5 = tmp7 * 0x100;
   2438	tmp6 = tmp5 / tmp4;
   2439	tmp7 = tmp5 % tmp4;
   2440	b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
   2441	tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19);
   2442	tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
   2443	b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16);
   2444	b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
   2445
   2446	lpphy_b2062_vco_calib(dev);
   2447	if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) {
   2448		b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC);
   2449		b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0);
   2450		lpphy_b2062_reset_pll_bias(dev);
   2451		lpphy_b2062_vco_calib(dev);
   2452		if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10)
   2453			err = -EIO;
   2454	}
   2455
   2456	b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04);
   2457	return err;
   2458}
   2459
   2460static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
   2461{
   2462	u16 tmp;
   2463
   2464	b43_radio_mask(dev, B2063_PLL_SP1, ~0x40);
   2465	tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
   2466	b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp);
   2467	udelay(1);
   2468	b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
   2469	udelay(1);
   2470	b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
   2471	udelay(1);
   2472	b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
   2473	udelay(300);
   2474	b43_radio_set(dev, B2063_PLL_SP1, 0x40);
   2475}
   2476
   2477static int lpphy_b2063_tune(struct b43_wldev *dev,
   2478			    unsigned int channel)
   2479{
   2480	struct ssb_bus *bus = dev->dev->sdev->bus;
   2481
   2482	static const struct b206x_channel *chandata = NULL;
   2483	u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
   2484	u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count;
   2485	u16 old_comm15, scale;
   2486	u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
   2487	int i, div = (crystal_freq <= 26000000 ? 1 : 2);
   2488
   2489	for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) {
   2490		if (b2063_chantbl[i].channel == channel) {
   2491			chandata = &b2063_chantbl[i];
   2492			break;
   2493		}
   2494	}
   2495
   2496	if (B43_WARN_ON(!chandata))
   2497		return -EINVAL;
   2498
   2499	b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]);
   2500	b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]);
   2501	b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]);
   2502	b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]);
   2503	b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]);
   2504	b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]);
   2505	b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]);
   2506	b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]);
   2507	b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]);
   2508	b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]);
   2509	b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]);
   2510	b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]);
   2511
   2512	old_comm15 = b43_radio_read(dev, B2063_COMM15);
   2513	b43_radio_set(dev, B2063_COMM15, 0x1E);
   2514
   2515	if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */
   2516		vco_freq = chandata->freq << 1;
   2517	else
   2518		vco_freq = chandata->freq << 2;
   2519
   2520	freqref = crystal_freq * 3;
   2521	val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16);
   2522	val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16);
   2523	val3 = lpphy_qdiv_roundup(vco_freq, 3, 16);
   2524	timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1;
   2525	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2);
   2526	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6,
   2527			  0xFFF8, timeout >> 2);
   2528	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
   2529			  0xFF9F,timeout << 5);
   2530
   2531	timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) +
   2532						999999) / 1000000) + 1;
   2533	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref);
   2534
   2535	count = lpphy_qdiv_roundup(val3, val2 + 16, 16);
   2536	count *= (timeout + 1) * (timeoutref + 1);
   2537	count--;
   2538	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
   2539						0xF0, count >> 8);
   2540	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF);
   2541
   2542	tmp1 = ((val3 * 62500) / freqref) << 4;
   2543	tmp2 = ((val3 * 62500) % freqref) << 4;
   2544	while (tmp2 >= freqref) {
   2545		tmp1++;
   2546		tmp2 -= freqref;
   2547	}
   2548	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4);
   2549	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4);
   2550	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16);
   2551	b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF);
   2552	b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF);
   2553
   2554	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9);
   2555	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88);
   2556	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28);
   2557	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63);
   2558
   2559	tmp3 = ((41 * (val3 - 3000)) /1200) + 27;
   2560	tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16);
   2561
   2562	if ((tmp4 + tmp3 - 1) / tmp3 > 60) {
   2563		scale = 1;
   2564		tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8;
   2565	} else {
   2566		scale = 0;
   2567		tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8;
   2568	}
   2569	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
   2570	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
   2571
   2572	tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16);
   2573	tmp6 *= (tmp5 * 8) * (scale + 1);
   2574	if (tmp6 > 150)
   2575		tmp6 = 0;
   2576
   2577	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
   2578	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
   2579
   2580	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
   2581	if (crystal_freq > 26000000)
   2582		b43_radio_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2);
   2583	else
   2584		b43_radio_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD);
   2585
   2586	if (val1 == 45)
   2587		b43_radio_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2);
   2588	else
   2589		b43_radio_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD);
   2590
   2591	b43_radio_set(dev, B2063_PLL_SP2, 0x3);
   2592	udelay(1);
   2593	b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC);
   2594	lpphy_b2063_vco_calib(dev);
   2595	b43_radio_write(dev, B2063_COMM15, old_comm15);
   2596
   2597	return 0;
   2598}
   2599
   2600static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
   2601				       unsigned int new_channel)
   2602{
   2603	struct b43_phy_lp *lpphy = dev->phy.lp;
   2604	int err;
   2605
   2606	if (dev->phy.radio_ver == 0x2063) {
   2607		err = lpphy_b2063_tune(dev, new_channel);
   2608		if (err)
   2609			return err;
   2610	} else {
   2611		err = lpphy_b2062_tune(dev, new_channel);
   2612		if (err)
   2613			return err;
   2614		lpphy_set_analog_filter(dev, new_channel);
   2615		lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));
   2616	}
   2617
   2618	lpphy->channel = new_channel;
   2619	b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
   2620
   2621	return 0;
   2622}
   2623
   2624static int b43_lpphy_op_init(struct b43_wldev *dev)
   2625{
   2626	int err;
   2627
   2628	if (dev->dev->bus_type != B43_BUS_SSB) {
   2629		b43err(dev->wl, "LP-PHY is supported only on SSB!\n");
   2630		return -EOPNOTSUPP;
   2631	}
   2632
   2633	lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
   2634	lpphy_baseband_init(dev);
   2635	lpphy_radio_init(dev);
   2636	lpphy_calibrate_rc(dev);
   2637	err = b43_lpphy_op_switch_channel(dev, 7);
   2638	if (err) {
   2639		b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n",
   2640		       err);
   2641	}
   2642	lpphy_tx_pctl_init(dev);
   2643	lpphy_calibration(dev);
   2644	//TODO ACI init
   2645
   2646	return 0;
   2647}
   2648
   2649static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
   2650{
   2651	//TODO
   2652}
   2653
   2654static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
   2655							 bool ignore_tssi)
   2656{
   2657	//TODO
   2658	return B43_TXPWR_RES_DONE;
   2659}
   2660
   2661static void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
   2662{
   2663       if (on) {
   2664               b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
   2665       } else {
   2666               b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0x0007);
   2667               b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x0007);
   2668       }
   2669}
   2670
   2671static void b43_lpphy_op_pwork_15sec(struct b43_wldev *dev)
   2672{
   2673	//TODO
   2674}
   2675
   2676const struct b43_phy_operations b43_phyops_lp = {
   2677	.allocate		= b43_lpphy_op_allocate,
   2678	.free			= b43_lpphy_op_free,
   2679	.prepare_structs	= b43_lpphy_op_prepare_structs,
   2680	.init			= b43_lpphy_op_init,
   2681	.phy_maskset		= b43_lpphy_op_maskset,
   2682	.radio_read		= b43_lpphy_op_radio_read,
   2683	.radio_write		= b43_lpphy_op_radio_write,
   2684	.software_rfkill	= b43_lpphy_op_software_rfkill,
   2685	.switch_analog		= b43_lpphy_op_switch_analog,
   2686	.switch_channel		= b43_lpphy_op_switch_channel,
   2687	.get_default_chan	= b43_lpphy_op_get_default_chan,
   2688	.set_rx_antenna		= b43_lpphy_op_set_rx_antenna,
   2689	.recalc_txpower		= b43_lpphy_op_recalc_txpower,
   2690	.adjust_txpower		= b43_lpphy_op_adjust_txpower,
   2691	.pwork_15sec		= b43_lpphy_op_pwork_15sec,
   2692	.pwork_60sec		= lpphy_calibration,
   2693};