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