162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci  Broadcom B43 wireless driver
562306a36Sopenharmony_ci  IEEE 802.11a/g LP-PHY driver
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci  Copyright (c) 2008-2009 Michael Buesch <m@bues.ch>
862306a36Sopenharmony_ci  Copyright (c) 2009 Gábor Stefanik <netrolller.3d@gmail.com>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci*/
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/cordic.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "b43.h"
1762306a36Sopenharmony_ci#include "main.h"
1862306a36Sopenharmony_ci#include "phy_lp.h"
1962306a36Sopenharmony_ci#include "phy_common.h"
2062306a36Sopenharmony_ci#include "tables_lpphy.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic inline u16 channel2freq_lp(u8 channel)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	if (channel < 14)
2662306a36Sopenharmony_ci		return (2407 + 5 * channel);
2762306a36Sopenharmony_ci	else if (channel == 14)
2862306a36Sopenharmony_ci		return 2484;
2962306a36Sopenharmony_ci	else if (channel < 184)
3062306a36Sopenharmony_ci		return (5000 + 5 * channel);
3162306a36Sopenharmony_ci	else
3262306a36Sopenharmony_ci		return (4000 + 5 * channel);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
3862306a36Sopenharmony_ci		return 1;
3962306a36Sopenharmony_ci	return 36;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int b43_lpphy_op_allocate(struct b43_wldev *dev)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct b43_phy_lp *lpphy;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	lpphy = kzalloc(sizeof(*lpphy), GFP_KERNEL);
4762306a36Sopenharmony_ci	if (!lpphy)
4862306a36Sopenharmony_ci		return -ENOMEM;
4962306a36Sopenharmony_ci	dev->phy.lp = lpphy;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return 0;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct b43_phy *phy = &dev->phy;
5762306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = phy->lp;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	memset(lpphy, 0, sizeof(*lpphy));
6062306a36Sopenharmony_ci	lpphy->antenna = B43_ANTENNA_DEFAULT;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	//TODO
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void b43_lpphy_op_free(struct b43_wldev *dev)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	kfree(lpphy);
7062306a36Sopenharmony_ci	dev->phy.lp = NULL;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* https://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */
7462306a36Sopenharmony_cistatic void lpphy_read_band_sprom(struct b43_wldev *dev)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct ssb_sprom *sprom = dev->dev->bus_sprom;
7762306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
7862306a36Sopenharmony_ci	u16 cckpo, maxpwr;
7962306a36Sopenharmony_ci	u32 ofdmpo;
8062306a36Sopenharmony_ci	int i;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
8362306a36Sopenharmony_ci		lpphy->tx_isolation_med_band = sprom->tri2g;
8462306a36Sopenharmony_ci		lpphy->bx_arch = sprom->bxa2g;
8562306a36Sopenharmony_ci		lpphy->rx_pwr_offset = sprom->rxpo2g;
8662306a36Sopenharmony_ci		lpphy->rssi_vf = sprom->rssismf2g;
8762306a36Sopenharmony_ci		lpphy->rssi_vc = sprom->rssismc2g;
8862306a36Sopenharmony_ci		lpphy->rssi_gs = sprom->rssisav2g;
8962306a36Sopenharmony_ci		lpphy->txpa[0] = sprom->pa0b0;
9062306a36Sopenharmony_ci		lpphy->txpa[1] = sprom->pa0b1;
9162306a36Sopenharmony_ci		lpphy->txpa[2] = sprom->pa0b2;
9262306a36Sopenharmony_ci		maxpwr = sprom->maxpwr_bg;
9362306a36Sopenharmony_ci		lpphy->max_tx_pwr_med_band = maxpwr;
9462306a36Sopenharmony_ci		cckpo = sprom->cck2gpo;
9562306a36Sopenharmony_ci		if (cckpo) {
9662306a36Sopenharmony_ci			ofdmpo = sprom->ofdm2gpo;
9762306a36Sopenharmony_ci			for (i = 0; i < 4; i++) {
9862306a36Sopenharmony_ci				lpphy->tx_max_rate[i] =
9962306a36Sopenharmony_ci					maxpwr - (ofdmpo & 0xF) * 2;
10062306a36Sopenharmony_ci				ofdmpo >>= 4;
10162306a36Sopenharmony_ci			}
10262306a36Sopenharmony_ci			ofdmpo = sprom->ofdm2gpo;
10362306a36Sopenharmony_ci			for (i = 4; i < 15; i++) {
10462306a36Sopenharmony_ci				lpphy->tx_max_rate[i] =
10562306a36Sopenharmony_ci					maxpwr - (ofdmpo & 0xF) * 2;
10662306a36Sopenharmony_ci				ofdmpo >>= 4;
10762306a36Sopenharmony_ci			}
10862306a36Sopenharmony_ci		} else {
10962306a36Sopenharmony_ci			u8 opo = sprom->opo;
11062306a36Sopenharmony_ci			for (i = 0; i < 4; i++)
11162306a36Sopenharmony_ci				lpphy->tx_max_rate[i] = maxpwr;
11262306a36Sopenharmony_ci			for (i = 4; i < 15; i++)
11362306a36Sopenharmony_ci				lpphy->tx_max_rate[i] = maxpwr - opo;
11462306a36Sopenharmony_ci		}
11562306a36Sopenharmony_ci	} else { /* 5GHz */
11662306a36Sopenharmony_ci		lpphy->tx_isolation_low_band = sprom->tri5gl;
11762306a36Sopenharmony_ci		lpphy->tx_isolation_med_band = sprom->tri5g;
11862306a36Sopenharmony_ci		lpphy->tx_isolation_hi_band = sprom->tri5gh;
11962306a36Sopenharmony_ci		lpphy->bx_arch = sprom->bxa5g;
12062306a36Sopenharmony_ci		lpphy->rx_pwr_offset = sprom->rxpo5g;
12162306a36Sopenharmony_ci		lpphy->rssi_vf = sprom->rssismf5g;
12262306a36Sopenharmony_ci		lpphy->rssi_vc = sprom->rssismc5g;
12362306a36Sopenharmony_ci		lpphy->rssi_gs = sprom->rssisav5g;
12462306a36Sopenharmony_ci		lpphy->txpa[0] = sprom->pa1b0;
12562306a36Sopenharmony_ci		lpphy->txpa[1] = sprom->pa1b1;
12662306a36Sopenharmony_ci		lpphy->txpa[2] = sprom->pa1b2;
12762306a36Sopenharmony_ci		lpphy->txpal[0] = sprom->pa1lob0;
12862306a36Sopenharmony_ci		lpphy->txpal[1] = sprom->pa1lob1;
12962306a36Sopenharmony_ci		lpphy->txpal[2] = sprom->pa1lob2;
13062306a36Sopenharmony_ci		lpphy->txpah[0] = sprom->pa1hib0;
13162306a36Sopenharmony_ci		lpphy->txpah[1] = sprom->pa1hib1;
13262306a36Sopenharmony_ci		lpphy->txpah[2] = sprom->pa1hib2;
13362306a36Sopenharmony_ci		maxpwr = sprom->maxpwr_al;
13462306a36Sopenharmony_ci		ofdmpo = sprom->ofdm5glpo;
13562306a36Sopenharmony_ci		lpphy->max_tx_pwr_low_band = maxpwr;
13662306a36Sopenharmony_ci		for (i = 4; i < 12; i++) {
13762306a36Sopenharmony_ci			lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2;
13862306a36Sopenharmony_ci			ofdmpo >>= 4;
13962306a36Sopenharmony_ci		}
14062306a36Sopenharmony_ci		maxpwr = sprom->maxpwr_a;
14162306a36Sopenharmony_ci		ofdmpo = sprom->ofdm5gpo;
14262306a36Sopenharmony_ci		lpphy->max_tx_pwr_med_band = maxpwr;
14362306a36Sopenharmony_ci		for (i = 4; i < 12; i++) {
14462306a36Sopenharmony_ci			lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2;
14562306a36Sopenharmony_ci			ofdmpo >>= 4;
14662306a36Sopenharmony_ci		}
14762306a36Sopenharmony_ci		maxpwr = sprom->maxpwr_ah;
14862306a36Sopenharmony_ci		ofdmpo = sprom->ofdm5ghpo;
14962306a36Sopenharmony_ci		lpphy->max_tx_pwr_hi_band = maxpwr;
15062306a36Sopenharmony_ci		for (i = 4; i < 12; i++) {
15162306a36Sopenharmony_ci			lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2;
15262306a36Sopenharmony_ci			ofdmpo >>= 4;
15362306a36Sopenharmony_ci		}
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic void lpphy_adjust_gain_table(struct b43_wldev *dev, u32 freq)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
16062306a36Sopenharmony_ci	u16 temp[3];
16162306a36Sopenharmony_ci	u16 isolation;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	B43_WARN_ON(dev->phy.rev >= 2);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
16662306a36Sopenharmony_ci		isolation = lpphy->tx_isolation_med_band;
16762306a36Sopenharmony_ci	else if (freq <= 5320)
16862306a36Sopenharmony_ci		isolation = lpphy->tx_isolation_low_band;
16962306a36Sopenharmony_ci	else if (freq <= 5700)
17062306a36Sopenharmony_ci		isolation = lpphy->tx_isolation_med_band;
17162306a36Sopenharmony_ci	else
17262306a36Sopenharmony_ci		isolation = lpphy->tx_isolation_hi_band;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	temp[0] = ((isolation - 26) / 12) << 12;
17562306a36Sopenharmony_ci	temp[1] = temp[0] + 0x1000;
17662306a36Sopenharmony_ci	temp[2] = temp[0] + 0x2000;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	b43_lptab_write_bulk(dev, B43_LPTAB16(13, 0), 3, temp);
17962306a36Sopenharmony_ci	b43_lptab_write_bulk(dev, B43_LPTAB16(12, 0), 3, temp);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic void lpphy_table_init(struct b43_wldev *dev)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	u32 freq = channel2freq_lp(b43_lpphy_op_get_default_chan(dev));
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (dev->phy.rev < 2)
18762306a36Sopenharmony_ci		lpphy_rev0_1_table_init(dev);
18862306a36Sopenharmony_ci	else
18962306a36Sopenharmony_ci		lpphy_rev2plus_table_init(dev);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	lpphy_init_tx_gain_table(dev);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (dev->phy.rev < 2)
19462306a36Sopenharmony_ci		lpphy_adjust_gain_table(dev, freq);
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct ssb_bus *bus = dev->dev->sdev->bus;
20062306a36Sopenharmony_ci	struct ssb_sprom *sprom = dev->dev->bus_sprom;
20162306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
20262306a36Sopenharmony_ci	u16 tmp, tmp2;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_DAC_CTL, 0xF7FF);
20562306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0);
20662306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
20762306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
20862306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
20962306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_AFE_DAC_CTL, 0x0004);
21062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0x0078);
21162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
21262306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x0016);
21362306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_0, 0xFFF8, 0x0004);
21462306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5400);
21562306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2400);
21662306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
21762306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0x0006);
21862306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RX_RADIO_CTL, 0xFFFE);
21962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x0005);
22062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0x0180);
22162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x3C00);
22262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFFF0, 0x0005);
22362306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_GAIN_MISMATCH_LIMIT, 0xFFC0, 0x001A);
22462306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0x00B3);
22562306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
22662306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB,
22762306a36Sopenharmony_ci			0xFF00, lpphy->rx_pwr_offset);
22862306a36Sopenharmony_ci	if ((sprom->boardflags_lo & B43_BFL_FEM) &&
22962306a36Sopenharmony_ci	   ((b43_current_band(dev->wl) == NL80211_BAND_5GHZ) ||
23062306a36Sopenharmony_ci	   (sprom->boardflags_hi & B43_BFH_PAREF))) {
23162306a36Sopenharmony_ci		ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28);
23262306a36Sopenharmony_ci		ssb_pmu_set_ldo_paref(&bus->chipco, true);
23362306a36Sopenharmony_ci		if (dev->phy.rev == 0) {
23462306a36Sopenharmony_ci			b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
23562306a36Sopenharmony_ci					0xFFCF, 0x0010);
23662306a36Sopenharmony_ci		}
23762306a36Sopenharmony_ci		b43_lptab_write(dev, B43_LPTAB16(11, 7), 60);
23862306a36Sopenharmony_ci	} else {
23962306a36Sopenharmony_ci		ssb_pmu_set_ldo_paref(&bus->chipco, false);
24062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_LP_RF_SIGNAL_LUT,
24162306a36Sopenharmony_ci				0xFFCF, 0x0020);
24262306a36Sopenharmony_ci		b43_lptab_write(dev, B43_LPTAB16(11, 7), 100);
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci	tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000;
24562306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp);
24662306a36Sopenharmony_ci	if (sprom->boardflags_hi & B43_BFH_RSSIINV)
24762306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA);
24862306a36Sopenharmony_ci	else
24962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA);
25062306a36Sopenharmony_ci	b43_lptab_write(dev, B43_LPTAB16(11, 1), 24);
25162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL,
25262306a36Sopenharmony_ci			0xFFF9, (lpphy->bx_arch << 1));
25362306a36Sopenharmony_ci	if (dev->phy.rev == 1 &&
25462306a36Sopenharmony_ci	   (sprom->boardflags_hi & B43_BFH_FEM_BT)) {
25562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
25662306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900);
25762306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
25862306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
25962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A);
26062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400);
26162306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A);
26262306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00);
26362306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A);
26462306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900);
26562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A);
26662306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00);
26762306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A);
26862306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900);
26962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
27062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
27162306a36Sopenharmony_ci	} else if (b43_current_band(dev->wl) == NL80211_BAND_5GHZ ||
27262306a36Sopenharmony_ci		   (dev->dev->board_type == SSB_BOARD_BU4312) ||
27362306a36Sopenharmony_ci		   (dev->phy.rev == 0 && (sprom->boardflags_lo & B43_BFL_FEM))) {
27462306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
27562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
27662306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
27762306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500);
27862306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
27962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800);
28062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
28162306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00);
28262306a36Sopenharmony_ci	} else if (dev->phy.rev == 1 ||
28362306a36Sopenharmony_ci		  (sprom->boardflags_lo & B43_BFL_FEM)) {
28462306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004);
28562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800);
28662306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004);
28762306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00);
28862306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
28962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100);
29062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
29162306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300);
29262306a36Sopenharmony_ci	} else {
29362306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
29462306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900);
29562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
29662306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
29762306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006);
29862306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500);
29962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
30062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci	if (dev->phy.rev == 1 && (sprom->boardflags_hi & B43_BFH_PAREF)) {
30362306a36Sopenharmony_ci		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1);
30462306a36Sopenharmony_ci		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2);
30562306a36Sopenharmony_ci		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3);
30662306a36Sopenharmony_ci		b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4);
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci	if ((sprom->boardflags_hi & B43_BFH_FEM_BT) &&
30962306a36Sopenharmony_ci	    (dev->dev->chip_id == 0x5354) &&
31062306a36Sopenharmony_ci	    (dev->dev->chip_pkg == SSB_CHIPPACK_BCM4712S)) {
31162306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
31262306a36Sopenharmony_ci		b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
31362306a36Sopenharmony_ci		b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
31462306a36Sopenharmony_ci		//FIXME the Broadcom driver caches & delays this HF write!
31562306a36Sopenharmony_ci		b43_hf_write(dev, b43_hf_read(dev) | B43_HF_PR45960W);
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
31862306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000);
31962306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040);
32062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400);
32162306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00);
32262306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007);
32362306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003);
32462306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020);
32562306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
32662306a36Sopenharmony_ci	} else { /* 5GHz */
32762306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF);
32862306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF);
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci	if (dev->phy.rev == 1) {
33162306a36Sopenharmony_ci		tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH);
33262306a36Sopenharmony_ci		tmp2 = (tmp & 0x03E0) >> 5;
33362306a36Sopenharmony_ci		tmp2 |= tmp2 << 5;
33462306a36Sopenharmony_ci		b43_phy_write(dev, B43_LPPHY_4C3, tmp2);
33562306a36Sopenharmony_ci		tmp = b43_phy_read(dev, B43_LPPHY_GAINDIRECTMISMATCH);
33662306a36Sopenharmony_ci		tmp2 = (tmp & 0x1F00) >> 8;
33762306a36Sopenharmony_ci		tmp2 |= tmp2 << 5;
33862306a36Sopenharmony_ci		b43_phy_write(dev, B43_LPPHY_4C4, tmp2);
33962306a36Sopenharmony_ci		tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB);
34062306a36Sopenharmony_ci		tmp2 = tmp & 0x00FF;
34162306a36Sopenharmony_ci		tmp2 |= tmp << 8;
34262306a36Sopenharmony_ci		b43_phy_write(dev, B43_LPPHY_4C5, tmp2);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void lpphy_save_dig_flt_state(struct b43_wldev *dev)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	static const u16 addr[] = {
34962306a36Sopenharmony_ci		B43_PHY_OFDM(0xC1),
35062306a36Sopenharmony_ci		B43_PHY_OFDM(0xC2),
35162306a36Sopenharmony_ci		B43_PHY_OFDM(0xC3),
35262306a36Sopenharmony_ci		B43_PHY_OFDM(0xC4),
35362306a36Sopenharmony_ci		B43_PHY_OFDM(0xC5),
35462306a36Sopenharmony_ci		B43_PHY_OFDM(0xC6),
35562306a36Sopenharmony_ci		B43_PHY_OFDM(0xC7),
35662306a36Sopenharmony_ci		B43_PHY_OFDM(0xC8),
35762306a36Sopenharmony_ci		B43_PHY_OFDM(0xCF),
35862306a36Sopenharmony_ci	};
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	static const u16 coefs[] = {
36162306a36Sopenharmony_ci		0xDE5E, 0xE832, 0xE331, 0x4D26,
36262306a36Sopenharmony_ci		0x0026, 0x1420, 0x0020, 0xFE08,
36362306a36Sopenharmony_ci		0x0008,
36462306a36Sopenharmony_ci	};
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
36762306a36Sopenharmony_ci	int i;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(addr); i++) {
37062306a36Sopenharmony_ci		lpphy->dig_flt_state[i] = b43_phy_read(dev, addr[i]);
37162306a36Sopenharmony_ci		b43_phy_write(dev, addr[i], coefs[i]);
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	static const u16 addr[] = {
37862306a36Sopenharmony_ci		B43_PHY_OFDM(0xC1),
37962306a36Sopenharmony_ci		B43_PHY_OFDM(0xC2),
38062306a36Sopenharmony_ci		B43_PHY_OFDM(0xC3),
38162306a36Sopenharmony_ci		B43_PHY_OFDM(0xC4),
38262306a36Sopenharmony_ci		B43_PHY_OFDM(0xC5),
38362306a36Sopenharmony_ci		B43_PHY_OFDM(0xC6),
38462306a36Sopenharmony_ci		B43_PHY_OFDM(0xC7),
38562306a36Sopenharmony_ci		B43_PHY_OFDM(0xC8),
38662306a36Sopenharmony_ci		B43_PHY_OFDM(0xCF),
38762306a36Sopenharmony_ci	};
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
39062306a36Sopenharmony_ci	int i;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(addr); i++)
39362306a36Sopenharmony_ci		b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50);
40162306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_CTL, 0x8800);
40262306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, 0);
40362306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0);
40462306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, 0);
40562306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0);
40662306a36Sopenharmony_ci	b43_phy_write(dev, B43_PHY_OFDM(0xF9), 0);
40762306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_TR_LOOKUP_1, 0);
40862306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_ADC_COMPENSATION_CTL, 0x10);
40962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_OFDMSYNCTHRESH0, 0xFF00, 0xB4);
41062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xF8FF, 0x200);
41162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_DCOFFSETTRANSIENT, 0xFF00, 0x7F);
41262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xFF0F, 0x40);
41362306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_PREAMBLECONFIRMTO, 0xFF00, 0x2);
41462306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000);
41562306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000);
41662306a36Sopenharmony_ci	b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1);
41762306a36Sopenharmony_ci	if (dev->dev->board_rev >= 0x18) {
41862306a36Sopenharmony_ci		b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC);
41962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14);
42062306a36Sopenharmony_ci	} else {
42162306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x10);
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0xFF00, 0xF4);
42462306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xDF), 0x00FF, 0xF100);
42562306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_CLIPTHRESH, 0x48);
42662306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0xFF00, 0x46);
42762306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xE4), 0xFF00, 0x10);
42862306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_PWR_THRESH1, 0xFFF0, 0x9);
42962306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_GAINDIRECTMISMATCH, ~0xF);
43062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0x00FF, 0x5500);
43162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0);
43262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300);
43362306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00);
43462306a36Sopenharmony_ci	if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
43562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
43662306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xA);
43762306a36Sopenharmony_ci	} else {
43862306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x1E00);
43962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xD);
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xFE), 0xFFE0, 0x1F);
44262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0xFFE0, 0xC);
44362306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0x100), 0xFF00, 0x19);
44462306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0x03FF, 0x3C00);
44562306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xFE), 0xFC1F, 0x3E0);
44662306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xFF), 0xFFE0, 0xC);
44762306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0x100), 0x00FF, 0x1900);
44862306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0x83FF, 0x5800);
44962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12);
45062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
45362306a36Sopenharmony_ci		b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
45462306a36Sopenharmony_ci		b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
45862306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x40);
45962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0xB00);
46062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x6);
46162306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0x9D00);
46262306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0xFF00, 0xA1);
46362306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
46462306a36Sopenharmony_ci	} else /* 5GHz */
46562306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x40);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0xFF00, 0xB3);
46862306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
46962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB, 0xFF00, lpphy->rx_pwr_offset);
47062306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RESET_CTL, 0x44);
47162306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RESET_CTL, 0x80);
47262306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, 0xA954);
47362306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_1,
47462306a36Sopenharmony_ci		      0x2000 | ((u16)lpphy->rssi_gs << 10) |
47562306a36Sopenharmony_ci		      ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
47862306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C);
47962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800);
48062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400);
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	lpphy_save_dig_flt_state(dev);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic void lpphy_baseband_init(struct b43_wldev *dev)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	lpphy_table_init(dev);
48962306a36Sopenharmony_ci	if (dev->phy.rev >= 2)
49062306a36Sopenharmony_ci		lpphy_baseband_rev2plus_init(dev);
49162306a36Sopenharmony_ci	else
49262306a36Sopenharmony_ci		lpphy_baseband_rev0_1_init(dev);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistruct b2062_freqdata {
49662306a36Sopenharmony_ci	u16 freq;
49762306a36Sopenharmony_ci	u8 data[6];
49862306a36Sopenharmony_ci};
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci/* Initialize the 2062 radio. */
50162306a36Sopenharmony_cistatic void lpphy_2062_init(struct b43_wldev *dev)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
50462306a36Sopenharmony_ci	struct ssb_bus *bus = dev->dev->sdev->bus;
50562306a36Sopenharmony_ci	u32 crystalfreq, tmp, ref;
50662306a36Sopenharmony_ci	unsigned int i;
50762306a36Sopenharmony_ci	const struct b2062_freqdata *fd = NULL;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	static const struct b2062_freqdata freqdata_tab[] = {
51062306a36Sopenharmony_ci		{ .freq = 12000, .data[0] =  6, .data[1] =  6, .data[2] =  6,
51162306a36Sopenharmony_ci				 .data[3] =  6, .data[4] = 10, .data[5] =  6, },
51262306a36Sopenharmony_ci		{ .freq = 13000, .data[0] =  4, .data[1] =  4, .data[2] =  4,
51362306a36Sopenharmony_ci				 .data[3] =  4, .data[4] = 11, .data[5] =  7, },
51462306a36Sopenharmony_ci		{ .freq = 14400, .data[0] =  3, .data[1] =  3, .data[2] =  3,
51562306a36Sopenharmony_ci				 .data[3] =  3, .data[4] = 12, .data[5] =  7, },
51662306a36Sopenharmony_ci		{ .freq = 16200, .data[0] =  3, .data[1] =  3, .data[2] =  3,
51762306a36Sopenharmony_ci				 .data[3] =  3, .data[4] = 13, .data[5] =  8, },
51862306a36Sopenharmony_ci		{ .freq = 18000, .data[0] =  2, .data[1] =  2, .data[2] =  2,
51962306a36Sopenharmony_ci				 .data[3] =  2, .data[4] = 14, .data[5] =  8, },
52062306a36Sopenharmony_ci		{ .freq = 19200, .data[0] =  1, .data[1] =  1, .data[2] =  1,
52162306a36Sopenharmony_ci				 .data[3] =  1, .data[4] = 14, .data[5] =  9, },
52262306a36Sopenharmony_ci	};
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	b2062_upload_init_table(dev);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_CTL3, 0);
52762306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_CTL4, 0);
52862306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_CTL5, 0);
52962306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_CTL6, 0);
53062306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_PDN_CTL0, 0x40);
53162306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_PDN_CTL0, 0);
53262306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_CALIB_TS, 0x10);
53362306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_CALIB_TS, 0);
53462306a36Sopenharmony_ci	if (dev->phy.rev > 0) {
53562306a36Sopenharmony_ci		b43_radio_write(dev, B2062_S_BG_CTL1,
53662306a36Sopenharmony_ci			(b43_radio_read(dev, B2062_N_COMM2) >> 1) | 0x80);
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
53962306a36Sopenharmony_ci		b43_radio_set(dev, B2062_N_TSSI_CTL0, 0x1);
54062306a36Sopenharmony_ci	else
54162306a36Sopenharmony_ci		b43_radio_mask(dev, B2062_N_TSSI_CTL0, ~0x1);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* Get the crystal freq, in Hz. */
54462306a36Sopenharmony_ci	crystalfreq = bus->chipco.pmu.crystalfreq * 1000;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	B43_WARN_ON(!(bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU));
54762306a36Sopenharmony_ci	B43_WARN_ON(crystalfreq == 0);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (crystalfreq <= 30000000) {
55062306a36Sopenharmony_ci		lpphy->pdiv = 1;
55162306a36Sopenharmony_ci		b43_radio_mask(dev, B2062_S_RFPLL_CTL1, 0xFFFB);
55262306a36Sopenharmony_ci	} else {
55362306a36Sopenharmony_ci		lpphy->pdiv = 2;
55462306a36Sopenharmony_ci		b43_radio_set(dev, B2062_S_RFPLL_CTL1, 0x4);
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	tmp = (((800000000 * lpphy->pdiv + crystalfreq) /
55862306a36Sopenharmony_ci	      (2 * crystalfreq)) - 8) & 0xFF;
55962306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL7, tmp);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	tmp = (((100 * crystalfreq + 16000000 * lpphy->pdiv) /
56262306a36Sopenharmony_ci	      (32000000 * lpphy->pdiv)) - 1) & 0xFF;
56362306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL18, tmp);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	tmp = (((2 * crystalfreq + 1000000 * lpphy->pdiv) /
56662306a36Sopenharmony_ci	      (2000000 * lpphy->pdiv)) - 1) & 0xFF;
56762306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL19, tmp);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	ref = (1000 * lpphy->pdiv + 2 * crystalfreq) / (2000 * lpphy->pdiv);
57062306a36Sopenharmony_ci	ref &= 0xFFFF;
57162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(freqdata_tab); i++) {
57262306a36Sopenharmony_ci		if (ref < freqdata_tab[i].freq) {
57362306a36Sopenharmony_ci			fd = &freqdata_tab[i];
57462306a36Sopenharmony_ci			break;
57562306a36Sopenharmony_ci		}
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci	if (!fd)
57862306a36Sopenharmony_ci		fd = &freqdata_tab[ARRAY_SIZE(freqdata_tab) - 1];
57962306a36Sopenharmony_ci	b43dbg(dev->wl, "b2062: Using crystal tab entry %u kHz.\n",
58062306a36Sopenharmony_ci	       fd->freq); /* FIXME: Keep this printk until the code is fully debugged. */
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL8,
58362306a36Sopenharmony_ci			((u16)(fd->data[1]) << 4) | fd->data[0]);
58462306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL9,
58562306a36Sopenharmony_ci			((u16)(fd->data[3]) << 4) | fd->data[2]);
58662306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL10, fd->data[4]);
58762306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL11, fd->data[5]);
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/* Initialize the 2063 radio. */
59162306a36Sopenharmony_cistatic void lpphy_2063_init(struct b43_wldev *dev)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	b2063_upload_init_table(dev);
59462306a36Sopenharmony_ci	b43_radio_write(dev, B2063_LOGEN_SP5, 0);
59562306a36Sopenharmony_ci	b43_radio_set(dev, B2063_COMM8, 0x38);
59662306a36Sopenharmony_ci	b43_radio_write(dev, B2063_REG_SP1, 0x56);
59762306a36Sopenharmony_ci	b43_radio_mask(dev, B2063_RX_BB_CTL2, ~0x2);
59862306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PA_SP7, 0);
59962306a36Sopenharmony_ci	b43_radio_write(dev, B2063_TX_RF_SP6, 0x20);
60062306a36Sopenharmony_ci	b43_radio_write(dev, B2063_TX_RF_SP9, 0x40);
60162306a36Sopenharmony_ci	if (dev->phy.rev == 2) {
60262306a36Sopenharmony_ci		b43_radio_write(dev, B2063_PA_SP3, 0xa0);
60362306a36Sopenharmony_ci		b43_radio_write(dev, B2063_PA_SP4, 0xa0);
60462306a36Sopenharmony_ci		b43_radio_write(dev, B2063_PA_SP2, 0x18);
60562306a36Sopenharmony_ci	} else {
60662306a36Sopenharmony_ci		b43_radio_write(dev, B2063_PA_SP3, 0x20);
60762306a36Sopenharmony_ci		b43_radio_write(dev, B2063_PA_SP2, 0x20);
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistruct lpphy_stx_table_entry {
61262306a36Sopenharmony_ci	u16 phy_offset;
61362306a36Sopenharmony_ci	u16 phy_shift;
61462306a36Sopenharmony_ci	u16 rf_addr;
61562306a36Sopenharmony_ci	u16 rf_shift;
61662306a36Sopenharmony_ci	u16 mask;
61762306a36Sopenharmony_ci};
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic const struct lpphy_stx_table_entry lpphy_stx_table[] = {
62062306a36Sopenharmony_ci	{ .phy_offset = 2, .phy_shift = 6, .rf_addr = 0x3d, .rf_shift = 3, .mask = 0x01, },
62162306a36Sopenharmony_ci	{ .phy_offset = 1, .phy_shift = 12, .rf_addr = 0x4c, .rf_shift = 1, .mask = 0x01, },
62262306a36Sopenharmony_ci	{ .phy_offset = 1, .phy_shift = 8, .rf_addr = 0x50, .rf_shift = 0, .mask = 0x7f, },
62362306a36Sopenharmony_ci	{ .phy_offset = 0, .phy_shift = 8, .rf_addr = 0x44, .rf_shift = 0, .mask = 0xff, },
62462306a36Sopenharmony_ci	{ .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4a, .rf_shift = 0, .mask = 0xff, },
62562306a36Sopenharmony_ci	{ .phy_offset = 0, .phy_shift = 4, .rf_addr = 0x4d, .rf_shift = 0, .mask = 0xff, },
62662306a36Sopenharmony_ci	{ .phy_offset = 1, .phy_shift = 4, .rf_addr = 0x4e, .rf_shift = 0, .mask = 0xff, },
62762306a36Sopenharmony_ci	{ .phy_offset = 0, .phy_shift = 12, .rf_addr = 0x4f, .rf_shift = 0, .mask = 0x0f, },
62862306a36Sopenharmony_ci	{ .phy_offset = 1, .phy_shift = 0, .rf_addr = 0x4f, .rf_shift = 4, .mask = 0x0f, },
62962306a36Sopenharmony_ci	{ .phy_offset = 3, .phy_shift = 0, .rf_addr = 0x49, .rf_shift = 0, .mask = 0x0f, },
63062306a36Sopenharmony_ci	{ .phy_offset = 4, .phy_shift = 3, .rf_addr = 0x46, .rf_shift = 4, .mask = 0x07, },
63162306a36Sopenharmony_ci	{ .phy_offset = 3, .phy_shift = 15, .rf_addr = 0x46, .rf_shift = 0, .mask = 0x01, },
63262306a36Sopenharmony_ci	{ .phy_offset = 4, .phy_shift = 0, .rf_addr = 0x46, .rf_shift = 1, .mask = 0x07, },
63362306a36Sopenharmony_ci	{ .phy_offset = 3, .phy_shift = 8, .rf_addr = 0x48, .rf_shift = 4, .mask = 0x07, },
63462306a36Sopenharmony_ci	{ .phy_offset = 3, .phy_shift = 11, .rf_addr = 0x48, .rf_shift = 0, .mask = 0x0f, },
63562306a36Sopenharmony_ci	{ .phy_offset = 3, .phy_shift = 4, .rf_addr = 0x49, .rf_shift = 4, .mask = 0x0f, },
63662306a36Sopenharmony_ci	{ .phy_offset = 2, .phy_shift = 15, .rf_addr = 0x45, .rf_shift = 0, .mask = 0x01, },
63762306a36Sopenharmony_ci	{ .phy_offset = 5, .phy_shift = 13, .rf_addr = 0x52, .rf_shift = 4, .mask = 0x07, },
63862306a36Sopenharmony_ci	{ .phy_offset = 6, .phy_shift = 0, .rf_addr = 0x52, .rf_shift = 7, .mask = 0x01, },
63962306a36Sopenharmony_ci	{ .phy_offset = 5, .phy_shift = 3, .rf_addr = 0x41, .rf_shift = 5, .mask = 0x07, },
64062306a36Sopenharmony_ci	{ .phy_offset = 5, .phy_shift = 6, .rf_addr = 0x41, .rf_shift = 0, .mask = 0x0f, },
64162306a36Sopenharmony_ci	{ .phy_offset = 5, .phy_shift = 10, .rf_addr = 0x42, .rf_shift = 5, .mask = 0x07, },
64262306a36Sopenharmony_ci	{ .phy_offset = 4, .phy_shift = 15, .rf_addr = 0x42, .rf_shift = 0, .mask = 0x01, },
64362306a36Sopenharmony_ci	{ .phy_offset = 5, .phy_shift = 0, .rf_addr = 0x42, .rf_shift = 1, .mask = 0x07, },
64462306a36Sopenharmony_ci	{ .phy_offset = 4, .phy_shift = 11, .rf_addr = 0x43, .rf_shift = 4, .mask = 0x0f, },
64562306a36Sopenharmony_ci	{ .phy_offset = 4, .phy_shift = 7, .rf_addr = 0x43, .rf_shift = 0, .mask = 0x0f, },
64662306a36Sopenharmony_ci	{ .phy_offset = 4, .phy_shift = 6, .rf_addr = 0x45, .rf_shift = 1, .mask = 0x01, },
64762306a36Sopenharmony_ci	{ .phy_offset = 2, .phy_shift = 7, .rf_addr = 0x40, .rf_shift = 4, .mask = 0x0f, },
64862306a36Sopenharmony_ci	{ .phy_offset = 2, .phy_shift = 11, .rf_addr = 0x40, .rf_shift = 0, .mask = 0x0f, },
64962306a36Sopenharmony_ci};
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic void lpphy_sync_stx(struct b43_wldev *dev)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	const struct lpphy_stx_table_entry *e;
65462306a36Sopenharmony_ci	unsigned int i;
65562306a36Sopenharmony_ci	u16 tmp;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(lpphy_stx_table); i++) {
65862306a36Sopenharmony_ci		e = &lpphy_stx_table[i];
65962306a36Sopenharmony_ci		tmp = b43_radio_read(dev, e->rf_addr);
66062306a36Sopenharmony_ci		tmp >>= e->rf_shift;
66162306a36Sopenharmony_ci		tmp <<= e->phy_shift;
66262306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_PHY_OFDM(0xF2 + e->phy_offset),
66362306a36Sopenharmony_ci				~(e->mask << e->phy_shift), tmp);
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void lpphy_radio_init(struct b43_wldev *dev)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	/* The radio is attached through the 4wire bus. */
67062306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_FOURWIRE_CTL, 0x2);
67162306a36Sopenharmony_ci	udelay(1);
67262306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_FOURWIRE_CTL, 0xFFFD);
67362306a36Sopenharmony_ci	udelay(1);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	if (dev->phy.radio_ver == 0x2062) {
67662306a36Sopenharmony_ci		lpphy_2062_init(dev);
67762306a36Sopenharmony_ci	} else {
67862306a36Sopenharmony_ci		lpphy_2063_init(dev);
67962306a36Sopenharmony_ci		lpphy_sync_stx(dev);
68062306a36Sopenharmony_ci		b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
68162306a36Sopenharmony_ci		b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
68262306a36Sopenharmony_ci		if (dev->dev->chip_id == 0x4325) {
68362306a36Sopenharmony_ci			// TODO SSB PMU recalibration
68462306a36Sopenharmony_ci		}
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistruct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; };
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic void lpphy_set_rc_cap(struct b43_wldev *dev)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	u8 rc_cap = (lpphy->rc_cap & 0x1F) >> 1;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (dev->phy.rev == 1) //FIXME check channel 14!
69762306a36Sopenharmony_ci		rc_cap = min_t(u8, rc_cap + 5, 15);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_RXBB_CALIB2,
70062306a36Sopenharmony_ci			max_t(u8, lpphy->rc_cap - 4, 0x80));
70162306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_CTL_A, rc_cap | 0x80);
70262306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RXG_CNT16,
70362306a36Sopenharmony_ci			((lpphy->rc_cap & 0x1F) >> 2) | 0x80);
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic u8 lpphy_get_bb_mult(struct b43_wldev *dev)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8;
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8);
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic void lpphy_set_deaf(struct b43_wldev *dev, bool user)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (user)
72162306a36Sopenharmony_ci		lpphy->crs_usr_disable = true;
72262306a36Sopenharmony_ci	else
72362306a36Sopenharmony_ci		lpphy->crs_sys_disable = true;
72462306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80);
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (user)
73262306a36Sopenharmony_ci		lpphy->crs_usr_disable = false;
73362306a36Sopenharmony_ci	else
73462306a36Sopenharmony_ci		lpphy->crs_sys_disable = false;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (!lpphy->crs_usr_disable && !lpphy->crs_sys_disable) {
73762306a36Sopenharmony_ci		if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
73862306a36Sopenharmony_ci			b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
73962306a36Sopenharmony_ci					0xFF1F, 0x60);
74062306a36Sopenharmony_ci		else
74162306a36Sopenharmony_ci			b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL,
74262306a36Sopenharmony_ci					0xFF1F, 0x20);
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic void lpphy_set_trsw_over(struct b43_wldev *dev, bool tx, bool rx)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	u16 trsw = (tx << 1) | rx;
74962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, trsw);
75062306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic void lpphy_disable_crs(struct b43_wldev *dev, bool user)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	lpphy_set_deaf(dev, user);
75662306a36Sopenharmony_ci	lpphy_set_trsw_over(dev, false, true);
75762306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
75862306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
75962306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);
76062306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
76162306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10);
76262306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
76362306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF);
76462306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
76562306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF);
76662306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
76762306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7);
76862306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38);
76962306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F);
77062306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100);
77162306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF);
77262306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0);
77362306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1);
77462306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20);
77562306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF);
77662306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF);
77762306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
77862306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF);
77962306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF);
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic void lpphy_restore_crs(struct b43_wldev *dev, bool user)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	lpphy_clear_deaf(dev, user);
78562306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80);
78662306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00);
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistruct lpphy_tx_gains { u16 gm, pga, pad, dac; };
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
79462306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
79562306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
79662306a36Sopenharmony_ci	if (dev->phy.rev >= 2) {
79762306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
79862306a36Sopenharmony_ci		if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
79962306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
80062306a36Sopenharmony_ci			b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
80162306a36Sopenharmony_ci		}
80262306a36Sopenharmony_ci	} else {
80362306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
81062306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
81162306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
81262306a36Sopenharmony_ci	if (dev->phy.rev >= 2) {
81362306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
81462306a36Sopenharmony_ci		if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
81562306a36Sopenharmony_ci			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
81662306a36Sopenharmony_ci			b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
81762306a36Sopenharmony_ci		}
81862306a36Sopenharmony_ci	} else {
81962306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic void lpphy_disable_tx_gain_override(struct b43_wldev *dev)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	if (dev->phy.rev < 2)
82662306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
82762306a36Sopenharmony_ci	else {
82862306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F);
82962306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF);
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF);
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_cistatic void lpphy_enable_tx_gain_override(struct b43_wldev *dev)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	if (dev->phy.rev < 2)
83762306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
83862306a36Sopenharmony_ci	else {
83962306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x80);
84062306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x4000);
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x40);
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct lpphy_tx_gains gains;
84862306a36Sopenharmony_ci	u16 tmp;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7;
85162306a36Sopenharmony_ci	if (dev->phy.rev < 2) {
85262306a36Sopenharmony_ci		tmp = b43_phy_read(dev,
85362306a36Sopenharmony_ci				   B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF;
85462306a36Sopenharmony_ci		gains.gm = tmp & 0x0007;
85562306a36Sopenharmony_ci		gains.pga = (tmp & 0x0078) >> 3;
85662306a36Sopenharmony_ci		gains.pad = (tmp & 0x780) >> 7;
85762306a36Sopenharmony_ci	} else {
85862306a36Sopenharmony_ci		tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL);
85962306a36Sopenharmony_ci		gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF;
86062306a36Sopenharmony_ci		gains.gm = tmp & 0xFF;
86162306a36Sopenharmony_ci		gains.pga = (tmp >> 8) & 0xFF;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	return gains;
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F;
87062306a36Sopenharmony_ci	ctl |= dac << 7;
87162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_cistatic u16 lpphy_get_pa_gain(struct b43_wldev *dev)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	return b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F;
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic void lpphy_set_pa_gain(struct b43_wldev *dev, u16 gain)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0xE03F, gain << 6);
88262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), 0x80FF, gain << 8);
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic void lpphy_set_tx_gains(struct b43_wldev *dev,
88662306a36Sopenharmony_ci			       struct lpphy_tx_gains gains)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	u16 rf_gain, pa_gain;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	if (dev->phy.rev < 2) {
89162306a36Sopenharmony_ci		rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm;
89262306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
89362306a36Sopenharmony_ci				0xF800, rf_gain);
89462306a36Sopenharmony_ci	} else {
89562306a36Sopenharmony_ci		pa_gain = lpphy_get_pa_gain(dev);
89662306a36Sopenharmony_ci		b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
89762306a36Sopenharmony_ci			      (gains.pga << 8) | gains.gm);
89862306a36Sopenharmony_ci		/*
89962306a36Sopenharmony_ci		 * SPEC FIXME The spec calls for (pa_gain << 8) here, but that
90062306a36Sopenharmony_ci		 * conflicts with the spec for set_pa_gain! Vendor driver bug?
90162306a36Sopenharmony_ci		 */
90262306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
90362306a36Sopenharmony_ci				0x8000, gains.pad | (pa_gain << 6));
90462306a36Sopenharmony_ci		b43_phy_write(dev, B43_PHY_OFDM(0xFC),
90562306a36Sopenharmony_ci			      (gains.pga << 8) | gains.gm);
90662306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_PHY_OFDM(0xFD),
90762306a36Sopenharmony_ci				0x8000, gains.pad | (pa_gain << 8));
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci	lpphy_set_dac_gain(dev, gains.dac);
91062306a36Sopenharmony_ci	lpphy_enable_tx_gain_override(dev);
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_cistatic void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	u16 trsw = gain & 0x1;
91662306a36Sopenharmony_ci	u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2);
91762306a36Sopenharmony_ci	u16 ext_lna = (gain & 2) >> 1;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
92062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
92162306a36Sopenharmony_ci			0xFBFF, ext_lna << 10);
92262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
92362306a36Sopenharmony_ci			0xF7FF, ext_lna << 11);
92462306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
92562306a36Sopenharmony_ci}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_cistatic void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	u16 low_gain = gain & 0xFFFF;
93062306a36Sopenharmony_ci	u16 high_gain = (gain >> 16) & 0xF;
93162306a36Sopenharmony_ci	u16 ext_lna = (gain >> 21) & 0x1;
93262306a36Sopenharmony_ci	u16 trsw = ~(gain >> 20) & 0x1;
93362306a36Sopenharmony_ci	u16 tmp;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
93662306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
93762306a36Sopenharmony_ci			0xFDFF, ext_lna << 9);
93862306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
93962306a36Sopenharmony_ci			0xFBFF, ext_lna << 10);
94062306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
94162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain);
94262306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
94362306a36Sopenharmony_ci		tmp = (gain >> 2) & 0x3;
94462306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
94562306a36Sopenharmony_ci				0xE7FF, tmp<<11);
94662306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp << 3);
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	if (dev->phy.rev < 2)
95362306a36Sopenharmony_ci		lpphy_rev0_1_set_rx_gain(dev, gain);
95462306a36Sopenharmony_ci	else
95562306a36Sopenharmony_ci		lpphy_rev2plus_set_rx_gain(dev, gain);
95662306a36Sopenharmony_ci	lpphy_enable_rx_gain_override(dev);
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_cistatic void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx));
96262306a36Sopenharmony_ci	lpphy_set_rx_gain(dev, gain);
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic void lpphy_stop_ddfs(struct b43_wldev *dev)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD);
96862306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF);
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on,
97262306a36Sopenharmony_ci			   int incr1, int incr2, int scale_idx)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	lpphy_stop_ddfs(dev);
97562306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80);
97662306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF);
97762306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1);
97862306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 8);
97962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3);
98062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4);
98162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5);
98262306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB);
98362306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2);
98462306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x20);
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
98862306a36Sopenharmony_ci			   struct lpphy_iq_est *iq_est)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	int i;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7);
99362306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples);
99462306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time);
99562306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF);
99662306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	for (i = 0; i < 500; i++) {
99962306a36Sopenharmony_ci		if (!(b43_phy_read(dev,
100062306a36Sopenharmony_ci				B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
100162306a36Sopenharmony_ci			break;
100262306a36Sopenharmony_ci		msleep(1);
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
100662306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
100762306a36Sopenharmony_ci		return false;
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR);
101162306a36Sopenharmony_ci	iq_est->iq_prod <<= 16;
101262306a36Sopenharmony_ci	iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR);
101562306a36Sopenharmony_ci	iq_est->i_pwr <<= 16;
101662306a36Sopenharmony_ci	iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR);
101962306a36Sopenharmony_ci	iq_est->q_pwr <<= 16;
102062306a36Sopenharmony_ci	iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
102362306a36Sopenharmony_ci	return true;
102462306a36Sopenharmony_ci}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cistatic int lpphy_loopback(struct b43_wldev *dev)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	struct lpphy_iq_est iq_est;
102962306a36Sopenharmony_ci	int i, index = -1;
103062306a36Sopenharmony_ci	u32 tmp;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	memset(&iq_est, 0, sizeof(iq_est));
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	lpphy_set_trsw_over(dev, true, true);
103562306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
103662306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
103762306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
103862306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
103962306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
104062306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8);
104162306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80);
104262306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80);
104362306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80);
104462306a36Sopenharmony_ci	for (i = 0; i < 32; i++) {
104562306a36Sopenharmony_ci		lpphy_set_rx_gain_by_index(dev, i);
104662306a36Sopenharmony_ci		lpphy_run_ddfs(dev, 1, 1, 5, 5, 0);
104762306a36Sopenharmony_ci		if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
104862306a36Sopenharmony_ci			continue;
104962306a36Sopenharmony_ci		tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000;
105062306a36Sopenharmony_ci		if ((tmp > 4000) && (tmp < 10000)) {
105162306a36Sopenharmony_ci			index = i;
105262306a36Sopenharmony_ci			break;
105362306a36Sopenharmony_ci		}
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci	lpphy_stop_ddfs(dev);
105662306a36Sopenharmony_ci	return index;
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci/* Fixed-point division algorithm using only integer math. */
106062306a36Sopenharmony_cistatic u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	u32 quotient, remainder;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	if (divisor == 0)
106562306a36Sopenharmony_ci		return 0;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	quotient = dividend / divisor;
106862306a36Sopenharmony_ci	remainder = dividend % divisor;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	while (precision > 0) {
107162306a36Sopenharmony_ci		quotient <<= 1;
107262306a36Sopenharmony_ci		if (remainder << 1 >= divisor) {
107362306a36Sopenharmony_ci			quotient++;
107462306a36Sopenharmony_ci			remainder = (remainder << 1) - divisor;
107562306a36Sopenharmony_ci		}
107662306a36Sopenharmony_ci		precision--;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	if (remainder << 1 >= divisor)
108062306a36Sopenharmony_ci		quotient++;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	return quotient;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci/* Read the TX power control mode from hardware. */
108662306a36Sopenharmony_cistatic void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
108962306a36Sopenharmony_ci	u16 ctl;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	ctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD);
109262306a36Sopenharmony_ci	switch (ctl & B43_LPPHY_TX_PWR_CTL_CMD_MODE) {
109362306a36Sopenharmony_ci	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF:
109462306a36Sopenharmony_ci		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_OFF;
109562306a36Sopenharmony_ci		break;
109662306a36Sopenharmony_ci	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW:
109762306a36Sopenharmony_ci		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_SW;
109862306a36Sopenharmony_ci		break;
109962306a36Sopenharmony_ci	case B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW:
110062306a36Sopenharmony_ci		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_HW;
110162306a36Sopenharmony_ci		break;
110262306a36Sopenharmony_ci	default:
110362306a36Sopenharmony_ci		lpphy->txpctl_mode = B43_LPPHY_TXPCTL_UNKNOWN;
110462306a36Sopenharmony_ci		B43_WARN_ON(1);
110562306a36Sopenharmony_ci		break;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci/* Set the TX power control mode in hardware. */
111062306a36Sopenharmony_cistatic void lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev *dev)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
111362306a36Sopenharmony_ci	u16 ctl;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	switch (lpphy->txpctl_mode) {
111662306a36Sopenharmony_ci	case B43_LPPHY_TXPCTL_OFF:
111762306a36Sopenharmony_ci		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF;
111862306a36Sopenharmony_ci		break;
111962306a36Sopenharmony_ci	case B43_LPPHY_TXPCTL_HW:
112062306a36Sopenharmony_ci		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW;
112162306a36Sopenharmony_ci		break;
112262306a36Sopenharmony_ci	case B43_LPPHY_TXPCTL_SW:
112362306a36Sopenharmony_ci		ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW;
112462306a36Sopenharmony_ci		break;
112562306a36Sopenharmony_ci	default:
112662306a36Sopenharmony_ci		ctl = 0;
112762306a36Sopenharmony_ci		B43_WARN_ON(1);
112862306a36Sopenharmony_ci	}
112962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
113062306a36Sopenharmony_ci			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF, ctl);
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic void lpphy_set_tx_power_control(struct b43_wldev *dev,
113462306a36Sopenharmony_ci				       enum b43_lpphy_txpctl_mode mode)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
113762306a36Sopenharmony_ci	enum b43_lpphy_txpctl_mode oldmode;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	lpphy_read_tx_pctl_mode_from_hardware(dev);
114062306a36Sopenharmony_ci	oldmode = lpphy->txpctl_mode;
114162306a36Sopenharmony_ci	if (oldmode == mode)
114262306a36Sopenharmony_ci		return;
114362306a36Sopenharmony_ci	lpphy->txpctl_mode = mode;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	if (oldmode == B43_LPPHY_TXPCTL_HW) {
114662306a36Sopenharmony_ci		//TODO Update TX Power NPT
114762306a36Sopenharmony_ci		//TODO Clear all TX Power offsets
114862306a36Sopenharmony_ci	} else {
114962306a36Sopenharmony_ci		if (mode == B43_LPPHY_TXPCTL_HW) {
115062306a36Sopenharmony_ci			//TODO Recalculate target TX power
115162306a36Sopenharmony_ci			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
115262306a36Sopenharmony_ci					0xFF80, lpphy->tssi_idx);
115362306a36Sopenharmony_ci			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
115462306a36Sopenharmony_ci					0x8FFF, ((u16)lpphy->tssi_npt << 16));
115562306a36Sopenharmony_ci			//TODO Set "TSSI Transmit Count" variable to total transmitted frame count
115662306a36Sopenharmony_ci			lpphy_disable_tx_gain_override(dev);
115762306a36Sopenharmony_ci			lpphy->tx_pwr_idx_over = -1;
115862306a36Sopenharmony_ci		}
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci	if (dev->phy.rev >= 2) {
116162306a36Sopenharmony_ci		if (mode == B43_LPPHY_TXPCTL_HW)
116262306a36Sopenharmony_ci			b43_phy_set(dev, B43_PHY_OFDM(0xD0), 0x2);
116362306a36Sopenharmony_ci		else
116462306a36Sopenharmony_ci			b43_phy_mask(dev, B43_PHY_OFDM(0xD0), 0xFFFD);
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci	lpphy_write_tx_pctl_mode_to_hardware(dev);
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
117062306a36Sopenharmony_ci				       unsigned int new_channel);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
117562306a36Sopenharmony_ci	struct lpphy_iq_est iq_est;
117662306a36Sopenharmony_ci	struct lpphy_tx_gains tx_gains;
117762306a36Sopenharmony_ci	static const u32 ideal_pwr_table[21] = {
117862306a36Sopenharmony_ci		0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
117962306a36Sopenharmony_ci		0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
118062306a36Sopenharmony_ci		0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
118162306a36Sopenharmony_ci		0x0004c, 0x0002c, 0x0001a,
118262306a36Sopenharmony_ci	};
118362306a36Sopenharmony_ci	bool old_txg_ovr;
118462306a36Sopenharmony_ci	u8 old_bbmult;
118562306a36Sopenharmony_ci	u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval,
118662306a36Sopenharmony_ci	    old_rf2_ovr, old_rf2_ovrval, old_phy_ctl;
118762306a36Sopenharmony_ci	enum b43_lpphy_txpctl_mode old_txpctl;
118862306a36Sopenharmony_ci	u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0;
118962306a36Sopenharmony_ci	int loopback, i, j, inner_sum, err;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	memset(&iq_est, 0, sizeof(iq_est));
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	err = b43_lpphy_op_switch_channel(dev, 7);
119462306a36Sopenharmony_ci	if (err) {
119562306a36Sopenharmony_ci		b43dbg(dev->wl,
119662306a36Sopenharmony_ci		       "RC calib: Failed to switch to channel 7, error = %d\n",
119762306a36Sopenharmony_ci		       err);
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci	old_txg_ovr = !!(b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40);
120062306a36Sopenharmony_ci	old_bbmult = lpphy_get_bb_mult(dev);
120162306a36Sopenharmony_ci	if (old_txg_ovr)
120262306a36Sopenharmony_ci		tx_gains = lpphy_get_tx_gains(dev);
120362306a36Sopenharmony_ci	old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0);
120462306a36Sopenharmony_ci	old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0);
120562306a36Sopenharmony_ci	old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR);
120662306a36Sopenharmony_ci	old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL);
120762306a36Sopenharmony_ci	old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2);
120862306a36Sopenharmony_ci	old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL);
120962306a36Sopenharmony_ci	old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL);
121062306a36Sopenharmony_ci	lpphy_read_tx_pctl_mode_from_hardware(dev);
121162306a36Sopenharmony_ci	old_txpctl = lpphy->txpctl_mode;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
121462306a36Sopenharmony_ci	lpphy_disable_crs(dev, true);
121562306a36Sopenharmony_ci	loopback = lpphy_loopback(dev);
121662306a36Sopenharmony_ci	if (loopback == -1)
121762306a36Sopenharmony_ci		goto finish;
121862306a36Sopenharmony_ci	lpphy_set_rx_gain_by_index(dev, loopback);
121962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40);
122062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1);
122162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8);
122262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0);
122362306a36Sopenharmony_ci	for (i = 128; i <= 159; i++) {
122462306a36Sopenharmony_ci		b43_radio_write(dev, B2062_N_RXBB_CALIB2, i);
122562306a36Sopenharmony_ci		inner_sum = 0;
122662306a36Sopenharmony_ci		for (j = 5; j <= 25; j++) {
122762306a36Sopenharmony_ci			lpphy_run_ddfs(dev, 1, 1, j, j, 0);
122862306a36Sopenharmony_ci			if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
122962306a36Sopenharmony_ci				goto finish;
123062306a36Sopenharmony_ci			mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr;
123162306a36Sopenharmony_ci			if (j == 5)
123262306a36Sopenharmony_ci				tmp = mean_sq_pwr;
123362306a36Sopenharmony_ci			ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1;
123462306a36Sopenharmony_ci			normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12);
123562306a36Sopenharmony_ci			mean_sq_pwr = ideal_pwr - normal_pwr;
123662306a36Sopenharmony_ci			mean_sq_pwr *= mean_sq_pwr;
123762306a36Sopenharmony_ci			inner_sum += mean_sq_pwr;
123862306a36Sopenharmony_ci			if ((i == 128) || (inner_sum < mean_sq_pwr_min)) {
123962306a36Sopenharmony_ci				lpphy->rc_cap = i;
124062306a36Sopenharmony_ci				mean_sq_pwr_min = inner_sum;
124162306a36Sopenharmony_ci			}
124262306a36Sopenharmony_ci		}
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci	lpphy_stop_ddfs(dev);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cifinish:
124762306a36Sopenharmony_ci	lpphy_restore_crs(dev, true);
124862306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval);
124962306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr);
125062306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval);
125162306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr);
125262306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval);
125362306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr);
125462306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	lpphy_set_bb_mult(dev, old_bbmult);
125762306a36Sopenharmony_ci	if (old_txg_ovr) {
125862306a36Sopenharmony_ci		/*
125962306a36Sopenharmony_ci		 * SPEC FIXME: The specs say "get_tx_gains" here, which is
126062306a36Sopenharmony_ci		 * illogical. According to lwfinger, vendor driver v4.150.10.5
126162306a36Sopenharmony_ci		 * has a Set here, while v4.174.64.19 has a Get - regression in
126262306a36Sopenharmony_ci		 * the vendor driver? This should be tested this once the code
126362306a36Sopenharmony_ci		 * is testable.
126462306a36Sopenharmony_ci		 */
126562306a36Sopenharmony_ci		lpphy_set_tx_gains(dev, tx_gains);
126662306a36Sopenharmony_ci	}
126762306a36Sopenharmony_ci	lpphy_set_tx_power_control(dev, old_txpctl);
126862306a36Sopenharmony_ci	if (lpphy->rc_cap)
126962306a36Sopenharmony_ci		lpphy_set_rc_cap(dev);
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	struct ssb_bus *bus = dev->dev->sdev->bus;
127562306a36Sopenharmony_ci	u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
127662306a36Sopenharmony_ci	u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
127762306a36Sopenharmony_ci	int i;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RX_BB_SP8, 0x0);
128062306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
128162306a36Sopenharmony_ci	b43_radio_mask(dev, B2063_PLL_SP1, 0xF7);
128262306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
128362306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x15);
128462306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x70);
128562306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x52);
128662306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
128762306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7D);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	for (i = 0; i < 10000; i++) {
129062306a36Sopenharmony_ci		if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
129162306a36Sopenharmony_ci			break;
129262306a36Sopenharmony_ci		msleep(1);
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
129662306a36Sopenharmony_ci		b43_radio_write(dev, B2063_RX_BB_SP8, tmp);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	tmp = b43_radio_read(dev, B2063_TX_BB_SP3) & 0xFF;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	b43_radio_write(dev, B2063_TX_BB_SP3, 0x0);
130162306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
130262306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7C);
130362306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL2, 0x55);
130462306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL3, 0x76);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	if (crystal_freq == 24000000) {
130762306a36Sopenharmony_ci		b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0xFC);
130862306a36Sopenharmony_ci		b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x0);
130962306a36Sopenharmony_ci	} else {
131062306a36Sopenharmony_ci		b43_radio_write(dev, B2063_RC_CALIB_CTL4, 0x13);
131162306a36Sopenharmony_ci		b43_radio_write(dev, B2063_RC_CALIB_CTL5, 0x1);
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PA_SP7, 0x7D);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	for (i = 0; i < 10000; i++) {
131762306a36Sopenharmony_ci		if (b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2)
131862306a36Sopenharmony_ci			break;
131962306a36Sopenharmony_ci		msleep(1);
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (!(b43_radio_read(dev, B2063_RC_CALIB_CTL6) & 0x2))
132362306a36Sopenharmony_ci		b43_radio_write(dev, B2063_TX_BB_SP3, tmp);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	b43_radio_write(dev, B2063_RC_CALIB_CTL1, 0x7E);
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_cistatic void lpphy_calibrate_rc(struct b43_wldev *dev)
132962306a36Sopenharmony_ci{
133062306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	if (dev->phy.rev >= 2) {
133362306a36Sopenharmony_ci		lpphy_rev2plus_rc_calib(dev);
133462306a36Sopenharmony_ci	} else if (!lpphy->rc_cap) {
133562306a36Sopenharmony_ci		if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
133662306a36Sopenharmony_ci			lpphy_rev0_1_rc_calib(dev);
133762306a36Sopenharmony_ci	} else {
133862306a36Sopenharmony_ci		lpphy_set_rc_cap(dev);
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	if (dev->phy.rev >= 2)
134562306a36Sopenharmony_ci		return; // rev2+ doesn't support antenna diversity
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
134862306a36Sopenharmony_ci		return;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
135362306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	dev->phy.lp->antenna = antenna;
135862306a36Sopenharmony_ci}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_cistatic void lpphy_set_tx_iqcc(struct b43_wldev *dev, u16 a, u16 b)
136162306a36Sopenharmony_ci{
136262306a36Sopenharmony_ci	u16 tmp[2];
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	tmp[0] = a;
136562306a36Sopenharmony_ci	tmp[1] = b;
136662306a36Sopenharmony_ci	b43_lptab_write_bulk(dev, B43_LPTAB16(0, 80), 2, tmp);
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_cistatic void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
137262306a36Sopenharmony_ci	struct lpphy_tx_gains gains;
137362306a36Sopenharmony_ci	u32 iq_comp, tx_gain, coeff, rf_power;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	lpphy->tx_pwr_idx_over = index;
137662306a36Sopenharmony_ci	lpphy_read_tx_pctl_mode_from_hardware(dev);
137762306a36Sopenharmony_ci	if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
137862306a36Sopenharmony_ci		lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);
137962306a36Sopenharmony_ci	if (dev->phy.rev >= 2) {
138062306a36Sopenharmony_ci		iq_comp = b43_lptab_read(dev, B43_LPTAB32(7, index + 320));
138162306a36Sopenharmony_ci		tx_gain = b43_lptab_read(dev, B43_LPTAB32(7, index + 192));
138262306a36Sopenharmony_ci		gains.pad = (tx_gain >> 16) & 0xFF;
138362306a36Sopenharmony_ci		gains.gm = tx_gain & 0xFF;
138462306a36Sopenharmony_ci		gains.pga = (tx_gain >> 8) & 0xFF;
138562306a36Sopenharmony_ci		gains.dac = (iq_comp >> 28) & 0xFF;
138662306a36Sopenharmony_ci		lpphy_set_tx_gains(dev, gains);
138762306a36Sopenharmony_ci	} else {
138862306a36Sopenharmony_ci		iq_comp = b43_lptab_read(dev, B43_LPTAB32(10, index + 320));
138962306a36Sopenharmony_ci		tx_gain = b43_lptab_read(dev, B43_LPTAB32(10, index + 192));
139062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
139162306a36Sopenharmony_ci				0xF800, (tx_gain >> 4) & 0x7FFF);
139262306a36Sopenharmony_ci		lpphy_set_dac_gain(dev, tx_gain & 0x7);
139362306a36Sopenharmony_ci		lpphy_set_pa_gain(dev, (tx_gain >> 24) & 0x7F);
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci	lpphy_set_bb_mult(dev, (iq_comp >> 20) & 0xFF);
139662306a36Sopenharmony_ci	lpphy_set_tx_iqcc(dev, (iq_comp >> 10) & 0x3FF, iq_comp & 0x3FF);
139762306a36Sopenharmony_ci	if (dev->phy.rev >= 2) {
139862306a36Sopenharmony_ci		coeff = b43_lptab_read(dev, B43_LPTAB32(7, index + 448));
139962306a36Sopenharmony_ci	} else {
140062306a36Sopenharmony_ci		coeff = b43_lptab_read(dev, B43_LPTAB32(10, index + 448));
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci	b43_lptab_write(dev, B43_LPTAB16(0, 85), coeff & 0xFFFF);
140362306a36Sopenharmony_ci	if (dev->phy.rev >= 2) {
140462306a36Sopenharmony_ci		rf_power = b43_lptab_read(dev, B43_LPTAB32(7, index + 576));
140562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00,
140662306a36Sopenharmony_ci				rf_power & 0xFFFF);//SPEC FIXME mask & set != 0
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci	lpphy_enable_tx_gain_override(dev);
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistatic void lpphy_btcoex_override(struct b43_wldev *dev)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	b43_write16(dev, B43_MMIO_BTCOEX_CTL, 0x3);
141462306a36Sopenharmony_ci	b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
141562306a36Sopenharmony_ci}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cistatic void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
141862306a36Sopenharmony_ci					 bool blocked)
141962306a36Sopenharmony_ci{
142062306a36Sopenharmony_ci	//TODO check MAC control register
142162306a36Sopenharmony_ci	if (blocked) {
142262306a36Sopenharmony_ci		if (dev->phy.rev >= 2) {
142362306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x83FF);
142462306a36Sopenharmony_ci			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
142562306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0x80FF);
142662306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xDFFF);
142762306a36Sopenharmony_ci			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0808);
142862306a36Sopenharmony_ci		} else {
142962306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xE0FF);
143062306a36Sopenharmony_ci			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
143162306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFCFF);
143262306a36Sopenharmony_ci			b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0018);
143362306a36Sopenharmony_ci		}
143462306a36Sopenharmony_ci	} else {
143562306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xE0FF);
143662306a36Sopenharmony_ci		if (dev->phy.rev >= 2)
143762306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xF7F7);
143862306a36Sopenharmony_ci		else
143962306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFE7);
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci/* This was previously called lpphy_japan_filter */
144462306a36Sopenharmony_cistatic void lpphy_set_analog_filter(struct b43_wldev *dev, int channel)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
144762306a36Sopenharmony_ci	u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
145062306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
145162306a36Sopenharmony_ci		if ((dev->phy.rev == 1) && (lpphy->rc_cap))
145262306a36Sopenharmony_ci			lpphy_set_rc_cap(dev);
145362306a36Sopenharmony_ci	} else {
145462306a36Sopenharmony_ci		b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_cistatic void lpphy_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	if (mode != TSSI_MUX_EXT) {
146162306a36Sopenharmony_ci		b43_radio_set(dev, B2063_PA_SP1, 0x2);
146262306a36Sopenharmony_ci		b43_phy_set(dev, B43_PHY_OFDM(0xF3), 0x1000);
146362306a36Sopenharmony_ci		b43_radio_write(dev, B2063_PA_CTL10, 0x51);
146462306a36Sopenharmony_ci		if (mode == TSSI_MUX_POSTPA) {
146562306a36Sopenharmony_ci			b43_radio_mask(dev, B2063_PA_SP1, 0xFFFE);
146662306a36Sopenharmony_ci			b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFC7);
146762306a36Sopenharmony_ci		} else {
146862306a36Sopenharmony_ci			b43_radio_maskset(dev, B2063_PA_SP1, 0xFFFE, 0x1);
146962306a36Sopenharmony_ci			b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVRVAL,
147062306a36Sopenharmony_ci					0xFFC7, 0x20);
147162306a36Sopenharmony_ci		}
147262306a36Sopenharmony_ci	} else {
147362306a36Sopenharmony_ci		B43_WARN_ON(1);
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_cistatic void lpphy_tx_pctl_init_hw(struct b43_wldev *dev)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	u16 tmp;
148062306a36Sopenharmony_ci	int i;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	//SPEC TODO Call LP PHY Clear TX Power offsets
148362306a36Sopenharmony_ci	for (i = 0; i < 64; i++) {
148462306a36Sopenharmony_ci		if (dev->phy.rev >= 2)
148562306a36Sopenharmony_ci			b43_lptab_write(dev, B43_LPTAB32(7, i + 1), i);
148662306a36Sopenharmony_ci		else
148762306a36Sopenharmony_ci			b43_lptab_write(dev, B43_LPTAB32(10, i + 1), i);
148862306a36Sopenharmony_ci	}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xFF00, 0xFF);
149162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0x8FFF, 0x5000);
149262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0xFFC0, 0x1F);
149362306a36Sopenharmony_ci	if (dev->phy.rev < 2) {
149462306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xEFFF);
149562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xDFFF, 0x2000);
149662306a36Sopenharmony_ci	} else {
149762306a36Sopenharmony_ci		b43_phy_mask(dev, B43_PHY_OFDM(0x103), 0xFFFE);
149862306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFFB, 0x4);
149962306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_PHY_OFDM(0x103), 0xFFEF, 0x10);
150062306a36Sopenharmony_ci		b43_radio_maskset(dev, B2063_IQ_CALIB_CTL2, 0xF3, 0x1);
150162306a36Sopenharmony_ci		lpphy_set_tssi_mux(dev, TSSI_MUX_POSTPA);
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI, 0x7FFF, 0x8000);
150462306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xFF);
150562306a36Sopenharmony_ci	b43_phy_write(dev, B43_LPPHY_TX_PWR_CTL_DELTAPWR_LIMIT, 0xA);
150662306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
150762306a36Sopenharmony_ci			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
150862306a36Sopenharmony_ci			B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
150962306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 0xF8FF);
151062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD,
151162306a36Sopenharmony_ci			~B43_LPPHY_TX_PWR_CTL_CMD_MODE & 0xFFFF,
151262306a36Sopenharmony_ci			B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	if (dev->phy.rev < 2) {
151562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF, 0x1000);
151662306a36Sopenharmony_ci		b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xEFFF);
151762306a36Sopenharmony_ci	} else {
151862306a36Sopenharmony_ci		lpphy_set_tx_power_by_index(dev, 0x7F);
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	b43_dummy_transmission(dev, true, true);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	tmp = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_STAT);
152462306a36Sopenharmony_ci	if (tmp & 0x8000) {
152562306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_IDLETSSI,
152662306a36Sopenharmony_ci				0xFFC0, (tmp & 0xFF) - 32);
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xEFFF);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	// (SPEC?) TODO Set "Target TX frequency" variable to 0
153262306a36Sopenharmony_ci	// SPEC FIXME "Set BB Multiplier to 0xE000" impossible - bb_mult is u8!
153362306a36Sopenharmony_ci}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_cistatic void lpphy_tx_pctl_init_sw(struct b43_wldev *dev)
153662306a36Sopenharmony_ci{
153762306a36Sopenharmony_ci	struct lpphy_tx_gains gains;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
154062306a36Sopenharmony_ci		gains.gm = 4;
154162306a36Sopenharmony_ci		gains.pad = 12;
154262306a36Sopenharmony_ci		gains.pga = 12;
154362306a36Sopenharmony_ci		gains.dac = 0;
154462306a36Sopenharmony_ci	} else {
154562306a36Sopenharmony_ci		gains.gm = 7;
154662306a36Sopenharmony_ci		gains.pad = 14;
154762306a36Sopenharmony_ci		gains.pga = 15;
154862306a36Sopenharmony_ci		gains.dac = 0;
154962306a36Sopenharmony_ci	}
155062306a36Sopenharmony_ci	lpphy_set_tx_gains(dev, gains);
155162306a36Sopenharmony_ci	lpphy_set_bb_mult(dev, 150);
155262306a36Sopenharmony_ci}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci/* Initialize TX power control */
155562306a36Sopenharmony_cistatic void lpphy_tx_pctl_init(struct b43_wldev *dev)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	if (0/*FIXME HWPCTL capable */) {
155862306a36Sopenharmony_ci		lpphy_tx_pctl_init_hw(dev);
155962306a36Sopenharmony_ci	} else { /* This device is only software TX power control capable. */
156062306a36Sopenharmony_ci		lpphy_tx_pctl_init_sw(dev);
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_cistatic void lpphy_pr41573_workaround(struct b43_wldev *dev)
156562306a36Sopenharmony_ci{
156662306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
156762306a36Sopenharmony_ci	u32 *saved_tab;
156862306a36Sopenharmony_ci	const unsigned int saved_tab_size = 256;
156962306a36Sopenharmony_ci	enum b43_lpphy_txpctl_mode txpctl_mode;
157062306a36Sopenharmony_ci	s8 tx_pwr_idx_over;
157162306a36Sopenharmony_ci	u16 tssi_npt, tssi_idx;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL);
157462306a36Sopenharmony_ci	if (!saved_tab) {
157562306a36Sopenharmony_ci		b43err(dev->wl, "PR41573 failed. Out of memory!\n");
157662306a36Sopenharmony_ci		return;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	lpphy_read_tx_pctl_mode_from_hardware(dev);
158062306a36Sopenharmony_ci	txpctl_mode = lpphy->txpctl_mode;
158162306a36Sopenharmony_ci	tx_pwr_idx_over = lpphy->tx_pwr_idx_over;
158262306a36Sopenharmony_ci	tssi_npt = lpphy->tssi_npt;
158362306a36Sopenharmony_ci	tssi_idx = lpphy->tssi_idx;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	if (dev->phy.rev < 2) {
158662306a36Sopenharmony_ci		b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140),
158762306a36Sopenharmony_ci				    saved_tab_size, saved_tab);
158862306a36Sopenharmony_ci	} else {
158962306a36Sopenharmony_ci		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
159062306a36Sopenharmony_ci				    saved_tab_size, saved_tab);
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci	//FIXME PHY reset
159362306a36Sopenharmony_ci	lpphy_table_init(dev); //FIXME is table init needed?
159462306a36Sopenharmony_ci	lpphy_baseband_init(dev);
159562306a36Sopenharmony_ci	lpphy_tx_pctl_init(dev);
159662306a36Sopenharmony_ci	b43_lpphy_op_software_rfkill(dev, false);
159762306a36Sopenharmony_ci	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
159862306a36Sopenharmony_ci	if (dev->phy.rev < 2) {
159962306a36Sopenharmony_ci		b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
160062306a36Sopenharmony_ci				     saved_tab_size, saved_tab);
160162306a36Sopenharmony_ci	} else {
160262306a36Sopenharmony_ci		b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
160362306a36Sopenharmony_ci				     saved_tab_size, saved_tab);
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci	b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
160662306a36Sopenharmony_ci	lpphy->tssi_npt = tssi_npt;
160762306a36Sopenharmony_ci	lpphy->tssi_idx = tssi_idx;
160862306a36Sopenharmony_ci	lpphy_set_analog_filter(dev, lpphy->channel);
160962306a36Sopenharmony_ci	if (tx_pwr_idx_over != -1)
161062306a36Sopenharmony_ci		lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
161162306a36Sopenharmony_ci	if (lpphy->rc_cap)
161262306a36Sopenharmony_ci		lpphy_set_rc_cap(dev);
161362306a36Sopenharmony_ci	b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
161462306a36Sopenharmony_ci	lpphy_set_tx_power_control(dev, txpctl_mode);
161562306a36Sopenharmony_ci	kfree(saved_tab);
161662306a36Sopenharmony_ci}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_cistruct lpphy_rx_iq_comp { u8 chan; s8 c1, c0; };
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_cistatic const struct lpphy_rx_iq_comp lpphy_5354_iq_table[] = {
162162306a36Sopenharmony_ci	{ .chan = 1, .c1 = -66, .c0 = 15, },
162262306a36Sopenharmony_ci	{ .chan = 2, .c1 = -66, .c0 = 15, },
162362306a36Sopenharmony_ci	{ .chan = 3, .c1 = -66, .c0 = 15, },
162462306a36Sopenharmony_ci	{ .chan = 4, .c1 = -66, .c0 = 15, },
162562306a36Sopenharmony_ci	{ .chan = 5, .c1 = -66, .c0 = 15, },
162662306a36Sopenharmony_ci	{ .chan = 6, .c1 = -66, .c0 = 15, },
162762306a36Sopenharmony_ci	{ .chan = 7, .c1 = -66, .c0 = 14, },
162862306a36Sopenharmony_ci	{ .chan = 8, .c1 = -66, .c0 = 14, },
162962306a36Sopenharmony_ci	{ .chan = 9, .c1 = -66, .c0 = 14, },
163062306a36Sopenharmony_ci	{ .chan = 10, .c1 = -66, .c0 = 14, },
163162306a36Sopenharmony_ci	{ .chan = 11, .c1 = -66, .c0 = 14, },
163262306a36Sopenharmony_ci	{ .chan = 12, .c1 = -66, .c0 = 13, },
163362306a36Sopenharmony_ci	{ .chan = 13, .c1 = -66, .c0 = 13, },
163462306a36Sopenharmony_ci	{ .chan = 14, .c1 = -66, .c0 = 13, },
163562306a36Sopenharmony_ci};
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_cistatic const struct lpphy_rx_iq_comp lpphy_rev0_1_iq_table[] = {
163862306a36Sopenharmony_ci	{ .chan = 1, .c1 = -64, .c0 = 13, },
163962306a36Sopenharmony_ci	{ .chan = 2, .c1 = -64, .c0 = 13, },
164062306a36Sopenharmony_ci	{ .chan = 3, .c1 = -64, .c0 = 13, },
164162306a36Sopenharmony_ci	{ .chan = 4, .c1 = -64, .c0 = 13, },
164262306a36Sopenharmony_ci	{ .chan = 5, .c1 = -64, .c0 = 12, },
164362306a36Sopenharmony_ci	{ .chan = 6, .c1 = -64, .c0 = 12, },
164462306a36Sopenharmony_ci	{ .chan = 7, .c1 = -64, .c0 = 12, },
164562306a36Sopenharmony_ci	{ .chan = 8, .c1 = -64, .c0 = 12, },
164662306a36Sopenharmony_ci	{ .chan = 9, .c1 = -64, .c0 = 12, },
164762306a36Sopenharmony_ci	{ .chan = 10, .c1 = -64, .c0 = 11, },
164862306a36Sopenharmony_ci	{ .chan = 11, .c1 = -64, .c0 = 11, },
164962306a36Sopenharmony_ci	{ .chan = 12, .c1 = -64, .c0 = 11, },
165062306a36Sopenharmony_ci	{ .chan = 13, .c1 = -64, .c0 = 11, },
165162306a36Sopenharmony_ci	{ .chan = 14, .c1 = -64, .c0 = 10, },
165262306a36Sopenharmony_ci	{ .chan = 34, .c1 = -62, .c0 = 24, },
165362306a36Sopenharmony_ci	{ .chan = 38, .c1 = -62, .c0 = 24, },
165462306a36Sopenharmony_ci	{ .chan = 42, .c1 = -62, .c0 = 24, },
165562306a36Sopenharmony_ci	{ .chan = 46, .c1 = -62, .c0 = 23, },
165662306a36Sopenharmony_ci	{ .chan = 36, .c1 = -62, .c0 = 24, },
165762306a36Sopenharmony_ci	{ .chan = 40, .c1 = -62, .c0 = 24, },
165862306a36Sopenharmony_ci	{ .chan = 44, .c1 = -62, .c0 = 23, },
165962306a36Sopenharmony_ci	{ .chan = 48, .c1 = -62, .c0 = 23, },
166062306a36Sopenharmony_ci	{ .chan = 52, .c1 = -62, .c0 = 23, },
166162306a36Sopenharmony_ci	{ .chan = 56, .c1 = -62, .c0 = 22, },
166262306a36Sopenharmony_ci	{ .chan = 60, .c1 = -62, .c0 = 22, },
166362306a36Sopenharmony_ci	{ .chan = 64, .c1 = -62, .c0 = 22, },
166462306a36Sopenharmony_ci	{ .chan = 100, .c1 = -62, .c0 = 16, },
166562306a36Sopenharmony_ci	{ .chan = 104, .c1 = -62, .c0 = 16, },
166662306a36Sopenharmony_ci	{ .chan = 108, .c1 = -62, .c0 = 15, },
166762306a36Sopenharmony_ci	{ .chan = 112, .c1 = -62, .c0 = 14, },
166862306a36Sopenharmony_ci	{ .chan = 116, .c1 = -62, .c0 = 14, },
166962306a36Sopenharmony_ci	{ .chan = 120, .c1 = -62, .c0 = 13, },
167062306a36Sopenharmony_ci	{ .chan = 124, .c1 = -62, .c0 = 12, },
167162306a36Sopenharmony_ci	{ .chan = 128, .c1 = -62, .c0 = 12, },
167262306a36Sopenharmony_ci	{ .chan = 132, .c1 = -62, .c0 = 12, },
167362306a36Sopenharmony_ci	{ .chan = 136, .c1 = -62, .c0 = 11, },
167462306a36Sopenharmony_ci	{ .chan = 140, .c1 = -62, .c0 = 10, },
167562306a36Sopenharmony_ci	{ .chan = 149, .c1 = -61, .c0 = 9, },
167662306a36Sopenharmony_ci	{ .chan = 153, .c1 = -61, .c0 = 9, },
167762306a36Sopenharmony_ci	{ .chan = 157, .c1 = -61, .c0 = 9, },
167862306a36Sopenharmony_ci	{ .chan = 161, .c1 = -61, .c0 = 8, },
167962306a36Sopenharmony_ci	{ .chan = 165, .c1 = -61, .c0 = 8, },
168062306a36Sopenharmony_ci	{ .chan = 184, .c1 = -62, .c0 = 25, },
168162306a36Sopenharmony_ci	{ .chan = 188, .c1 = -62, .c0 = 25, },
168262306a36Sopenharmony_ci	{ .chan = 192, .c1 = -62, .c0 = 25, },
168362306a36Sopenharmony_ci	{ .chan = 196, .c1 = -62, .c0 = 25, },
168462306a36Sopenharmony_ci	{ .chan = 200, .c1 = -62, .c0 = 25, },
168562306a36Sopenharmony_ci	{ .chan = 204, .c1 = -62, .c0 = 25, },
168662306a36Sopenharmony_ci	{ .chan = 208, .c1 = -62, .c0 = 25, },
168762306a36Sopenharmony_ci	{ .chan = 212, .c1 = -62, .c0 = 25, },
168862306a36Sopenharmony_ci	{ .chan = 216, .c1 = -62, .c0 = 26, },
168962306a36Sopenharmony_ci};
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_cistatic const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
169262306a36Sopenharmony_ci	.chan = 0,
169362306a36Sopenharmony_ci	.c1 = -64,
169462306a36Sopenharmony_ci	.c0 = 0,
169562306a36Sopenharmony_ci};
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_cistatic int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	struct lpphy_iq_est iq_est;
170062306a36Sopenharmony_ci	u16 c0, c1;
170162306a36Sopenharmony_ci	int prod, ipwr, qpwr, prod_msb, q_msb, tmp1, tmp2, tmp3, tmp4, ret;
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	c1 = b43_phy_read(dev, B43_LPPHY_RX_COMP_COEFF_S);
170462306a36Sopenharmony_ci	c0 = c1 >> 8;
170562306a36Sopenharmony_ci	c1 |= 0xFF;
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, 0x00C0);
170862306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	ret = lpphy_rx_iq_est(dev, samples, 32, &iq_est);
171162306a36Sopenharmony_ci	if (!ret)
171262306a36Sopenharmony_ci		goto out;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	prod = iq_est.iq_prod;
171562306a36Sopenharmony_ci	ipwr = iq_est.i_pwr;
171662306a36Sopenharmony_ci	qpwr = iq_est.q_pwr;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	if (ipwr + qpwr < 2) {
171962306a36Sopenharmony_ci		ret = 0;
172062306a36Sopenharmony_ci		goto out;
172162306a36Sopenharmony_ci	}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	prod_msb = fls(abs(prod));
172462306a36Sopenharmony_ci	q_msb = fls(abs(qpwr));
172562306a36Sopenharmony_ci	tmp1 = prod_msb - 20;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	if (tmp1 >= 0) {
172862306a36Sopenharmony_ci		tmp3 = ((prod << (30 - prod_msb)) + (ipwr >> (1 + tmp1))) /
172962306a36Sopenharmony_ci			(ipwr >> tmp1);
173062306a36Sopenharmony_ci	} else {
173162306a36Sopenharmony_ci		tmp3 = ((prod << (30 - prod_msb)) + (ipwr << (-1 - tmp1))) /
173262306a36Sopenharmony_ci			(ipwr << -tmp1);
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	tmp2 = q_msb - 11;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	if (tmp2 >= 0)
173862306a36Sopenharmony_ci		tmp4 = (qpwr << (31 - q_msb)) / (ipwr >> tmp2);
173962306a36Sopenharmony_ci	else
174062306a36Sopenharmony_ci		tmp4 = (qpwr << (31 - q_msb)) / (ipwr << -tmp2);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	tmp4 -= tmp3 * tmp3;
174362306a36Sopenharmony_ci	tmp4 = -int_sqrt(tmp4);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	c0 = tmp3 >> 3;
174662306a36Sopenharmony_ci	c1 = tmp4 >> 4;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ciout:
174962306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, c1);
175062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF, c0 << 8);
175162306a36Sopenharmony_ci	return ret;
175262306a36Sopenharmony_ci}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_cistatic void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
175562306a36Sopenharmony_ci			      u16 wait)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL,
175862306a36Sopenharmony_ci			0xFFC0, samples - 1);
175962306a36Sopenharmony_ci	if (loops != 0xFFFF)
176062306a36Sopenharmony_ci		loops--;
176162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000, loops);
176262306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL, 0x3F, wait << 6);
176362306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_A_PHY_CTL_ADDR, 0x1);
176462306a36Sopenharmony_ci}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci//SPEC FIXME what does a negative freq mean?
176762306a36Sopenharmony_cistatic void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
177062306a36Sopenharmony_ci	u16 buf[64];
177162306a36Sopenharmony_ci	int i, samples = 0, theta = 0;
177262306a36Sopenharmony_ci	int rotation = (((36 * freq) / 20) << 16) / 100;
177362306a36Sopenharmony_ci	struct cordic_iq sample;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	lpphy->tx_tone_freq = freq;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if (freq) {
177862306a36Sopenharmony_ci		/* Find i for which abs(freq) integrally divides 20000 * i */
177962306a36Sopenharmony_ci		for (i = 1; samples * abs(freq) != 20000 * i; i++) {
178062306a36Sopenharmony_ci			samples = (20000 * i) / abs(freq);
178162306a36Sopenharmony_ci			if(B43_WARN_ON(samples > 63))
178262306a36Sopenharmony_ci				return;
178362306a36Sopenharmony_ci		}
178462306a36Sopenharmony_ci	} else {
178562306a36Sopenharmony_ci		samples = 2;
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	for (i = 0; i < samples; i++) {
178962306a36Sopenharmony_ci		sample = cordic_calc_iq(CORDIC_FIXED(theta));
179062306a36Sopenharmony_ci		theta += rotation;
179162306a36Sopenharmony_ci		buf[i] = CORDIC_FLOAT((sample.i * max) & 0xFF) << 8;
179262306a36Sopenharmony_ci		buf[i] |= CORDIC_FLOAT((sample.q * max) & 0xFF);
179362306a36Sopenharmony_ci	}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	lpphy_run_samples(dev, samples, 0xFFFF, 0);
179862306a36Sopenharmony_ci}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_cistatic void lpphy_stop_tx_tone(struct b43_wldev *dev)
180162306a36Sopenharmony_ci{
180262306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
180362306a36Sopenharmony_ci	int i;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	lpphy->tx_tone_freq = 0;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000);
180862306a36Sopenharmony_ci	for (i = 0; i < 31; i++) {
180962306a36Sopenharmony_ci		if (!(b43_phy_read(dev, B43_LPPHY_A_PHY_CTL_ADDR) & 0x1))
181062306a36Sopenharmony_ci			break;
181162306a36Sopenharmony_ci		udelay(100);
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_cistatic void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
181762306a36Sopenharmony_ci{
181862306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
181962306a36Sopenharmony_ci	struct lpphy_tx_gains oldgains;
182062306a36Sopenharmony_ci	int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	lpphy_read_tx_pctl_mode_from_hardware(dev);
182362306a36Sopenharmony_ci	old_txpctl = lpphy->txpctl_mode;
182462306a36Sopenharmony_ci	old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
182562306a36Sopenharmony_ci	if (old_afe_ovr)
182662306a36Sopenharmony_ci		oldgains = lpphy_get_tx_gains(dev);
182762306a36Sopenharmony_ci	old_rf = b43_phy_read(dev, B43_LPPHY_RF_PWR_OVERRIDE) & 0xFF;
182862306a36Sopenharmony_ci	old_bbmult = lpphy_get_bb_mult(dev);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	if (old_afe_ovr)
183362306a36Sopenharmony_ci		lpphy_set_tx_gains(dev, oldgains);
183462306a36Sopenharmony_ci	lpphy_set_bb_mult(dev, old_bbmult);
183562306a36Sopenharmony_ci	lpphy_set_tx_power_control(dev, old_txpctl);
183662306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00, old_rf);
183762306a36Sopenharmony_ci}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_cistatic int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
184062306a36Sopenharmony_ci			    bool rx, bool pa, struct lpphy_tx_gains *gains)
184162306a36Sopenharmony_ci{
184262306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
184362306a36Sopenharmony_ci	const struct lpphy_rx_iq_comp *iqcomp = NULL;
184462306a36Sopenharmony_ci	struct lpphy_tx_gains nogains, oldgains;
184562306a36Sopenharmony_ci	u16 tmp;
184662306a36Sopenharmony_ci	int i, ret;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	memset(&nogains, 0, sizeof(nogains));
184962306a36Sopenharmony_ci	memset(&oldgains, 0, sizeof(oldgains));
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	if (dev->dev->chip_id == 0x5354) {
185262306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
185362306a36Sopenharmony_ci			if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
185462306a36Sopenharmony_ci				iqcomp = &lpphy_5354_iq_table[i];
185562306a36Sopenharmony_ci			}
185662306a36Sopenharmony_ci		}
185762306a36Sopenharmony_ci	} else if (dev->phy.rev >= 2) {
185862306a36Sopenharmony_ci		iqcomp = &lpphy_rev2plus_iq_comp;
185962306a36Sopenharmony_ci	} else {
186062306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(lpphy_rev0_1_iq_table); i++) {
186162306a36Sopenharmony_ci			if (lpphy_rev0_1_iq_table[i].chan == lpphy->channel) {
186262306a36Sopenharmony_ci				iqcomp = &lpphy_rev0_1_iq_table[i];
186362306a36Sopenharmony_ci			}
186462306a36Sopenharmony_ci		}
186562306a36Sopenharmony_ci	}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (B43_WARN_ON(!iqcomp))
186862306a36Sopenharmony_ci		return 0;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, iqcomp->c1);
187162306a36Sopenharmony_ci	b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S,
187262306a36Sopenharmony_ci			0x00FF, iqcomp->c0 << 8);
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	if (noise) {
187562306a36Sopenharmony_ci		tx = true;
187662306a36Sopenharmony_ci		rx = false;
187762306a36Sopenharmony_ci		pa = false;
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	lpphy_set_trsw_over(dev, tx, rx);
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
188362306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
188462306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
188562306a36Sopenharmony_ci				0xFFF7, pa << 3);
188662306a36Sopenharmony_ci	} else {
188762306a36Sopenharmony_ci		b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
188862306a36Sopenharmony_ci		b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
188962306a36Sopenharmony_ci				0xFFDF, pa << 5);
189062306a36Sopenharmony_ci	}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	tmp = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	if (noise)
189562306a36Sopenharmony_ci		lpphy_set_rx_gain(dev, 0x2D5D);
189662306a36Sopenharmony_ci	else {
189762306a36Sopenharmony_ci		if (tmp)
189862306a36Sopenharmony_ci			oldgains = lpphy_get_tx_gains(dev);
189962306a36Sopenharmony_ci		if (!gains)
190062306a36Sopenharmony_ci			gains = &nogains;
190162306a36Sopenharmony_ci		lpphy_set_tx_gains(dev, *gains);
190262306a36Sopenharmony_ci	}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
190562306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
190662306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
190762306a36Sopenharmony_ci	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
190862306a36Sopenharmony_ci	lpphy_set_deaf(dev, false);
190962306a36Sopenharmony_ci	if (noise)
191062306a36Sopenharmony_ci		ret = lpphy_calc_rx_iq_comp(dev, 0xFFF0);
191162306a36Sopenharmony_ci	else {
191262306a36Sopenharmony_ci		lpphy_start_tx_tone(dev, 4000, 100);
191362306a36Sopenharmony_ci		ret = lpphy_calc_rx_iq_comp(dev, 0x4000);
191462306a36Sopenharmony_ci		lpphy_stop_tx_tone(dev);
191562306a36Sopenharmony_ci	}
191662306a36Sopenharmony_ci	lpphy_clear_deaf(dev, false);
191762306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFC);
191862306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
191962306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFDF);
192062306a36Sopenharmony_ci	if (!noise) {
192162306a36Sopenharmony_ci		if (tmp)
192262306a36Sopenharmony_ci			lpphy_set_tx_gains(dev, oldgains);
192362306a36Sopenharmony_ci		else
192462306a36Sopenharmony_ci			lpphy_disable_tx_gain_override(dev);
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci	lpphy_disable_rx_gain_override(dev);
192762306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
192862306a36Sopenharmony_ci	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xF7FF);
192962306a36Sopenharmony_ci	return ret;
193062306a36Sopenharmony_ci}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_cistatic void lpphy_calibration(struct b43_wldev *dev)
193362306a36Sopenharmony_ci{
193462306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
193562306a36Sopenharmony_ci	enum b43_lpphy_txpctl_mode saved_pctl_mode;
193662306a36Sopenharmony_ci	bool full_cal = false;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	if (lpphy->full_calib_chan != lpphy->channel) {
193962306a36Sopenharmony_ci		full_cal = true;
194062306a36Sopenharmony_ci		lpphy->full_calib_chan = lpphy->channel;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	b43_mac_suspend(dev);
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	lpphy_btcoex_override(dev);
194662306a36Sopenharmony_ci	if (dev->phy.rev >= 2)
194762306a36Sopenharmony_ci		lpphy_save_dig_flt_state(dev);
194862306a36Sopenharmony_ci	lpphy_read_tx_pctl_mode_from_hardware(dev);
194962306a36Sopenharmony_ci	saved_pctl_mode = lpphy->txpctl_mode;
195062306a36Sopenharmony_ci	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
195162306a36Sopenharmony_ci	//TODO Perform transmit power table I/Q LO calibration
195262306a36Sopenharmony_ci	if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
195362306a36Sopenharmony_ci		lpphy_pr41573_workaround(dev);
195462306a36Sopenharmony_ci	if ((dev->phy.rev >= 2) && full_cal) {
195562306a36Sopenharmony_ci		lpphy_papd_cal_txpwr(dev);
195662306a36Sopenharmony_ci	}
195762306a36Sopenharmony_ci	lpphy_set_tx_power_control(dev, saved_pctl_mode);
195862306a36Sopenharmony_ci	if (dev->phy.rev >= 2)
195962306a36Sopenharmony_ci		lpphy_restore_dig_flt_state(dev);
196062306a36Sopenharmony_ci	lpphy_rx_iq_cal(dev, true, true, false, false, NULL);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	b43_mac_enable(dev);
196362306a36Sopenharmony_ci}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_cistatic void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
196662306a36Sopenharmony_ci				 u16 set)
196762306a36Sopenharmony_ci{
196862306a36Sopenharmony_ci	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
196962306a36Sopenharmony_ci	b43_write16(dev, B43_MMIO_PHY_DATA,
197062306a36Sopenharmony_ci		    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
197162306a36Sopenharmony_ci}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_cistatic u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
197462306a36Sopenharmony_ci{
197562306a36Sopenharmony_ci	/* Register 1 is a 32-bit register. */
197662306a36Sopenharmony_ci	B43_WARN_ON(reg == 1);
197762306a36Sopenharmony_ci	/* LP-PHY needs a special bit set for read access */
197862306a36Sopenharmony_ci	if (dev->phy.rev < 2) {
197962306a36Sopenharmony_ci		if (reg != 0x4001)
198062306a36Sopenharmony_ci			reg |= 0x100;
198162306a36Sopenharmony_ci	} else
198262306a36Sopenharmony_ci		reg |= 0x200;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
198562306a36Sopenharmony_ci	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_cistatic void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
198962306a36Sopenharmony_ci{
199062306a36Sopenharmony_ci	/* Register 1 is a 32-bit register. */
199162306a36Sopenharmony_ci	B43_WARN_ON(reg == 1);
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
199462306a36Sopenharmony_ci	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
199562306a36Sopenharmony_ci}
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_cistruct b206x_channel {
199862306a36Sopenharmony_ci	u8 channel;
199962306a36Sopenharmony_ci	u16 freq;
200062306a36Sopenharmony_ci	u8 data[12];
200162306a36Sopenharmony_ci};
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_cistatic const struct b206x_channel b2062_chantbl[] = {
200462306a36Sopenharmony_ci	{ .channel = 1, .freq = 2412, .data[0] = 0xFF, .data[1] = 0xFF,
200562306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
200662306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
200762306a36Sopenharmony_ci	{ .channel = 2, .freq = 2417, .data[0] = 0xFF, .data[1] = 0xFF,
200862306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
200962306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
201062306a36Sopenharmony_ci	{ .channel = 3, .freq = 2422, .data[0] = 0xFF, .data[1] = 0xFF,
201162306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
201262306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
201362306a36Sopenharmony_ci	{ .channel = 4, .freq = 2427, .data[0] = 0xFF, .data[1] = 0xFF,
201462306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
201562306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
201662306a36Sopenharmony_ci	{ .channel = 5, .freq = 2432, .data[0] = 0xFF, .data[1] = 0xFF,
201762306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
201862306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
201962306a36Sopenharmony_ci	{ .channel = 6, .freq = 2437, .data[0] = 0xFF, .data[1] = 0xFF,
202062306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
202162306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
202262306a36Sopenharmony_ci	{ .channel = 7, .freq = 2442, .data[0] = 0xFF, .data[1] = 0xFF,
202362306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
202462306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
202562306a36Sopenharmony_ci	{ .channel = 8, .freq = 2447, .data[0] = 0xFF, .data[1] = 0xFF,
202662306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
202762306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
202862306a36Sopenharmony_ci	{ .channel = 9, .freq = 2452, .data[0] = 0xFF, .data[1] = 0xFF,
202962306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
203062306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
203162306a36Sopenharmony_ci	{ .channel = 10, .freq = 2457, .data[0] = 0xFF, .data[1] = 0xFF,
203262306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
203362306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
203462306a36Sopenharmony_ci	{ .channel = 11, .freq = 2462, .data[0] = 0xFF, .data[1] = 0xFF,
203562306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
203662306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
203762306a36Sopenharmony_ci	{ .channel = 12, .freq = 2467, .data[0] = 0xFF, .data[1] = 0xFF,
203862306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
203962306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
204062306a36Sopenharmony_ci	{ .channel = 13, .freq = 2472, .data[0] = 0xFF, .data[1] = 0xFF,
204162306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
204262306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
204362306a36Sopenharmony_ci	{ .channel = 14, .freq = 2484, .data[0] = 0xFF, .data[1] = 0xFF,
204462306a36Sopenharmony_ci	  .data[2] = 0xB5, .data[3] = 0x1B, .data[4] = 0x24, .data[5] = 0x32,
204562306a36Sopenharmony_ci	  .data[6] = 0x32, .data[7] = 0x88, .data[8] = 0x88, },
204662306a36Sopenharmony_ci	{ .channel = 34, .freq = 5170, .data[0] = 0x00, .data[1] = 0x22,
204762306a36Sopenharmony_ci	  .data[2] = 0x20, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
204862306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
204962306a36Sopenharmony_ci	{ .channel = 38, .freq = 5190, .data[0] = 0x00, .data[1] = 0x11,
205062306a36Sopenharmony_ci	  .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
205162306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
205262306a36Sopenharmony_ci	{ .channel = 42, .freq = 5210, .data[0] = 0x00, .data[1] = 0x11,
205362306a36Sopenharmony_ci	  .data[2] = 0x10, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
205462306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
205562306a36Sopenharmony_ci	{ .channel = 46, .freq = 5230, .data[0] = 0x00, .data[1] = 0x00,
205662306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
205762306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
205862306a36Sopenharmony_ci	{ .channel = 36, .freq = 5180, .data[0] = 0x00, .data[1] = 0x11,
205962306a36Sopenharmony_ci	  .data[2] = 0x20, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
206062306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
206162306a36Sopenharmony_ci	{ .channel = 40, .freq = 5200, .data[0] = 0x00, .data[1] = 0x11,
206262306a36Sopenharmony_ci	  .data[2] = 0x10, .data[3] = 0x84, .data[4] = 0x3C, .data[5] = 0x77,
206362306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
206462306a36Sopenharmony_ci	{ .channel = 44, .freq = 5220, .data[0] = 0x00, .data[1] = 0x11,
206562306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
206662306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
206762306a36Sopenharmony_ci	{ .channel = 48, .freq = 5240, .data[0] = 0x00, .data[1] = 0x00,
206862306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
206962306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
207062306a36Sopenharmony_ci	{ .channel = 52, .freq = 5260, .data[0] = 0x00, .data[1] = 0x00,
207162306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
207262306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
207362306a36Sopenharmony_ci	{ .channel = 56, .freq = 5280, .data[0] = 0x00, .data[1] = 0x00,
207462306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x83, .data[4] = 0x3C, .data[5] = 0x77,
207562306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
207662306a36Sopenharmony_ci	{ .channel = 60, .freq = 5300, .data[0] = 0x00, .data[1] = 0x00,
207762306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x63, .data[4] = 0x3C, .data[5] = 0x77,
207862306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
207962306a36Sopenharmony_ci	{ .channel = 64, .freq = 5320, .data[0] = 0x00, .data[1] = 0x00,
208062306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x62, .data[4] = 0x3C, .data[5] = 0x77,
208162306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
208262306a36Sopenharmony_ci	{ .channel = 100, .freq = 5500, .data[0] = 0x00, .data[1] = 0x00,
208362306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x30, .data[4] = 0x3C, .data[5] = 0x77,
208462306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
208562306a36Sopenharmony_ci	{ .channel = 104, .freq = 5520, .data[0] = 0x00, .data[1] = 0x00,
208662306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
208762306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
208862306a36Sopenharmony_ci	{ .channel = 108, .freq = 5540, .data[0] = 0x00, .data[1] = 0x00,
208962306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
209062306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
209162306a36Sopenharmony_ci	{ .channel = 112, .freq = 5560, .data[0] = 0x00, .data[1] = 0x00,
209262306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x20, .data[4] = 0x3C, .data[5] = 0x77,
209362306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
209462306a36Sopenharmony_ci	{ .channel = 116, .freq = 5580, .data[0] = 0x00, .data[1] = 0x00,
209562306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x10, .data[4] = 0x3C, .data[5] = 0x77,
209662306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
209762306a36Sopenharmony_ci	{ .channel = 120, .freq = 5600, .data[0] = 0x00, .data[1] = 0x00,
209862306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
209962306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
210062306a36Sopenharmony_ci	{ .channel = 124, .freq = 5620, .data[0] = 0x00, .data[1] = 0x00,
210162306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
210262306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
210362306a36Sopenharmony_ci	{ .channel = 128, .freq = 5640, .data[0] = 0x00, .data[1] = 0x00,
210462306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
210562306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
210662306a36Sopenharmony_ci	{ .channel = 132, .freq = 5660, .data[0] = 0x00, .data[1] = 0x00,
210762306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
210862306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
210962306a36Sopenharmony_ci	{ .channel = 136, .freq = 5680, .data[0] = 0x00, .data[1] = 0x00,
211062306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
211162306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
211262306a36Sopenharmony_ci	{ .channel = 140, .freq = 5700, .data[0] = 0x00, .data[1] = 0x00,
211362306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
211462306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
211562306a36Sopenharmony_ci	{ .channel = 149, .freq = 5745, .data[0] = 0x00, .data[1] = 0x00,
211662306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
211762306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
211862306a36Sopenharmony_ci	{ .channel = 153, .freq = 5765, .data[0] = 0x00, .data[1] = 0x00,
211962306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
212062306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
212162306a36Sopenharmony_ci	{ .channel = 157, .freq = 5785, .data[0] = 0x00, .data[1] = 0x00,
212262306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
212362306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
212462306a36Sopenharmony_ci	{ .channel = 161, .freq = 5805, .data[0] = 0x00, .data[1] = 0x00,
212562306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
212662306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
212762306a36Sopenharmony_ci	{ .channel = 165, .freq = 5825, .data[0] = 0x00, .data[1] = 0x00,
212862306a36Sopenharmony_ci	  .data[2] = 0x00, .data[3] = 0x00, .data[4] = 0x3C, .data[5] = 0x77,
212962306a36Sopenharmony_ci	  .data[6] = 0x37, .data[7] = 0xFF, .data[8] = 0x88, },
213062306a36Sopenharmony_ci	{ .channel = 184, .freq = 4920, .data[0] = 0x55, .data[1] = 0x77,
213162306a36Sopenharmony_ci	  .data[2] = 0x90, .data[3] = 0xF7, .data[4] = 0x3C, .data[5] = 0x77,
213262306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
213362306a36Sopenharmony_ci	{ .channel = 188, .freq = 4940, .data[0] = 0x44, .data[1] = 0x77,
213462306a36Sopenharmony_ci	  .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
213562306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
213662306a36Sopenharmony_ci	{ .channel = 192, .freq = 4960, .data[0] = 0x44, .data[1] = 0x66,
213762306a36Sopenharmony_ci	  .data[2] = 0x80, .data[3] = 0xE7, .data[4] = 0x3C, .data[5] = 0x77,
213862306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
213962306a36Sopenharmony_ci	{ .channel = 196, .freq = 4980, .data[0] = 0x33, .data[1] = 0x66,
214062306a36Sopenharmony_ci	  .data[2] = 0x70, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
214162306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
214262306a36Sopenharmony_ci	{ .channel = 200, .freq = 5000, .data[0] = 0x22, .data[1] = 0x55,
214362306a36Sopenharmony_ci	  .data[2] = 0x60, .data[3] = 0xD7, .data[4] = 0x3C, .data[5] = 0x77,
214462306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
214562306a36Sopenharmony_ci	{ .channel = 204, .freq = 5020, .data[0] = 0x22, .data[1] = 0x55,
214662306a36Sopenharmony_ci	  .data[2] = 0x60, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
214762306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
214862306a36Sopenharmony_ci	{ .channel = 208, .freq = 5040, .data[0] = 0x22, .data[1] = 0x44,
214962306a36Sopenharmony_ci	  .data[2] = 0x50, .data[3] = 0xC7, .data[4] = 0x3C, .data[5] = 0x77,
215062306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0xFF, },
215162306a36Sopenharmony_ci	{ .channel = 212, .freq = 5060, .data[0] = 0x11, .data[1] = 0x44,
215262306a36Sopenharmony_ci	  .data[2] = 0x50, .data[3] = 0xA5, .data[4] = 0x3C, .data[5] = 0x77,
215362306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
215462306a36Sopenharmony_ci	{ .channel = 216, .freq = 5080, .data[0] = 0x00, .data[1] = 0x44,
215562306a36Sopenharmony_ci	  .data[2] = 0x40, .data[3] = 0xB6, .data[4] = 0x3C, .data[5] = 0x77,
215662306a36Sopenharmony_ci	  .data[6] = 0x35, .data[7] = 0xFF, .data[8] = 0x88, },
215762306a36Sopenharmony_ci};
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_cistatic const struct b206x_channel b2063_chantbl[] = {
216062306a36Sopenharmony_ci	{ .channel = 1, .freq = 2412, .data[0] = 0x6F, .data[1] = 0x3C,
216162306a36Sopenharmony_ci	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
216262306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
216362306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
216462306a36Sopenharmony_ci	{ .channel = 2, .freq = 2417, .data[0] = 0x6F, .data[1] = 0x3C,
216562306a36Sopenharmony_ci	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
216662306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
216762306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
216862306a36Sopenharmony_ci	{ .channel = 3, .freq = 2422, .data[0] = 0x6F, .data[1] = 0x3C,
216962306a36Sopenharmony_ci	  .data[2] = 0x3C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
217062306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
217162306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
217262306a36Sopenharmony_ci	{ .channel = 4, .freq = 2427, .data[0] = 0x6F, .data[1] = 0x2C,
217362306a36Sopenharmony_ci	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
217462306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
217562306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
217662306a36Sopenharmony_ci	{ .channel = 5, .freq = 2432, .data[0] = 0x6F, .data[1] = 0x2C,
217762306a36Sopenharmony_ci	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
217862306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
217962306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
218062306a36Sopenharmony_ci	{ .channel = 6, .freq = 2437, .data[0] = 0x6F, .data[1] = 0x2C,
218162306a36Sopenharmony_ci	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
218262306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
218362306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
218462306a36Sopenharmony_ci	{ .channel = 7, .freq = 2442, .data[0] = 0x6F, .data[1] = 0x2C,
218562306a36Sopenharmony_ci	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
218662306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
218762306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
218862306a36Sopenharmony_ci	{ .channel = 8, .freq = 2447, .data[0] = 0x6F, .data[1] = 0x2C,
218962306a36Sopenharmony_ci	  .data[2] = 0x2C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
219062306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
219162306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
219262306a36Sopenharmony_ci	{ .channel = 9, .freq = 2452, .data[0] = 0x6F, .data[1] = 0x1C,
219362306a36Sopenharmony_ci	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
219462306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
219562306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
219662306a36Sopenharmony_ci	{ .channel = 10, .freq = 2457, .data[0] = 0x6F, .data[1] = 0x1C,
219762306a36Sopenharmony_ci	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
219862306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
219962306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
220062306a36Sopenharmony_ci	{ .channel = 11, .freq = 2462, .data[0] = 0x6E, .data[1] = 0x1C,
220162306a36Sopenharmony_ci	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
220262306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
220362306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
220462306a36Sopenharmony_ci	{ .channel = 12, .freq = 2467, .data[0] = 0x6E, .data[1] = 0x1C,
220562306a36Sopenharmony_ci	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
220662306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
220762306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
220862306a36Sopenharmony_ci	{ .channel = 13, .freq = 2472, .data[0] = 0x6E, .data[1] = 0x1C,
220962306a36Sopenharmony_ci	  .data[2] = 0x1C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
221062306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
221162306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
221262306a36Sopenharmony_ci	{ .channel = 14, .freq = 2484, .data[0] = 0x6E, .data[1] = 0x0C,
221362306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x04, .data[4] = 0x05, .data[5] = 0x05,
221462306a36Sopenharmony_ci	  .data[6] = 0x05, .data[7] = 0x05, .data[8] = 0x77, .data[9] = 0x80,
221562306a36Sopenharmony_ci	  .data[10] = 0x80, .data[11] = 0x70, },
221662306a36Sopenharmony_ci	{ .channel = 34, .freq = 5170, .data[0] = 0x6A, .data[1] = 0x0C,
221762306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x02, .data[5] = 0x05,
221862306a36Sopenharmony_ci	  .data[6] = 0x0D, .data[7] = 0x0D, .data[8] = 0x77, .data[9] = 0x80,
221962306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
222062306a36Sopenharmony_ci	{ .channel = 36, .freq = 5180, .data[0] = 0x6A, .data[1] = 0x0C,
222162306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x05,
222262306a36Sopenharmony_ci	  .data[6] = 0x0D, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
222362306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
222462306a36Sopenharmony_ci	{ .channel = 38, .freq = 5190, .data[0] = 0x6A, .data[1] = 0x0C,
222562306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
222662306a36Sopenharmony_ci	  .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x80,
222762306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
222862306a36Sopenharmony_ci	{ .channel = 40, .freq = 5200, .data[0] = 0x69, .data[1] = 0x0C,
222962306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
223062306a36Sopenharmony_ci	  .data[6] = 0x0C, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
223162306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
223262306a36Sopenharmony_ci	{ .channel = 42, .freq = 5210, .data[0] = 0x69, .data[1] = 0x0C,
223362306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x01, .data[5] = 0x04,
223462306a36Sopenharmony_ci	  .data[6] = 0x0B, .data[7] = 0x0C, .data[8] = 0x77, .data[9] = 0x70,
223562306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
223662306a36Sopenharmony_ci	{ .channel = 44, .freq = 5220, .data[0] = 0x69, .data[1] = 0x0C,
223762306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x04,
223862306a36Sopenharmony_ci	  .data[6] = 0x0B, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
223962306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
224062306a36Sopenharmony_ci	{ .channel = 46, .freq = 5230, .data[0] = 0x69, .data[1] = 0x0C,
224162306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
224262306a36Sopenharmony_ci	  .data[6] = 0x0A, .data[7] = 0x0B, .data[8] = 0x77, .data[9] = 0x60,
224362306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
224462306a36Sopenharmony_ci	{ .channel = 48, .freq = 5240, .data[0] = 0x69, .data[1] = 0x0C,
224562306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x03,
224662306a36Sopenharmony_ci	  .data[6] = 0x0A, .data[7] = 0x0A, .data[8] = 0x77, .data[9] = 0x60,
224762306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
224862306a36Sopenharmony_ci	{ .channel = 52, .freq = 5260, .data[0] = 0x68, .data[1] = 0x0C,
224962306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x02,
225062306a36Sopenharmony_ci	  .data[6] = 0x09, .data[7] = 0x09, .data[8] = 0x77, .data[9] = 0x60,
225162306a36Sopenharmony_ci	  .data[10] = 0x20, .data[11] = 0x00, },
225262306a36Sopenharmony_ci	{ .channel = 56, .freq = 5280, .data[0] = 0x68, .data[1] = 0x0C,
225362306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
225462306a36Sopenharmony_ci	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
225562306a36Sopenharmony_ci	  .data[10] = 0x10, .data[11] = 0x00, },
225662306a36Sopenharmony_ci	{ .channel = 60, .freq = 5300, .data[0] = 0x68, .data[1] = 0x0C,
225762306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x01,
225862306a36Sopenharmony_ci	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
225962306a36Sopenharmony_ci	  .data[10] = 0x10, .data[11] = 0x00, },
226062306a36Sopenharmony_ci	{ .channel = 64, .freq = 5320, .data[0] = 0x67, .data[1] = 0x0C,
226162306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
226262306a36Sopenharmony_ci	  .data[6] = 0x08, .data[7] = 0x08, .data[8] = 0x77, .data[9] = 0x50,
226362306a36Sopenharmony_ci	  .data[10] = 0x10, .data[11] = 0x00, },
226462306a36Sopenharmony_ci	{ .channel = 100, .freq = 5500, .data[0] = 0x64, .data[1] = 0x0C,
226562306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
226662306a36Sopenharmony_ci	  .data[6] = 0x02, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
226762306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
226862306a36Sopenharmony_ci	{ .channel = 104, .freq = 5520, .data[0] = 0x64, .data[1] = 0x0C,
226962306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
227062306a36Sopenharmony_ci	  .data[6] = 0x01, .data[7] = 0x01, .data[8] = 0x77, .data[9] = 0x20,
227162306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
227262306a36Sopenharmony_ci	{ .channel = 108, .freq = 5540, .data[0] = 0x63, .data[1] = 0x0C,
227362306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
227462306a36Sopenharmony_ci	  .data[6] = 0x01, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
227562306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
227662306a36Sopenharmony_ci	{ .channel = 112, .freq = 5560, .data[0] = 0x63, .data[1] = 0x0C,
227762306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
227862306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
227962306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
228062306a36Sopenharmony_ci	{ .channel = 116, .freq = 5580, .data[0] = 0x62, .data[1] = 0x0C,
228162306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
228262306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x10,
228362306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
228462306a36Sopenharmony_ci	{ .channel = 120, .freq = 5600, .data[0] = 0x62, .data[1] = 0x0C,
228562306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
228662306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
228762306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
228862306a36Sopenharmony_ci	{ .channel = 124, .freq = 5620, .data[0] = 0x62, .data[1] = 0x0C,
228962306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
229062306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
229162306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
229262306a36Sopenharmony_ci	{ .channel = 128, .freq = 5640, .data[0] = 0x61, .data[1] = 0x0C,
229362306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
229462306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
229562306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
229662306a36Sopenharmony_ci	{ .channel = 132, .freq = 5660, .data[0] = 0x61, .data[1] = 0x0C,
229762306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
229862306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
229962306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
230062306a36Sopenharmony_ci	{ .channel = 136, .freq = 5680, .data[0] = 0x61, .data[1] = 0x0C,
230162306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
230262306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
230362306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
230462306a36Sopenharmony_ci	{ .channel = 140, .freq = 5700, .data[0] = 0x60, .data[1] = 0x0C,
230562306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
230662306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
230762306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
230862306a36Sopenharmony_ci	{ .channel = 149, .freq = 5745, .data[0] = 0x60, .data[1] = 0x0C,
230962306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
231062306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
231162306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
231262306a36Sopenharmony_ci	{ .channel = 153, .freq = 5765, .data[0] = 0x60, .data[1] = 0x0C,
231362306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
231462306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
231562306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
231662306a36Sopenharmony_ci	{ .channel = 157, .freq = 5785, .data[0] = 0x60, .data[1] = 0x0C,
231762306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
231862306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
231962306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
232062306a36Sopenharmony_ci	{ .channel = 161, .freq = 5805, .data[0] = 0x60, .data[1] = 0x0C,
232162306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
232262306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
232362306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
232462306a36Sopenharmony_ci	{ .channel = 165, .freq = 5825, .data[0] = 0x60, .data[1] = 0x0C,
232562306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x00, .data[5] = 0x00,
232662306a36Sopenharmony_ci	  .data[6] = 0x00, .data[7] = 0x00, .data[8] = 0x77, .data[9] = 0x00,
232762306a36Sopenharmony_ci	  .data[10] = 0x00, .data[11] = 0x00, },
232862306a36Sopenharmony_ci	{ .channel = 184, .freq = 4920, .data[0] = 0x6E, .data[1] = 0x0C,
232962306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0E,
233062306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xC0,
233162306a36Sopenharmony_ci	  .data[10] = 0x50, .data[11] = 0x00, },
233262306a36Sopenharmony_ci	{ .channel = 188, .freq = 4940, .data[0] = 0x6E, .data[1] = 0x0C,
233362306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x09, .data[5] = 0x0D,
233462306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
233562306a36Sopenharmony_ci	  .data[10] = 0x50, .data[11] = 0x00, },
233662306a36Sopenharmony_ci	{ .channel = 192, .freq = 4960, .data[0] = 0x6E, .data[1] = 0x0C,
233762306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
233862306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xB0,
233962306a36Sopenharmony_ci	  .data[10] = 0x50, .data[11] = 0x00, },
234062306a36Sopenharmony_ci	{ .channel = 196, .freq = 4980, .data[0] = 0x6D, .data[1] = 0x0C,
234162306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0C,
234262306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
234362306a36Sopenharmony_ci	  .data[10] = 0x40, .data[11] = 0x00, },
234462306a36Sopenharmony_ci	{ .channel = 200, .freq = 5000, .data[0] = 0x6D, .data[1] = 0x0C,
234562306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0B,
234662306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
234762306a36Sopenharmony_ci	  .data[10] = 0x40, .data[11] = 0x00, },
234862306a36Sopenharmony_ci	{ .channel = 204, .freq = 5020, .data[0] = 0x6D, .data[1] = 0x0C,
234962306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x08, .data[5] = 0x0A,
235062306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0xA0,
235162306a36Sopenharmony_ci	  .data[10] = 0x40, .data[11] = 0x00, },
235262306a36Sopenharmony_ci	{ .channel = 208, .freq = 5040, .data[0] = 0x6C, .data[1] = 0x0C,
235362306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x07, .data[5] = 0x09,
235462306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
235562306a36Sopenharmony_ci	  .data[10] = 0x40, .data[11] = 0x00, },
235662306a36Sopenharmony_ci	{ .channel = 212, .freq = 5060, .data[0] = 0x6C, .data[1] = 0x0C,
235762306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x06, .data[5] = 0x08,
235862306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
235962306a36Sopenharmony_ci	  .data[10] = 0x40, .data[11] = 0x00, },
236062306a36Sopenharmony_ci	{ .channel = 216, .freq = 5080, .data[0] = 0x6C, .data[1] = 0x0C,
236162306a36Sopenharmony_ci	  .data[2] = 0x0C, .data[3] = 0x00, .data[4] = 0x05, .data[5] = 0x08,
236262306a36Sopenharmony_ci	  .data[6] = 0x0F, .data[7] = 0x0F, .data[8] = 0x77, .data[9] = 0x90,
236362306a36Sopenharmony_ci	  .data[10] = 0x40, .data[11] = 0x00, },
236462306a36Sopenharmony_ci};
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_cistatic void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
236762306a36Sopenharmony_ci{
236862306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
236962306a36Sopenharmony_ci	udelay(20);
237062306a36Sopenharmony_ci	if (dev->dev->chip_id == 0x5354) {
237162306a36Sopenharmony_ci		b43_radio_write(dev, B2062_N_COMM1, 4);
237262306a36Sopenharmony_ci		b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4);
237362306a36Sopenharmony_ci	} else {
237462306a36Sopenharmony_ci		b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0);
237562306a36Sopenharmony_ci	}
237662306a36Sopenharmony_ci	udelay(5);
237762306a36Sopenharmony_ci}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_cistatic void lpphy_b2062_vco_calib(struct b43_wldev *dev)
238062306a36Sopenharmony_ci{
238162306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x42);
238262306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL21, 0x62);
238362306a36Sopenharmony_ci	udelay(200);
238462306a36Sopenharmony_ci}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_cistatic int lpphy_b2062_tune(struct b43_wldev *dev,
238762306a36Sopenharmony_ci			    unsigned int channel)
238862306a36Sopenharmony_ci{
238962306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
239062306a36Sopenharmony_ci	struct ssb_bus *bus = dev->dev->sdev->bus;
239162306a36Sopenharmony_ci	const struct b206x_channel *chandata = NULL;
239262306a36Sopenharmony_ci	u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
239362306a36Sopenharmony_ci	u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
239462306a36Sopenharmony_ci	int i, err = 0;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(b2062_chantbl); i++) {
239762306a36Sopenharmony_ci		if (b2062_chantbl[i].channel == channel) {
239862306a36Sopenharmony_ci			chandata = &b2062_chantbl[i];
239962306a36Sopenharmony_ci			break;
240062306a36Sopenharmony_ci		}
240162306a36Sopenharmony_ci	}
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci	if (B43_WARN_ON(!chandata))
240462306a36Sopenharmony_ci		return -EINVAL;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	b43_radio_set(dev, B2062_S_RFPLL_CTL14, 0x04);
240762306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_LGENA_TUNE0, chandata->data[0]);
240862306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_LGENA_TUNE2, chandata->data[1]);
240962306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_LGENA_TUNE3, chandata->data[2]);
241062306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_TUNE, chandata->data[3]);
241162306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_LGENG_CTL1, chandata->data[4]);
241262306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_LGENA_CTL5, chandata->data[5]);
241362306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_LGENA_CTL6, chandata->data[6]);
241462306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_PGA, chandata->data[7]);
241562306a36Sopenharmony_ci	b43_radio_write(dev, B2062_N_TX_PAD, chandata->data[8]);
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	tmp1 = crystal_freq / 1000;
241862306a36Sopenharmony_ci	tmp2 = lpphy->pdiv * 1000;
241962306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xCC);
242062306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0x07);
242162306a36Sopenharmony_ci	lpphy_b2062_reset_pll_bias(dev);
242262306a36Sopenharmony_ci	tmp3 = tmp2 * channel2freq_lp(channel);
242362306a36Sopenharmony_ci	if (channel2freq_lp(channel) < 4000)
242462306a36Sopenharmony_ci		tmp3 *= 2;
242562306a36Sopenharmony_ci	tmp4 = 48 * tmp1;
242662306a36Sopenharmony_ci	tmp6 = tmp3 / tmp4;
242762306a36Sopenharmony_ci	tmp7 = tmp3 % tmp4;
242862306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL26, tmp6);
242962306a36Sopenharmony_ci	tmp5 = tmp7 * 0x100;
243062306a36Sopenharmony_ci	tmp6 = tmp5 / tmp4;
243162306a36Sopenharmony_ci	tmp7 = tmp5 % tmp4;
243262306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL27, tmp6);
243362306a36Sopenharmony_ci	tmp5 = tmp7 * 0x100;
243462306a36Sopenharmony_ci	tmp6 = tmp5 / tmp4;
243562306a36Sopenharmony_ci	tmp7 = tmp5 % tmp4;
243662306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL28, tmp6);
243762306a36Sopenharmony_ci	tmp5 = tmp7 * 0x100;
243862306a36Sopenharmony_ci	tmp6 = tmp5 / tmp4;
243962306a36Sopenharmony_ci	tmp7 = tmp5 % tmp4;
244062306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL29, tmp6 + ((2 * tmp7) / tmp4));
244162306a36Sopenharmony_ci	tmp8 = b43_radio_read(dev, B2062_S_RFPLL_CTL19);
244262306a36Sopenharmony_ci	tmp9 = ((2 * tmp3 * (tmp8 + 1)) + (3 * tmp1)) / (6 * tmp1);
244362306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL23, (tmp9 >> 8) + 16);
244462306a36Sopenharmony_ci	b43_radio_write(dev, B2062_S_RFPLL_CTL24, tmp9 & 0xFF);
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	lpphy_b2062_vco_calib(dev);
244762306a36Sopenharmony_ci	if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10) {
244862306a36Sopenharmony_ci		b43_radio_write(dev, B2062_S_RFPLL_CTL33, 0xFC);
244962306a36Sopenharmony_ci		b43_radio_write(dev, B2062_S_RFPLL_CTL34, 0);
245062306a36Sopenharmony_ci		lpphy_b2062_reset_pll_bias(dev);
245162306a36Sopenharmony_ci		lpphy_b2062_vco_calib(dev);
245262306a36Sopenharmony_ci		if (b43_radio_read(dev, B2062_S_RFPLL_CTL3) & 0x10)
245362306a36Sopenharmony_ci			err = -EIO;
245462306a36Sopenharmony_ci	}
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	b43_radio_mask(dev, B2062_S_RFPLL_CTL14, ~0x04);
245762306a36Sopenharmony_ci	return err;
245862306a36Sopenharmony_ci}
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_cistatic void lpphy_b2063_vco_calib(struct b43_wldev *dev)
246162306a36Sopenharmony_ci{
246262306a36Sopenharmony_ci	u16 tmp;
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	b43_radio_mask(dev, B2063_PLL_SP1, ~0x40);
246562306a36Sopenharmony_ci	tmp = b43_radio_read(dev, B2063_PLL_JTAG_CALNRST) & 0xF8;
246662306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp);
246762306a36Sopenharmony_ci	udelay(1);
246862306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x4);
246962306a36Sopenharmony_ci	udelay(1);
247062306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x6);
247162306a36Sopenharmony_ci	udelay(1);
247262306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_CALNRST, tmp | 0x7);
247362306a36Sopenharmony_ci	udelay(300);
247462306a36Sopenharmony_ci	b43_radio_set(dev, B2063_PLL_SP1, 0x40);
247562306a36Sopenharmony_ci}
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_cistatic int lpphy_b2063_tune(struct b43_wldev *dev,
247862306a36Sopenharmony_ci			    unsigned int channel)
247962306a36Sopenharmony_ci{
248062306a36Sopenharmony_ci	struct ssb_bus *bus = dev->dev->sdev->bus;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	static const struct b206x_channel *chandata = NULL;
248362306a36Sopenharmony_ci	u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
248462306a36Sopenharmony_ci	u32 freqref, vco_freq, val1, val2, val3, timeout, timeoutref, count;
248562306a36Sopenharmony_ci	u16 old_comm15, scale;
248662306a36Sopenharmony_ci	u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
248762306a36Sopenharmony_ci	int i, div = (crystal_freq <= 26000000 ? 1 : 2);
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(b2063_chantbl); i++) {
249062306a36Sopenharmony_ci		if (b2063_chantbl[i].channel == channel) {
249162306a36Sopenharmony_ci			chandata = &b2063_chantbl[i];
249262306a36Sopenharmony_ci			break;
249362306a36Sopenharmony_ci		}
249462306a36Sopenharmony_ci	}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	if (B43_WARN_ON(!chandata))
249762306a36Sopenharmony_ci		return -EINVAL;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	b43_radio_write(dev, B2063_LOGEN_VCOBUF1, chandata->data[0]);
250062306a36Sopenharmony_ci	b43_radio_write(dev, B2063_LOGEN_MIXER2, chandata->data[1]);
250162306a36Sopenharmony_ci	b43_radio_write(dev, B2063_LOGEN_BUF2, chandata->data[2]);
250262306a36Sopenharmony_ci	b43_radio_write(dev, B2063_LOGEN_RCCR1, chandata->data[3]);
250362306a36Sopenharmony_ci	b43_radio_write(dev, B2063_A_RX_1ST3, chandata->data[4]);
250462306a36Sopenharmony_ci	b43_radio_write(dev, B2063_A_RX_2ND1, chandata->data[5]);
250562306a36Sopenharmony_ci	b43_radio_write(dev, B2063_A_RX_2ND4, chandata->data[6]);
250662306a36Sopenharmony_ci	b43_radio_write(dev, B2063_A_RX_2ND7, chandata->data[7]);
250762306a36Sopenharmony_ci	b43_radio_write(dev, B2063_A_RX_PS6, chandata->data[8]);
250862306a36Sopenharmony_ci	b43_radio_write(dev, B2063_TX_RF_CTL2, chandata->data[9]);
250962306a36Sopenharmony_ci	b43_radio_write(dev, B2063_TX_RF_CTL5, chandata->data[10]);
251062306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PA_CTL11, chandata->data[11]);
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	old_comm15 = b43_radio_read(dev, B2063_COMM15);
251362306a36Sopenharmony_ci	b43_radio_set(dev, B2063_COMM15, 0x1E);
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	if (chandata->freq > 4000) /* spec says 2484, but 4000 is safer */
251662306a36Sopenharmony_ci		vco_freq = chandata->freq << 1;
251762306a36Sopenharmony_ci	else
251862306a36Sopenharmony_ci		vco_freq = chandata->freq << 2;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	freqref = crystal_freq * 3;
252162306a36Sopenharmony_ci	val1 = lpphy_qdiv_roundup(crystal_freq, 1000000, 16);
252262306a36Sopenharmony_ci	val2 = lpphy_qdiv_roundup(crystal_freq, 1000000 * div, 16);
252362306a36Sopenharmony_ci	val3 = lpphy_qdiv_roundup(vco_freq, 3, 16);
252462306a36Sopenharmony_ci	timeout = ((((8 * crystal_freq) / (div * 5000000)) + 1) >> 1) - 1;
252562306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB3, 0x2);
252662306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB6,
252762306a36Sopenharmony_ci			  0xFFF8, timeout >> 2);
252862306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
252962306a36Sopenharmony_ci			  0xFF9F,timeout << 5);
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	timeoutref = ((((8 * crystal_freq) / (div * (timeout + 1))) +
253262306a36Sopenharmony_ci						999999) / 1000000) + 1;
253362306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB5, timeoutref);
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	count = lpphy_qdiv_roundup(val3, val2 + 16, 16);
253662306a36Sopenharmony_ci	count *= (timeout + 1) * (timeoutref + 1);
253762306a36Sopenharmony_ci	count--;
253862306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_VCO_CALIB7,
253962306a36Sopenharmony_ci						0xF0, count >> 8);
254062306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_VCO_CALIB8, count & 0xFF);
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	tmp1 = ((val3 * 62500) / freqref) << 4;
254362306a36Sopenharmony_ci	tmp2 = ((val3 * 62500) % freqref) << 4;
254462306a36Sopenharmony_ci	while (tmp2 >= freqref) {
254562306a36Sopenharmony_ci		tmp1++;
254662306a36Sopenharmony_ci		tmp2 -= freqref;
254762306a36Sopenharmony_ci	}
254862306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG1, 0xFFE0, tmp1 >> 4);
254962306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFE0F, tmp1 << 4);
255062306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_SG2, 0xFFF0, tmp1 >> 16);
255162306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG3, (tmp2 >> 8) & 0xFF);
255262306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_SG4, tmp2 & 0xFF);
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF1, 0xB9);
255562306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF2, 0x88);
255662306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF3, 0x28);
255762306a36Sopenharmony_ci	b43_radio_write(dev, B2063_PLL_JTAG_PLL_LF4, 0x63);
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	tmp3 = ((41 * (val3 - 3000)) /1200) + 27;
256062306a36Sopenharmony_ci	tmp4 = lpphy_qdiv_roundup(132000 * tmp1, 8451, 16);
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	if ((tmp4 + tmp3 - 1) / tmp3 > 60) {
256362306a36Sopenharmony_ci		scale = 1;
256462306a36Sopenharmony_ci		tmp5 = ((tmp4 + tmp3) / (tmp3 << 1)) - 8;
256562306a36Sopenharmony_ci	} else {
256662306a36Sopenharmony_ci		scale = 0;
256762306a36Sopenharmony_ci		tmp5 = ((tmp4 + (tmp3 >> 1)) / tmp3) - 8;
256862306a36Sopenharmony_ci	}
256962306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFC0, tmp5);
257062306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP2, 0xFFBF, scale << 6);
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci	tmp6 = lpphy_qdiv_roundup(100 * val1, val3, 16);
257362306a36Sopenharmony_ci	tmp6 *= (tmp5 * 8) * (scale + 1);
257462306a36Sopenharmony_ci	if (tmp6 > 150)
257562306a36Sopenharmony_ci		tmp6 = 0;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFE0, tmp6);
257862306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_CP3, 0xFFDF, scale << 5);
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	b43_radio_maskset(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFFFB, 0x4);
258162306a36Sopenharmony_ci	if (crystal_freq > 26000000)
258262306a36Sopenharmony_ci		b43_radio_set(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0x2);
258362306a36Sopenharmony_ci	else
258462306a36Sopenharmony_ci		b43_radio_mask(dev, B2063_PLL_JTAG_PLL_XTAL_12, 0xFD);
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	if (val1 == 45)
258762306a36Sopenharmony_ci		b43_radio_set(dev, B2063_PLL_JTAG_PLL_VCO1, 0x2);
258862306a36Sopenharmony_ci	else
258962306a36Sopenharmony_ci		b43_radio_mask(dev, B2063_PLL_JTAG_PLL_VCO1, 0xFD);
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	b43_radio_set(dev, B2063_PLL_SP2, 0x3);
259262306a36Sopenharmony_ci	udelay(1);
259362306a36Sopenharmony_ci	b43_radio_mask(dev, B2063_PLL_SP2, 0xFFFC);
259462306a36Sopenharmony_ci	lpphy_b2063_vco_calib(dev);
259562306a36Sopenharmony_ci	b43_radio_write(dev, B2063_COMM15, old_comm15);
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	return 0;
259862306a36Sopenharmony_ci}
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_cistatic int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
260162306a36Sopenharmony_ci				       unsigned int new_channel)
260262306a36Sopenharmony_ci{
260362306a36Sopenharmony_ci	struct b43_phy_lp *lpphy = dev->phy.lp;
260462306a36Sopenharmony_ci	int err;
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci	if (dev->phy.radio_ver == 0x2063) {
260762306a36Sopenharmony_ci		err = lpphy_b2063_tune(dev, new_channel);
260862306a36Sopenharmony_ci		if (err)
260962306a36Sopenharmony_ci			return err;
261062306a36Sopenharmony_ci	} else {
261162306a36Sopenharmony_ci		err = lpphy_b2062_tune(dev, new_channel);
261262306a36Sopenharmony_ci		if (err)
261362306a36Sopenharmony_ci			return err;
261462306a36Sopenharmony_ci		lpphy_set_analog_filter(dev, new_channel);
261562306a36Sopenharmony_ci		lpphy_adjust_gain_table(dev, channel2freq_lp(new_channel));
261662306a36Sopenharmony_ci	}
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci	lpphy->channel = new_channel;
261962306a36Sopenharmony_ci	b43_write16(dev, B43_MMIO_CHANNEL, new_channel);
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	return 0;
262262306a36Sopenharmony_ci}
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_cistatic int b43_lpphy_op_init(struct b43_wldev *dev)
262562306a36Sopenharmony_ci{
262662306a36Sopenharmony_ci	int err;
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	if (dev->dev->bus_type != B43_BUS_SSB) {
262962306a36Sopenharmony_ci		b43err(dev->wl, "LP-PHY is supported only on SSB!\n");
263062306a36Sopenharmony_ci		return -EOPNOTSUPP;
263162306a36Sopenharmony_ci	}
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
263462306a36Sopenharmony_ci	lpphy_baseband_init(dev);
263562306a36Sopenharmony_ci	lpphy_radio_init(dev);
263662306a36Sopenharmony_ci	lpphy_calibrate_rc(dev);
263762306a36Sopenharmony_ci	err = b43_lpphy_op_switch_channel(dev, 7);
263862306a36Sopenharmony_ci	if (err) {
263962306a36Sopenharmony_ci		b43dbg(dev->wl, "Switch to channel 7 failed, error = %d.\n",
264062306a36Sopenharmony_ci		       err);
264162306a36Sopenharmony_ci	}
264262306a36Sopenharmony_ci	lpphy_tx_pctl_init(dev);
264362306a36Sopenharmony_ci	lpphy_calibration(dev);
264462306a36Sopenharmony_ci	//TODO ACI init
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	return 0;
264762306a36Sopenharmony_ci}
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_cistatic void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
265062306a36Sopenharmony_ci{
265162306a36Sopenharmony_ci	//TODO
265262306a36Sopenharmony_ci}
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_cistatic enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
265562306a36Sopenharmony_ci							 bool ignore_tssi)
265662306a36Sopenharmony_ci{
265762306a36Sopenharmony_ci	//TODO
265862306a36Sopenharmony_ci	return B43_TXPWR_RES_DONE;
265962306a36Sopenharmony_ci}
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_cistatic void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
266262306a36Sopenharmony_ci{
266362306a36Sopenharmony_ci       if (on) {
266462306a36Sopenharmony_ci               b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
266562306a36Sopenharmony_ci       } else {
266662306a36Sopenharmony_ci               b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0x0007);
266762306a36Sopenharmony_ci               b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x0007);
266862306a36Sopenharmony_ci       }
266962306a36Sopenharmony_ci}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_cistatic void b43_lpphy_op_pwork_15sec(struct b43_wldev *dev)
267262306a36Sopenharmony_ci{
267362306a36Sopenharmony_ci	//TODO
267462306a36Sopenharmony_ci}
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ciconst struct b43_phy_operations b43_phyops_lp = {
267762306a36Sopenharmony_ci	.allocate		= b43_lpphy_op_allocate,
267862306a36Sopenharmony_ci	.free			= b43_lpphy_op_free,
267962306a36Sopenharmony_ci	.prepare_structs	= b43_lpphy_op_prepare_structs,
268062306a36Sopenharmony_ci	.init			= b43_lpphy_op_init,
268162306a36Sopenharmony_ci	.phy_maskset		= b43_lpphy_op_maskset,
268262306a36Sopenharmony_ci	.radio_read		= b43_lpphy_op_radio_read,
268362306a36Sopenharmony_ci	.radio_write		= b43_lpphy_op_radio_write,
268462306a36Sopenharmony_ci	.software_rfkill	= b43_lpphy_op_software_rfkill,
268562306a36Sopenharmony_ci	.switch_analog		= b43_lpphy_op_switch_analog,
268662306a36Sopenharmony_ci	.switch_channel		= b43_lpphy_op_switch_channel,
268762306a36Sopenharmony_ci	.get_default_chan	= b43_lpphy_op_get_default_chan,
268862306a36Sopenharmony_ci	.set_rx_antenna		= b43_lpphy_op_set_rx_antenna,
268962306a36Sopenharmony_ci	.recalc_txpower		= b43_lpphy_op_recalc_txpower,
269062306a36Sopenharmony_ci	.adjust_txpower		= b43_lpphy_op_adjust_txpower,
269162306a36Sopenharmony_ci	.pwork_15sec		= b43_lpphy_op_pwork_15sec,
269262306a36Sopenharmony_ci	.pwork_60sec		= lpphy_calibration,
269362306a36Sopenharmony_ci};
2694