xref: /linux/drivers/net/wireless/broadcom/b43/phy_g.c (revision 9b793db5)
1ca47d344SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
258619b14SKalle Valo /*
358619b14SKalle Valo 
458619b14SKalle Valo   Broadcom B43 wireless driver
558619b14SKalle Valo   IEEE 802.11g PHY driver
658619b14SKalle Valo 
758619b14SKalle Valo   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
858619b14SKalle Valo   Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
958619b14SKalle Valo   Copyright (c) 2005-2008 Michael Buesch <m@bues.ch>
1058619b14SKalle Valo   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
1158619b14SKalle Valo   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
1258619b14SKalle Valo 
1358619b14SKalle Valo 
1458619b14SKalle Valo */
1558619b14SKalle Valo 
1658619b14SKalle Valo #include "b43.h"
1758619b14SKalle Valo #include "phy_g.h"
1858619b14SKalle Valo #include "phy_common.h"
1958619b14SKalle Valo #include "lo.h"
2058619b14SKalle Valo #include "main.h"
219791333aSGuenter Roeck #include "wa.h"
2258619b14SKalle Valo 
2358619b14SKalle Valo #include <linux/bitrev.h>
2458619b14SKalle Valo #include <linux/slab.h>
2558619b14SKalle Valo 
2658619b14SKalle Valo 
2758619b14SKalle Valo static const s8 b43_tssi2dbm_g_table[] = {
2858619b14SKalle Valo 	77, 77, 77, 76,
2958619b14SKalle Valo 	76, 76, 75, 75,
3058619b14SKalle Valo 	74, 74, 73, 73,
3158619b14SKalle Valo 	73, 72, 72, 71,
3258619b14SKalle Valo 	71, 70, 70, 69,
3358619b14SKalle Valo 	68, 68, 67, 67,
3458619b14SKalle Valo 	66, 65, 65, 64,
3558619b14SKalle Valo 	63, 63, 62, 61,
3658619b14SKalle Valo 	60, 59, 58, 57,
3758619b14SKalle Valo 	56, 55, 54, 53,
3858619b14SKalle Valo 	52, 50, 49, 47,
3958619b14SKalle Valo 	45, 43, 40, 37,
4058619b14SKalle Valo 	33, 28, 22, 14,
4158619b14SKalle Valo 	5, -7, -20, -20,
4258619b14SKalle Valo 	-20, -20, -20, -20,
4358619b14SKalle Valo 	-20, -20, -20, -20,
4458619b14SKalle Valo };
4558619b14SKalle Valo 
4658619b14SKalle Valo static const u8 b43_radio_channel_codes_bg[] = {
4758619b14SKalle Valo 	12, 17, 22, 27,
4858619b14SKalle Valo 	32, 37, 42, 47,
4958619b14SKalle Valo 	52, 57, 62, 67,
5058619b14SKalle Valo 	72, 84,
5158619b14SKalle Valo };
5258619b14SKalle Valo 
5358619b14SKalle Valo 
5458619b14SKalle Valo static void b43_calc_nrssi_threshold(struct b43_wldev *dev);
5558619b14SKalle Valo 
5658619b14SKalle Valo 
5758619b14SKalle Valo #define bitrev4(tmp) (bitrev8(tmp) >> 4)
5858619b14SKalle Valo 
5958619b14SKalle Valo 
6058619b14SKalle Valo /* Get the freq, as it has to be written to the device. */
channel2freq_bg(u8 channel)6158619b14SKalle Valo static inline u16 channel2freq_bg(u8 channel)
6258619b14SKalle Valo {
6358619b14SKalle Valo 	B43_WARN_ON(!(channel >= 1 && channel <= 14));
6458619b14SKalle Valo 
6558619b14SKalle Valo 	return b43_radio_channel_codes_bg[channel - 1];
6658619b14SKalle Valo }
6758619b14SKalle Valo 
generate_rfatt_list(struct b43_wldev * dev,struct b43_rfatt_list * list)6858619b14SKalle Valo static void generate_rfatt_list(struct b43_wldev *dev,
6958619b14SKalle Valo 				struct b43_rfatt_list *list)
7058619b14SKalle Valo {
7158619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
7258619b14SKalle Valo 
7358619b14SKalle Valo 	/* APHY.rev < 5 || GPHY.rev < 6 */
7458619b14SKalle Valo 	static const struct b43_rfatt rfatt_0[] = {
7558619b14SKalle Valo 		{.att = 3,.with_padmix = 0,},
7658619b14SKalle Valo 		{.att = 1,.with_padmix = 0,},
7758619b14SKalle Valo 		{.att = 5,.with_padmix = 0,},
7858619b14SKalle Valo 		{.att = 7,.with_padmix = 0,},
7958619b14SKalle Valo 		{.att = 9,.with_padmix = 0,},
8058619b14SKalle Valo 		{.att = 2,.with_padmix = 0,},
8158619b14SKalle Valo 		{.att = 0,.with_padmix = 0,},
8258619b14SKalle Valo 		{.att = 4,.with_padmix = 0,},
8358619b14SKalle Valo 		{.att = 6,.with_padmix = 0,},
8458619b14SKalle Valo 		{.att = 8,.with_padmix = 0,},
8558619b14SKalle Valo 		{.att = 1,.with_padmix = 1,},
8658619b14SKalle Valo 		{.att = 2,.with_padmix = 1,},
8758619b14SKalle Valo 		{.att = 3,.with_padmix = 1,},
8858619b14SKalle Valo 		{.att = 4,.with_padmix = 1,},
8958619b14SKalle Valo 	};
9058619b14SKalle Valo 	/* Radio.rev == 8 && Radio.version == 0x2050 */
9158619b14SKalle Valo 	static const struct b43_rfatt rfatt_1[] = {
9258619b14SKalle Valo 		{.att = 2,.with_padmix = 1,},
9358619b14SKalle Valo 		{.att = 4,.with_padmix = 1,},
9458619b14SKalle Valo 		{.att = 6,.with_padmix = 1,},
9558619b14SKalle Valo 		{.att = 8,.with_padmix = 1,},
9658619b14SKalle Valo 		{.att = 10,.with_padmix = 1,},
9758619b14SKalle Valo 		{.att = 12,.with_padmix = 1,},
9858619b14SKalle Valo 		{.att = 14,.with_padmix = 1,},
9958619b14SKalle Valo 	};
10058619b14SKalle Valo 	/* Otherwise */
10158619b14SKalle Valo 	static const struct b43_rfatt rfatt_2[] = {
10258619b14SKalle Valo 		{.att = 0,.with_padmix = 1,},
10358619b14SKalle Valo 		{.att = 2,.with_padmix = 1,},
10458619b14SKalle Valo 		{.att = 4,.with_padmix = 1,},
10558619b14SKalle Valo 		{.att = 6,.with_padmix = 1,},
10658619b14SKalle Valo 		{.att = 8,.with_padmix = 1,},
10758619b14SKalle Valo 		{.att = 9,.with_padmix = 1,},
10858619b14SKalle Valo 		{.att = 9,.with_padmix = 1,},
10958619b14SKalle Valo 	};
11058619b14SKalle Valo 
11158619b14SKalle Valo 	if (!b43_has_hardware_pctl(dev)) {
11258619b14SKalle Valo 		/* Software pctl */
11358619b14SKalle Valo 		list->list = rfatt_0;
11458619b14SKalle Valo 		list->len = ARRAY_SIZE(rfatt_0);
11558619b14SKalle Valo 		list->min_val = 0;
11658619b14SKalle Valo 		list->max_val = 9;
11758619b14SKalle Valo 		return;
11858619b14SKalle Valo 	}
11958619b14SKalle Valo 	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
12058619b14SKalle Valo 		/* Hardware pctl */
12158619b14SKalle Valo 		list->list = rfatt_1;
12258619b14SKalle Valo 		list->len = ARRAY_SIZE(rfatt_1);
12358619b14SKalle Valo 		list->min_val = 0;
12458619b14SKalle Valo 		list->max_val = 14;
12558619b14SKalle Valo 		return;
12658619b14SKalle Valo 	}
12758619b14SKalle Valo 	/* Hardware pctl */
12858619b14SKalle Valo 	list->list = rfatt_2;
12958619b14SKalle Valo 	list->len = ARRAY_SIZE(rfatt_2);
13058619b14SKalle Valo 	list->min_val = 0;
13158619b14SKalle Valo 	list->max_val = 9;
13258619b14SKalle Valo }
13358619b14SKalle Valo 
generate_bbatt_list(struct b43_wldev * dev,struct b43_bbatt_list * list)13458619b14SKalle Valo static void generate_bbatt_list(struct b43_wldev *dev,
13558619b14SKalle Valo 				struct b43_bbatt_list *list)
13658619b14SKalle Valo {
13758619b14SKalle Valo 	static const struct b43_bbatt bbatt_0[] = {
13858619b14SKalle Valo 		{.att = 0,},
13958619b14SKalle Valo 		{.att = 1,},
14058619b14SKalle Valo 		{.att = 2,},
14158619b14SKalle Valo 		{.att = 3,},
14258619b14SKalle Valo 		{.att = 4,},
14358619b14SKalle Valo 		{.att = 5,},
14458619b14SKalle Valo 		{.att = 6,},
14558619b14SKalle Valo 		{.att = 7,},
14658619b14SKalle Valo 		{.att = 8,},
14758619b14SKalle Valo 	};
14858619b14SKalle Valo 
14958619b14SKalle Valo 	list->list = bbatt_0;
15058619b14SKalle Valo 	list->len = ARRAY_SIZE(bbatt_0);
15158619b14SKalle Valo 	list->min_val = 0;
15258619b14SKalle Valo 	list->max_val = 8;
15358619b14SKalle Valo }
15458619b14SKalle Valo 
b43_shm_clear_tssi(struct b43_wldev * dev)15558619b14SKalle Valo static void b43_shm_clear_tssi(struct b43_wldev *dev)
15658619b14SKalle Valo {
15758619b14SKalle Valo 	b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
15858619b14SKalle Valo 	b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
15958619b14SKalle Valo 	b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
16058619b14SKalle Valo 	b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
16158619b14SKalle Valo }
16258619b14SKalle Valo 
16358619b14SKalle Valo /* Synthetic PU workaround */
b43_synth_pu_workaround(struct b43_wldev * dev,u8 channel)16458619b14SKalle Valo static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel)
16558619b14SKalle Valo {
16658619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
16758619b14SKalle Valo 
16858619b14SKalle Valo 	might_sleep();
16958619b14SKalle Valo 
17058619b14SKalle Valo 	if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
17158619b14SKalle Valo 		/* We do not need the workaround. */
17258619b14SKalle Valo 		return;
17358619b14SKalle Valo 	}
17458619b14SKalle Valo 
17558619b14SKalle Valo 	if (channel <= 10) {
17658619b14SKalle Valo 		b43_write16(dev, B43_MMIO_CHANNEL,
17758619b14SKalle Valo 			    channel2freq_bg(channel + 4));
17858619b14SKalle Valo 	} else {
17958619b14SKalle Valo 		b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1));
18058619b14SKalle Valo 	}
18158619b14SKalle Valo 	msleep(1);
18258619b14SKalle Valo 	b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
18358619b14SKalle Valo }
18458619b14SKalle Valo 
18558619b14SKalle Valo /* Set the baseband attenuation value on chip. */
b43_gphy_set_baseband_attenuation(struct b43_wldev * dev,u16 baseband_attenuation)18658619b14SKalle Valo void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
18758619b14SKalle Valo 				       u16 baseband_attenuation)
18858619b14SKalle Valo {
18958619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
19058619b14SKalle Valo 
19158619b14SKalle Valo 	if (phy->analog == 0) {
19258619b14SKalle Valo 		b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0)
19358619b14SKalle Valo 						 & 0xFFF0) |
19458619b14SKalle Valo 			    baseband_attenuation);
19558619b14SKalle Valo 	} else if (phy->analog > 1) {
19658619b14SKalle Valo 		b43_phy_maskset(dev, B43_PHY_DACCTL, 0xFFC3, (baseband_attenuation << 2));
19758619b14SKalle Valo 	} else {
19858619b14SKalle Valo 		b43_phy_maskset(dev, B43_PHY_DACCTL, 0xFF87, (baseband_attenuation << 3));
19958619b14SKalle Valo 	}
20058619b14SKalle Valo }
20158619b14SKalle Valo 
20258619b14SKalle Valo /* Adjust the transmission power output (G-PHY) */
b43_set_txpower_g(struct b43_wldev * dev,const struct b43_bbatt * bbatt,const struct b43_rfatt * rfatt,u8 tx_control)20358619b14SKalle Valo static void b43_set_txpower_g(struct b43_wldev *dev,
20458619b14SKalle Valo 			      const struct b43_bbatt *bbatt,
20558619b14SKalle Valo 			      const struct b43_rfatt *rfatt, u8 tx_control)
20658619b14SKalle Valo {
20758619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
20858619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
20958619b14SKalle Valo 	struct b43_txpower_lo_control *lo = gphy->lo_control;
21058619b14SKalle Valo 	u16 bb, rf;
21158619b14SKalle Valo 	u16 tx_bias, tx_magn;
21258619b14SKalle Valo 
21358619b14SKalle Valo 	bb = bbatt->att;
21458619b14SKalle Valo 	rf = rfatt->att;
21558619b14SKalle Valo 	tx_bias = lo->tx_bias;
21658619b14SKalle Valo 	tx_magn = lo->tx_magn;
21758619b14SKalle Valo 	if (unlikely(tx_bias == 0xFF))
21858619b14SKalle Valo 		tx_bias = 0;
21958619b14SKalle Valo 
22058619b14SKalle Valo 	/* Save the values for later. Use memmove, because it's valid
22158619b14SKalle Valo 	 * to pass &gphy->rfatt as rfatt pointer argument. Same for bbatt. */
22258619b14SKalle Valo 	gphy->tx_control = tx_control;
22358619b14SKalle Valo 	memmove(&gphy->rfatt, rfatt, sizeof(*rfatt));
22458619b14SKalle Valo 	gphy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
22558619b14SKalle Valo 	memmove(&gphy->bbatt, bbatt, sizeof(*bbatt));
22658619b14SKalle Valo 
22758619b14SKalle Valo 	if (b43_debug(dev, B43_DBG_XMITPOWER)) {
22858619b14SKalle Valo 		b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
22958619b14SKalle Valo 		       "rfatt(%u), tx_control(0x%02X), "
23058619b14SKalle Valo 		       "tx_bias(0x%02X), tx_magn(0x%02X)\n",
23158619b14SKalle Valo 		       bb, rf, tx_control, tx_bias, tx_magn);
23258619b14SKalle Valo 	}
23358619b14SKalle Valo 
23458619b14SKalle Valo 	b43_gphy_set_baseband_attenuation(dev, bb);
23558619b14SKalle Valo 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf);
23658619b14SKalle Valo 	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
23758619b14SKalle Valo 		b43_radio_write16(dev, 0x43,
23858619b14SKalle Valo 				  (rf & 0x000F) | (tx_control & 0x0070));
23958619b14SKalle Valo 	} else {
24058619b14SKalle Valo 		b43_radio_maskset(dev, 0x43, 0xFFF0, (rf & 0x000F));
24158619b14SKalle Valo 		b43_radio_maskset(dev, 0x52, ~0x0070, (tx_control & 0x0070));
24258619b14SKalle Valo 	}
24358619b14SKalle Valo 	if (has_tx_magnification(phy)) {
24458619b14SKalle Valo 		b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
24558619b14SKalle Valo 	} else {
24658619b14SKalle Valo 		b43_radio_maskset(dev, 0x52, 0xFFF0, (tx_bias & 0x000F));
24758619b14SKalle Valo 	}
24858619b14SKalle Valo 	b43_lo_g_adjust(dev);
24958619b14SKalle Valo }
25058619b14SKalle Valo 
25158619b14SKalle Valo /* GPHY_TSSI_Power_Lookup_Table_Init */
b43_gphy_tssi_power_lt_init(struct b43_wldev * dev)25258619b14SKalle Valo static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev)
25358619b14SKalle Valo {
25458619b14SKalle Valo 	struct b43_phy_g *gphy = dev->phy.g;
25558619b14SKalle Valo 	int i;
25658619b14SKalle Valo 	u16 value;
25758619b14SKalle Valo 
25858619b14SKalle Valo 	for (i = 0; i < 32; i++)
25958619b14SKalle Valo 		b43_ofdmtab_write16(dev, 0x3C20, i, gphy->tssi2dbm[i]);
26058619b14SKalle Valo 	for (i = 32; i < 64; i++)
26158619b14SKalle Valo 		b43_ofdmtab_write16(dev, 0x3C00, i - 32, gphy->tssi2dbm[i]);
26258619b14SKalle Valo 	for (i = 0; i < 64; i += 2) {
26358619b14SKalle Valo 		value = (u16) gphy->tssi2dbm[i];
26458619b14SKalle Valo 		value |= ((u16) gphy->tssi2dbm[i + 1]) << 8;
26558619b14SKalle Valo 		b43_phy_write(dev, 0x380 + (i / 2), value);
26658619b14SKalle Valo 	}
26758619b14SKalle Valo }
26858619b14SKalle Valo 
26958619b14SKalle Valo /* GPHY_Gain_Lookup_Table_Init */
b43_gphy_gain_lt_init(struct b43_wldev * dev)27058619b14SKalle Valo static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
27158619b14SKalle Valo {
27258619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
27358619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
27458619b14SKalle Valo 	struct b43_txpower_lo_control *lo = gphy->lo_control;
27558619b14SKalle Valo 	u16 nr_written = 0;
27658619b14SKalle Valo 	u16 tmp;
27758619b14SKalle Valo 	u8 rf, bb;
27858619b14SKalle Valo 
27958619b14SKalle Valo 	for (rf = 0; rf < lo->rfatt_list.len; rf++) {
28058619b14SKalle Valo 		for (bb = 0; bb < lo->bbatt_list.len; bb++) {
28158619b14SKalle Valo 			if (nr_written >= 0x40)
28258619b14SKalle Valo 				return;
28358619b14SKalle Valo 			tmp = lo->bbatt_list.list[bb].att;
28458619b14SKalle Valo 			tmp <<= 8;
28558619b14SKalle Valo 			if (phy->radio_rev == 8)
28658619b14SKalle Valo 				tmp |= 0x50;
28758619b14SKalle Valo 			else
28858619b14SKalle Valo 				tmp |= 0x40;
28958619b14SKalle Valo 			tmp |= lo->rfatt_list.list[rf].att;
29058619b14SKalle Valo 			b43_phy_write(dev, 0x3C0 + nr_written, tmp);
29158619b14SKalle Valo 			nr_written++;
29258619b14SKalle Valo 		}
29358619b14SKalle Valo 	}
29458619b14SKalle Valo }
29558619b14SKalle Valo 
b43_set_all_gains(struct b43_wldev * dev,s16 first,s16 second,s16 third)29658619b14SKalle Valo static void b43_set_all_gains(struct b43_wldev *dev,
29758619b14SKalle Valo 			      s16 first, s16 second, s16 third)
29858619b14SKalle Valo {
29958619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
30058619b14SKalle Valo 	u16 i;
30158619b14SKalle Valo 	u16 start = 0x08, end = 0x18;
30258619b14SKalle Valo 	u16 tmp;
30358619b14SKalle Valo 	u16 table;
30458619b14SKalle Valo 
30558619b14SKalle Valo 	if (phy->rev <= 1) {
30658619b14SKalle Valo 		start = 0x10;
30758619b14SKalle Valo 		end = 0x20;
30858619b14SKalle Valo 	}
30958619b14SKalle Valo 
31058619b14SKalle Valo 	table = B43_OFDMTAB_GAINX;
31158619b14SKalle Valo 	if (phy->rev <= 1)
31258619b14SKalle Valo 		table = B43_OFDMTAB_GAINX_R1;
31358619b14SKalle Valo 	for (i = 0; i < 4; i++)
31458619b14SKalle Valo 		b43_ofdmtab_write16(dev, table, i, first);
31558619b14SKalle Valo 
31658619b14SKalle Valo 	for (i = start; i < end; i++)
31758619b14SKalle Valo 		b43_ofdmtab_write16(dev, table, i, second);
31858619b14SKalle Valo 
31958619b14SKalle Valo 	if (third != -1) {
32058619b14SKalle Valo 		tmp = ((u16) third << 14) | ((u16) third << 6);
32158619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A0, 0xBFBF, tmp);
32258619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp);
32358619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp);
32458619b14SKalle Valo 	}
32558619b14SKalle Valo 	b43_dummy_transmission(dev, false, true);
32658619b14SKalle Valo }
32758619b14SKalle Valo 
b43_set_original_gains(struct b43_wldev * dev)32858619b14SKalle Valo static void b43_set_original_gains(struct b43_wldev *dev)
32958619b14SKalle Valo {
33058619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
33158619b14SKalle Valo 	u16 i, tmp;
33258619b14SKalle Valo 	u16 table;
33358619b14SKalle Valo 	u16 start = 0x0008, end = 0x0018;
33458619b14SKalle Valo 
33558619b14SKalle Valo 	if (phy->rev <= 1) {
33658619b14SKalle Valo 		start = 0x0010;
33758619b14SKalle Valo 		end = 0x0020;
33858619b14SKalle Valo 	}
33958619b14SKalle Valo 
34058619b14SKalle Valo 	table = B43_OFDMTAB_GAINX;
34158619b14SKalle Valo 	if (phy->rev <= 1)
34258619b14SKalle Valo 		table = B43_OFDMTAB_GAINX_R1;
34358619b14SKalle Valo 	for (i = 0; i < 4; i++) {
34458619b14SKalle Valo 		tmp = (i & 0xFFFC);
34558619b14SKalle Valo 		tmp |= (i & 0x0001) << 1;
34658619b14SKalle Valo 		tmp |= (i & 0x0002) >> 1;
34758619b14SKalle Valo 
34858619b14SKalle Valo 		b43_ofdmtab_write16(dev, table, i, tmp);
34958619b14SKalle Valo 	}
35058619b14SKalle Valo 
35158619b14SKalle Valo 	for (i = start; i < end; i++)
35258619b14SKalle Valo 		b43_ofdmtab_write16(dev, table, i, i - start);
35358619b14SKalle Valo 
35458619b14SKalle Valo 	b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040);
35558619b14SKalle Valo 	b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040);
35658619b14SKalle Valo 	b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000);
35758619b14SKalle Valo 	b43_dummy_transmission(dev, false, true);
35858619b14SKalle Valo }
35958619b14SKalle Valo 
3602d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43_nrssi_hw_write(struct b43_wldev * dev,u16 offset,s16 val)36158619b14SKalle Valo static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
36258619b14SKalle Valo {
36358619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
36458619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
36558619b14SKalle Valo }
36658619b14SKalle Valo 
3672d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43_nrssi_hw_read(struct b43_wldev * dev,u16 offset)36858619b14SKalle Valo static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
36958619b14SKalle Valo {
37058619b14SKalle Valo 	u16 val;
37158619b14SKalle Valo 
37258619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
37358619b14SKalle Valo 	val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA);
37458619b14SKalle Valo 
37558619b14SKalle Valo 	return (s16) val;
37658619b14SKalle Valo }
37758619b14SKalle Valo 
3782d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43_nrssi_hw_update(struct b43_wldev * dev,u16 val)37958619b14SKalle Valo static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
38058619b14SKalle Valo {
38158619b14SKalle Valo 	u16 i;
38258619b14SKalle Valo 	s16 tmp;
38358619b14SKalle Valo 
38458619b14SKalle Valo 	for (i = 0; i < 64; i++) {
38558619b14SKalle Valo 		tmp = b43_nrssi_hw_read(dev, i);
38658619b14SKalle Valo 		tmp -= val;
38758619b14SKalle Valo 		tmp = clamp_val(tmp, -32, 31);
38858619b14SKalle Valo 		b43_nrssi_hw_write(dev, i, tmp);
38958619b14SKalle Valo 	}
39058619b14SKalle Valo }
39158619b14SKalle Valo 
3922d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/NRSSILookupTable */
b43_nrssi_mem_update(struct b43_wldev * dev)39358619b14SKalle Valo static void b43_nrssi_mem_update(struct b43_wldev *dev)
39458619b14SKalle Valo {
39558619b14SKalle Valo 	struct b43_phy_g *gphy = dev->phy.g;
39658619b14SKalle Valo 	s16 i, delta;
39758619b14SKalle Valo 	s32 tmp;
39858619b14SKalle Valo 
39958619b14SKalle Valo 	delta = 0x1F - gphy->nrssi[0];
40058619b14SKalle Valo 	for (i = 0; i < 64; i++) {
40158619b14SKalle Valo 		tmp = (i - delta) * gphy->nrssislope;
40258619b14SKalle Valo 		tmp /= 0x10000;
40358619b14SKalle Valo 		tmp += 0x3A;
40458619b14SKalle Valo 		tmp = clamp_val(tmp, 0, 0x3F);
40558619b14SKalle Valo 		gphy->nrssi_lt[i] = tmp;
40658619b14SKalle Valo 	}
40758619b14SKalle Valo }
40858619b14SKalle Valo 
b43_calc_nrssi_offset(struct b43_wldev * dev)40958619b14SKalle Valo static void b43_calc_nrssi_offset(struct b43_wldev *dev)
41058619b14SKalle Valo {
41158619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
41258619b14SKalle Valo 	u16 backup[20] = { 0 };
41358619b14SKalle Valo 	s16 v47F;
41458619b14SKalle Valo 	u16 i;
41558619b14SKalle Valo 	u16 saved = 0xFFFF;
41658619b14SKalle Valo 
41758619b14SKalle Valo 	backup[0] = b43_phy_read(dev, 0x0001);
41858619b14SKalle Valo 	backup[1] = b43_phy_read(dev, 0x0811);
41958619b14SKalle Valo 	backup[2] = b43_phy_read(dev, 0x0812);
42058619b14SKalle Valo 	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
42158619b14SKalle Valo 		backup[3] = b43_phy_read(dev, 0x0814);
42258619b14SKalle Valo 		backup[4] = b43_phy_read(dev, 0x0815);
42358619b14SKalle Valo 	}
42458619b14SKalle Valo 	backup[5] = b43_phy_read(dev, 0x005A);
42558619b14SKalle Valo 	backup[6] = b43_phy_read(dev, 0x0059);
42658619b14SKalle Valo 	backup[7] = b43_phy_read(dev, 0x0058);
42758619b14SKalle Valo 	backup[8] = b43_phy_read(dev, 0x000A);
42858619b14SKalle Valo 	backup[9] = b43_phy_read(dev, 0x0003);
42958619b14SKalle Valo 	backup[10] = b43_radio_read16(dev, 0x007A);
43058619b14SKalle Valo 	backup[11] = b43_radio_read16(dev, 0x0043);
43158619b14SKalle Valo 
43258619b14SKalle Valo 	b43_phy_mask(dev, 0x0429, 0x7FFF);
43358619b14SKalle Valo 	b43_phy_maskset(dev, 0x0001, 0x3FFF, 0x4000);
43458619b14SKalle Valo 	b43_phy_set(dev, 0x0811, 0x000C);
43558619b14SKalle Valo 	b43_phy_maskset(dev, 0x0812, 0xFFF3, 0x0004);
43658619b14SKalle Valo 	b43_phy_mask(dev, 0x0802, ~(0x1 | 0x2));
43758619b14SKalle Valo 	if (phy->rev >= 6) {
43858619b14SKalle Valo 		backup[12] = b43_phy_read(dev, 0x002E);
43958619b14SKalle Valo 		backup[13] = b43_phy_read(dev, 0x002F);
44058619b14SKalle Valo 		backup[14] = b43_phy_read(dev, 0x080F);
44158619b14SKalle Valo 		backup[15] = b43_phy_read(dev, 0x0810);
44258619b14SKalle Valo 		backup[16] = b43_phy_read(dev, 0x0801);
44358619b14SKalle Valo 		backup[17] = b43_phy_read(dev, 0x0060);
44458619b14SKalle Valo 		backup[18] = b43_phy_read(dev, 0x0014);
44558619b14SKalle Valo 		backup[19] = b43_phy_read(dev, 0x0478);
44658619b14SKalle Valo 
44758619b14SKalle Valo 		b43_phy_write(dev, 0x002E, 0);
44858619b14SKalle Valo 		b43_phy_write(dev, 0x002F, 0);
44958619b14SKalle Valo 		b43_phy_write(dev, 0x080F, 0);
45058619b14SKalle Valo 		b43_phy_write(dev, 0x0810, 0);
45158619b14SKalle Valo 		b43_phy_set(dev, 0x0478, 0x0100);
45258619b14SKalle Valo 		b43_phy_set(dev, 0x0801, 0x0040);
45358619b14SKalle Valo 		b43_phy_set(dev, 0x0060, 0x0040);
45458619b14SKalle Valo 		b43_phy_set(dev, 0x0014, 0x0200);
45558619b14SKalle Valo 	}
45658619b14SKalle Valo 	b43_radio_set(dev, 0x007A, 0x0070);
45758619b14SKalle Valo 	b43_radio_set(dev, 0x007A, 0x0080);
45858619b14SKalle Valo 	udelay(30);
45958619b14SKalle Valo 
46058619b14SKalle Valo 	v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
46158619b14SKalle Valo 	if (v47F >= 0x20)
46258619b14SKalle Valo 		v47F -= 0x40;
46358619b14SKalle Valo 	if (v47F == 31) {
46458619b14SKalle Valo 		for (i = 7; i >= 4; i--) {
46558619b14SKalle Valo 			b43_radio_write16(dev, 0x007B, i);
46658619b14SKalle Valo 			udelay(20);
46758619b14SKalle Valo 			v47F =
46858619b14SKalle Valo 			    (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
46958619b14SKalle Valo 			if (v47F >= 0x20)
47058619b14SKalle Valo 				v47F -= 0x40;
47158619b14SKalle Valo 			if (v47F < 31 && saved == 0xFFFF)
47258619b14SKalle Valo 				saved = i;
47358619b14SKalle Valo 		}
47458619b14SKalle Valo 		if (saved == 0xFFFF)
47558619b14SKalle Valo 			saved = 4;
47658619b14SKalle Valo 	} else {
47758619b14SKalle Valo 		b43_radio_mask(dev, 0x007A, 0x007F);
47858619b14SKalle Valo 		if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
47958619b14SKalle Valo 			b43_phy_set(dev, 0x0814, 0x0001);
48058619b14SKalle Valo 			b43_phy_mask(dev, 0x0815, 0xFFFE);
48158619b14SKalle Valo 		}
48258619b14SKalle Valo 		b43_phy_set(dev, 0x0811, 0x000C);
48358619b14SKalle Valo 		b43_phy_set(dev, 0x0812, 0x000C);
48458619b14SKalle Valo 		b43_phy_set(dev, 0x0811, 0x0030);
48558619b14SKalle Valo 		b43_phy_set(dev, 0x0812, 0x0030);
48658619b14SKalle Valo 		b43_phy_write(dev, 0x005A, 0x0480);
48758619b14SKalle Valo 		b43_phy_write(dev, 0x0059, 0x0810);
48858619b14SKalle Valo 		b43_phy_write(dev, 0x0058, 0x000D);
48958619b14SKalle Valo 		if (phy->rev == 0) {
49058619b14SKalle Valo 			b43_phy_write(dev, 0x0003, 0x0122);
49158619b14SKalle Valo 		} else {
49258619b14SKalle Valo 			b43_phy_set(dev, 0x000A, 0x2000);
49358619b14SKalle Valo 		}
49458619b14SKalle Valo 		if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
49558619b14SKalle Valo 			b43_phy_set(dev, 0x0814, 0x0004);
49658619b14SKalle Valo 			b43_phy_mask(dev, 0x0815, 0xFFFB);
49758619b14SKalle Valo 		}
49858619b14SKalle Valo 		b43_phy_maskset(dev, 0x0003, 0xFF9F, 0x0040);
49958619b14SKalle Valo 		b43_radio_set(dev, 0x007A, 0x000F);
50058619b14SKalle Valo 		b43_set_all_gains(dev, 3, 0, 1);
50158619b14SKalle Valo 		b43_radio_maskset(dev, 0x0043, 0x00F0, 0x000F);
50258619b14SKalle Valo 		udelay(30);
50358619b14SKalle Valo 		v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
50458619b14SKalle Valo 		if (v47F >= 0x20)
50558619b14SKalle Valo 			v47F -= 0x40;
50658619b14SKalle Valo 		if (v47F == -32) {
50758619b14SKalle Valo 			for (i = 0; i < 4; i++) {
50858619b14SKalle Valo 				b43_radio_write16(dev, 0x007B, i);
50958619b14SKalle Valo 				udelay(20);
51058619b14SKalle Valo 				v47F =
51158619b14SKalle Valo 				    (s16) ((b43_phy_read(dev, 0x047F) >> 8) &
51258619b14SKalle Valo 					   0x003F);
51358619b14SKalle Valo 				if (v47F >= 0x20)
51458619b14SKalle Valo 					v47F -= 0x40;
51558619b14SKalle Valo 				if (v47F > -31 && saved == 0xFFFF)
51658619b14SKalle Valo 					saved = i;
51758619b14SKalle Valo 			}
51858619b14SKalle Valo 			if (saved == 0xFFFF)
51958619b14SKalle Valo 				saved = 3;
52058619b14SKalle Valo 		} else
52158619b14SKalle Valo 			saved = 0;
52258619b14SKalle Valo 	}
52358619b14SKalle Valo 	b43_radio_write16(dev, 0x007B, saved);
52458619b14SKalle Valo 
52558619b14SKalle Valo 	if (phy->rev >= 6) {
52658619b14SKalle Valo 		b43_phy_write(dev, 0x002E, backup[12]);
52758619b14SKalle Valo 		b43_phy_write(dev, 0x002F, backup[13]);
52858619b14SKalle Valo 		b43_phy_write(dev, 0x080F, backup[14]);
52958619b14SKalle Valo 		b43_phy_write(dev, 0x0810, backup[15]);
53058619b14SKalle Valo 	}
53158619b14SKalle Valo 	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
53258619b14SKalle Valo 		b43_phy_write(dev, 0x0814, backup[3]);
53358619b14SKalle Valo 		b43_phy_write(dev, 0x0815, backup[4]);
53458619b14SKalle Valo 	}
53558619b14SKalle Valo 	b43_phy_write(dev, 0x005A, backup[5]);
53658619b14SKalle Valo 	b43_phy_write(dev, 0x0059, backup[6]);
53758619b14SKalle Valo 	b43_phy_write(dev, 0x0058, backup[7]);
53858619b14SKalle Valo 	b43_phy_write(dev, 0x000A, backup[8]);
53958619b14SKalle Valo 	b43_phy_write(dev, 0x0003, backup[9]);
54058619b14SKalle Valo 	b43_radio_write16(dev, 0x0043, backup[11]);
54158619b14SKalle Valo 	b43_radio_write16(dev, 0x007A, backup[10]);
54258619b14SKalle Valo 	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
54358619b14SKalle Valo 	b43_phy_set(dev, 0x0429, 0x8000);
54458619b14SKalle Valo 	b43_set_original_gains(dev);
54558619b14SKalle Valo 	if (phy->rev >= 6) {
54658619b14SKalle Valo 		b43_phy_write(dev, 0x0801, backup[16]);
54758619b14SKalle Valo 		b43_phy_write(dev, 0x0060, backup[17]);
54858619b14SKalle Valo 		b43_phy_write(dev, 0x0014, backup[18]);
54958619b14SKalle Valo 		b43_phy_write(dev, 0x0478, backup[19]);
55058619b14SKalle Valo 	}
55158619b14SKalle Valo 	b43_phy_write(dev, 0x0001, backup[0]);
55258619b14SKalle Valo 	b43_phy_write(dev, 0x0812, backup[2]);
55358619b14SKalle Valo 	b43_phy_write(dev, 0x0811, backup[1]);
55458619b14SKalle Valo }
55558619b14SKalle Valo 
b43_calc_nrssi_slope(struct b43_wldev * dev)55658619b14SKalle Valo static void b43_calc_nrssi_slope(struct b43_wldev *dev)
55758619b14SKalle Valo {
55858619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
55958619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
56058619b14SKalle Valo 	u16 backup[18] = { 0 };
56158619b14SKalle Valo 	u16 tmp;
56258619b14SKalle Valo 	s16 nrssi0, nrssi1;
56358619b14SKalle Valo 
56458619b14SKalle Valo 	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
56558619b14SKalle Valo 
56658619b14SKalle Valo 	if (phy->radio_rev >= 9)
56758619b14SKalle Valo 		return;
56858619b14SKalle Valo 	if (phy->radio_rev == 8)
56958619b14SKalle Valo 		b43_calc_nrssi_offset(dev);
57058619b14SKalle Valo 
57158619b14SKalle Valo 	b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF);
57258619b14SKalle Valo 	b43_phy_mask(dev, 0x0802, 0xFFFC);
57358619b14SKalle Valo 	backup[7] = b43_read16(dev, 0x03E2);
57458619b14SKalle Valo 	b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
57558619b14SKalle Valo 	backup[0] = b43_radio_read16(dev, 0x007A);
57658619b14SKalle Valo 	backup[1] = b43_radio_read16(dev, 0x0052);
57758619b14SKalle Valo 	backup[2] = b43_radio_read16(dev, 0x0043);
57858619b14SKalle Valo 	backup[3] = b43_phy_read(dev, 0x0015);
57958619b14SKalle Valo 	backup[4] = b43_phy_read(dev, 0x005A);
58058619b14SKalle Valo 	backup[5] = b43_phy_read(dev, 0x0059);
58158619b14SKalle Valo 	backup[6] = b43_phy_read(dev, 0x0058);
58258619b14SKalle Valo 	backup[8] = b43_read16(dev, 0x03E6);
58358619b14SKalle Valo 	backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
58458619b14SKalle Valo 	if (phy->rev >= 3) {
58558619b14SKalle Valo 		backup[10] = b43_phy_read(dev, 0x002E);
58658619b14SKalle Valo 		backup[11] = b43_phy_read(dev, 0x002F);
58758619b14SKalle Valo 		backup[12] = b43_phy_read(dev, 0x080F);
58858619b14SKalle Valo 		backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL);
58958619b14SKalle Valo 		backup[14] = b43_phy_read(dev, 0x0801);
59058619b14SKalle Valo 		backup[15] = b43_phy_read(dev, 0x0060);
59158619b14SKalle Valo 		backup[16] = b43_phy_read(dev, 0x0014);
59258619b14SKalle Valo 		backup[17] = b43_phy_read(dev, 0x0478);
59358619b14SKalle Valo 		b43_phy_write(dev, 0x002E, 0);
59458619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0);
59558619b14SKalle Valo 		switch (phy->rev) {
59658619b14SKalle Valo 		case 4:
59758619b14SKalle Valo 		case 6:
59858619b14SKalle Valo 		case 7:
59958619b14SKalle Valo 			b43_phy_set(dev, 0x0478, 0x0100);
60058619b14SKalle Valo 			b43_phy_set(dev, 0x0801, 0x0040);
60158619b14SKalle Valo 			break;
60258619b14SKalle Valo 		case 3:
60358619b14SKalle Valo 		case 5:
60458619b14SKalle Valo 			b43_phy_mask(dev, 0x0801, 0xFFBF);
60558619b14SKalle Valo 			break;
60658619b14SKalle Valo 		}
60758619b14SKalle Valo 		b43_phy_set(dev, 0x0060, 0x0040);
60858619b14SKalle Valo 		b43_phy_set(dev, 0x0014, 0x0200);
60958619b14SKalle Valo 	}
61058619b14SKalle Valo 	b43_radio_set(dev, 0x007A, 0x0070);
61158619b14SKalle Valo 	b43_set_all_gains(dev, 0, 8, 0);
61258619b14SKalle Valo 	b43_radio_mask(dev, 0x007A, 0x00F7);
61358619b14SKalle Valo 	if (phy->rev >= 2) {
61458619b14SKalle Valo 		b43_phy_maskset(dev, 0x0811, 0xFFCF, 0x0030);
61558619b14SKalle Valo 		b43_phy_maskset(dev, 0x0812, 0xFFCF, 0x0010);
61658619b14SKalle Valo 	}
61758619b14SKalle Valo 	b43_radio_set(dev, 0x007A, 0x0080);
61858619b14SKalle Valo 	udelay(20);
61958619b14SKalle Valo 
62058619b14SKalle Valo 	nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
62158619b14SKalle Valo 	if (nrssi0 >= 0x0020)
62258619b14SKalle Valo 		nrssi0 -= 0x0040;
62358619b14SKalle Valo 
62458619b14SKalle Valo 	b43_radio_mask(dev, 0x007A, 0x007F);
62558619b14SKalle Valo 	if (phy->rev >= 2) {
62658619b14SKalle Valo 		b43_phy_maskset(dev, 0x0003, 0xFF9F, 0x0040);
62758619b14SKalle Valo 	}
62858619b14SKalle Valo 
62958619b14SKalle Valo 	b43_write16(dev, B43_MMIO_CHANNEL_EXT,
63058619b14SKalle Valo 		    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
63158619b14SKalle Valo 		    | 0x2000);
63258619b14SKalle Valo 	b43_radio_set(dev, 0x007A, 0x000F);
63358619b14SKalle Valo 	b43_phy_write(dev, 0x0015, 0xF330);
63458619b14SKalle Valo 	if (phy->rev >= 2) {
63558619b14SKalle Valo 		b43_phy_maskset(dev, 0x0812, 0xFFCF, 0x0020);
63658619b14SKalle Valo 		b43_phy_maskset(dev, 0x0811, 0xFFCF, 0x0020);
63758619b14SKalle Valo 	}
63858619b14SKalle Valo 
63958619b14SKalle Valo 	b43_set_all_gains(dev, 3, 0, 1);
64058619b14SKalle Valo 	if (phy->radio_rev == 8) {
64158619b14SKalle Valo 		b43_radio_write16(dev, 0x0043, 0x001F);
64258619b14SKalle Valo 	} else {
64358619b14SKalle Valo 		tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F;
64458619b14SKalle Valo 		b43_radio_write16(dev, 0x0052, tmp | 0x0060);
64558619b14SKalle Valo 		tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0;
64658619b14SKalle Valo 		b43_radio_write16(dev, 0x0043, tmp | 0x0009);
64758619b14SKalle Valo 	}
64858619b14SKalle Valo 	b43_phy_write(dev, 0x005A, 0x0480);
64958619b14SKalle Valo 	b43_phy_write(dev, 0x0059, 0x0810);
65058619b14SKalle Valo 	b43_phy_write(dev, 0x0058, 0x000D);
65158619b14SKalle Valo 	udelay(20);
65258619b14SKalle Valo 	nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
65358619b14SKalle Valo 	if (nrssi1 >= 0x0020)
65458619b14SKalle Valo 		nrssi1 -= 0x0040;
65558619b14SKalle Valo 	if (nrssi0 == nrssi1)
65658619b14SKalle Valo 		gphy->nrssislope = 0x00010000;
65758619b14SKalle Valo 	else
65858619b14SKalle Valo 		gphy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
65958619b14SKalle Valo 	if (nrssi0 >= -4) {
66058619b14SKalle Valo 		gphy->nrssi[0] = nrssi1;
66158619b14SKalle Valo 		gphy->nrssi[1] = nrssi0;
66258619b14SKalle Valo 	}
66358619b14SKalle Valo 	if (phy->rev >= 3) {
66458619b14SKalle Valo 		b43_phy_write(dev, 0x002E, backup[10]);
66558619b14SKalle Valo 		b43_phy_write(dev, 0x002F, backup[11]);
66658619b14SKalle Valo 		b43_phy_write(dev, 0x080F, backup[12]);
66758619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
66858619b14SKalle Valo 	}
66958619b14SKalle Valo 	if (phy->rev >= 2) {
67058619b14SKalle Valo 		b43_phy_mask(dev, 0x0812, 0xFFCF);
67158619b14SKalle Valo 		b43_phy_mask(dev, 0x0811, 0xFFCF);
67258619b14SKalle Valo 	}
67358619b14SKalle Valo 
67458619b14SKalle Valo 	b43_radio_write16(dev, 0x007A, backup[0]);
67558619b14SKalle Valo 	b43_radio_write16(dev, 0x0052, backup[1]);
67658619b14SKalle Valo 	b43_radio_write16(dev, 0x0043, backup[2]);
67758619b14SKalle Valo 	b43_write16(dev, 0x03E2, backup[7]);
67858619b14SKalle Valo 	b43_write16(dev, 0x03E6, backup[8]);
67958619b14SKalle Valo 	b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]);
68058619b14SKalle Valo 	b43_phy_write(dev, 0x0015, backup[3]);
68158619b14SKalle Valo 	b43_phy_write(dev, 0x005A, backup[4]);
68258619b14SKalle Valo 	b43_phy_write(dev, 0x0059, backup[5]);
68358619b14SKalle Valo 	b43_phy_write(dev, 0x0058, backup[6]);
68458619b14SKalle Valo 	b43_synth_pu_workaround(dev, phy->channel);
68558619b14SKalle Valo 	b43_phy_set(dev, 0x0802, (0x0001 | 0x0002));
68658619b14SKalle Valo 	b43_set_original_gains(dev);
68758619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_G_CRS, 0x8000);
68858619b14SKalle Valo 	if (phy->rev >= 3) {
68958619b14SKalle Valo 		b43_phy_write(dev, 0x0801, backup[14]);
69058619b14SKalle Valo 		b43_phy_write(dev, 0x0060, backup[15]);
69158619b14SKalle Valo 		b43_phy_write(dev, 0x0014, backup[16]);
69258619b14SKalle Valo 		b43_phy_write(dev, 0x0478, backup[17]);
69358619b14SKalle Valo 	}
69458619b14SKalle Valo 	b43_nrssi_mem_update(dev);
69558619b14SKalle Valo 	b43_calc_nrssi_threshold(dev);
69658619b14SKalle Valo }
69758619b14SKalle Valo 
b43_calc_nrssi_threshold(struct b43_wldev * dev)69858619b14SKalle Valo static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
69958619b14SKalle Valo {
70058619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
70158619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
70258619b14SKalle Valo 	s32 a, b;
70358619b14SKalle Valo 	s16 tmp16;
70458619b14SKalle Valo 	u16 tmp_u16;
70558619b14SKalle Valo 
70658619b14SKalle Valo 	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
70758619b14SKalle Valo 
70858619b14SKalle Valo 	if (!phy->gmode ||
70958619b14SKalle Valo 	    !(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) {
71058619b14SKalle Valo 		tmp16 = b43_nrssi_hw_read(dev, 0x20);
71158619b14SKalle Valo 		if (tmp16 >= 0x20)
71258619b14SKalle Valo 			tmp16 -= 0x40;
71358619b14SKalle Valo 		if (tmp16 < 3) {
71458619b14SKalle Valo 			b43_phy_maskset(dev, 0x048A, 0xF000, 0x09EB);
71558619b14SKalle Valo 		} else {
71658619b14SKalle Valo 			b43_phy_maskset(dev, 0x048A, 0xF000, 0x0AED);
71758619b14SKalle Valo 		}
71858619b14SKalle Valo 	} else {
71958619b14SKalle Valo 		if (gphy->interfmode == B43_INTERFMODE_NONWLAN) {
72058619b14SKalle Valo 			a = 0xE;
72158619b14SKalle Valo 			b = 0xA;
72258619b14SKalle Valo 		} else if (!gphy->aci_wlan_automatic && gphy->aci_enable) {
72358619b14SKalle Valo 			a = 0x13;
72458619b14SKalle Valo 			b = 0x12;
72558619b14SKalle Valo 		} else {
72658619b14SKalle Valo 			a = 0xE;
72758619b14SKalle Valo 			b = 0x11;
72858619b14SKalle Valo 		}
72958619b14SKalle Valo 
73058619b14SKalle Valo 		a = a * (gphy->nrssi[1] - gphy->nrssi[0]);
73158619b14SKalle Valo 		a += (gphy->nrssi[0] << 6);
73258619b14SKalle Valo 		if (a < 32)
73358619b14SKalle Valo 			a += 31;
73458619b14SKalle Valo 		else
73558619b14SKalle Valo 			a += 32;
73658619b14SKalle Valo 		a = a >> 6;
73758619b14SKalle Valo 		a = clamp_val(a, -31, 31);
73858619b14SKalle Valo 
73958619b14SKalle Valo 		b = b * (gphy->nrssi[1] - gphy->nrssi[0]);
74058619b14SKalle Valo 		b += (gphy->nrssi[0] << 6);
74158619b14SKalle Valo 		if (b < 32)
74258619b14SKalle Valo 			b += 31;
74358619b14SKalle Valo 		else
74458619b14SKalle Valo 			b += 32;
74558619b14SKalle Valo 		b = b >> 6;
74658619b14SKalle Valo 		b = clamp_val(b, -31, 31);
74758619b14SKalle Valo 
74858619b14SKalle Valo 		tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
74958619b14SKalle Valo 		tmp_u16 |= ((u32) b & 0x0000003F);
75058619b14SKalle Valo 		tmp_u16 |= (((u32) a & 0x0000003F) << 6);
75158619b14SKalle Valo 		b43_phy_write(dev, 0x048A, tmp_u16);
75258619b14SKalle Valo 	}
75358619b14SKalle Valo }
75458619b14SKalle Valo 
75558619b14SKalle Valo /* Stack implementation to save/restore values from the
75658619b14SKalle Valo  * interference mitigation code.
75758619b14SKalle Valo  * It is save to restore values in random order.
75858619b14SKalle Valo  */
_stack_save(u32 * _stackptr,size_t * stackidx,u8 id,u16 offset,u16 value)75958619b14SKalle Valo static void _stack_save(u32 *_stackptr, size_t *stackidx,
76058619b14SKalle Valo 			u8 id, u16 offset, u16 value)
76158619b14SKalle Valo {
76258619b14SKalle Valo 	u32 *stackptr = &(_stackptr[*stackidx]);
76358619b14SKalle Valo 
76458619b14SKalle Valo 	B43_WARN_ON(offset & 0xF000);
76558619b14SKalle Valo 	B43_WARN_ON(id & 0xF0);
76658619b14SKalle Valo 	*stackptr = offset;
76758619b14SKalle Valo 	*stackptr |= ((u32) id) << 12;
76858619b14SKalle Valo 	*stackptr |= ((u32) value) << 16;
76958619b14SKalle Valo 	(*stackidx)++;
77058619b14SKalle Valo 	B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
77158619b14SKalle Valo }
77258619b14SKalle Valo 
_stack_restore(u32 * stackptr,u8 id,u16 offset)77358619b14SKalle Valo static u16 _stack_restore(u32 *stackptr, u8 id, u16 offset)
77458619b14SKalle Valo {
77558619b14SKalle Valo 	size_t i;
77658619b14SKalle Valo 
77758619b14SKalle Valo 	B43_WARN_ON(offset & 0xF000);
77858619b14SKalle Valo 	B43_WARN_ON(id & 0xF0);
77958619b14SKalle Valo 	for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) {
78058619b14SKalle Valo 		if ((*stackptr & 0x00000FFF) != offset)
78158619b14SKalle Valo 			continue;
78258619b14SKalle Valo 		if (((*stackptr & 0x0000F000) >> 12) != id)
78358619b14SKalle Valo 			continue;
78458619b14SKalle Valo 		return ((*stackptr & 0xFFFF0000) >> 16);
78558619b14SKalle Valo 	}
78658619b14SKalle Valo 	B43_WARN_ON(1);
78758619b14SKalle Valo 
78858619b14SKalle Valo 	return 0;
78958619b14SKalle Valo }
79058619b14SKalle Valo 
79158619b14SKalle Valo #define phy_stacksave(offset)					\
79258619b14SKalle Valo 	do {							\
79358619b14SKalle Valo 		_stack_save(stack, &stackidx, 0x1, (offset),	\
79458619b14SKalle Valo 			    b43_phy_read(dev, (offset)));	\
79558619b14SKalle Valo 	} while (0)
79658619b14SKalle Valo #define phy_stackrestore(offset)				\
79758619b14SKalle Valo 	do {							\
79858619b14SKalle Valo 		b43_phy_write(dev, (offset),		\
79958619b14SKalle Valo 				  _stack_restore(stack, 0x1,	\
80058619b14SKalle Valo 						 (offset)));	\
80158619b14SKalle Valo 	} while (0)
80258619b14SKalle Valo #define radio_stacksave(offset)						\
80358619b14SKalle Valo 	do {								\
80458619b14SKalle Valo 		_stack_save(stack, &stackidx, 0x2, (offset),		\
80558619b14SKalle Valo 			    b43_radio_read16(dev, (offset)));	\
80658619b14SKalle Valo 	} while (0)
80758619b14SKalle Valo #define radio_stackrestore(offset)					\
80858619b14SKalle Valo 	do {								\
80958619b14SKalle Valo 		b43_radio_write16(dev, (offset),			\
81058619b14SKalle Valo 				      _stack_restore(stack, 0x2,	\
81158619b14SKalle Valo 						     (offset)));	\
81258619b14SKalle Valo 	} while (0)
81358619b14SKalle Valo #define ofdmtab_stacksave(table, offset)			\
81458619b14SKalle Valo 	do {							\
81558619b14SKalle Valo 		_stack_save(stack, &stackidx, 0x3, (offset)|(table),	\
81658619b14SKalle Valo 			    b43_ofdmtab_read16(dev, (table), (offset)));	\
81758619b14SKalle Valo 	} while (0)
81858619b14SKalle Valo #define ofdmtab_stackrestore(table, offset)			\
81958619b14SKalle Valo 	do {							\
82058619b14SKalle Valo 		b43_ofdmtab_write16(dev, (table),	(offset),	\
82158619b14SKalle Valo 				  _stack_restore(stack, 0x3,	\
82258619b14SKalle Valo 						 (offset)|(table)));	\
82358619b14SKalle Valo 	} while (0)
82458619b14SKalle Valo 
82558619b14SKalle Valo static void
b43_radio_interference_mitigation_enable(struct b43_wldev * dev,int mode)82658619b14SKalle Valo b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
82758619b14SKalle Valo {
82858619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
82958619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
83058619b14SKalle Valo 	u16 tmp, flipped;
83158619b14SKalle Valo 	size_t stackidx = 0;
83258619b14SKalle Valo 	u32 *stack = gphy->interfstack;
83358619b14SKalle Valo 
83458619b14SKalle Valo 	switch (mode) {
83558619b14SKalle Valo 	case B43_INTERFMODE_NONWLAN:
83658619b14SKalle Valo 		if (phy->rev != 1) {
83758619b14SKalle Valo 			b43_phy_set(dev, 0x042B, 0x0800);
83858619b14SKalle Valo 			b43_phy_mask(dev, B43_PHY_G_CRS, ~0x4000);
83958619b14SKalle Valo 			break;
84058619b14SKalle Valo 		}
84158619b14SKalle Valo 		radio_stacksave(0x0078);
84258619b14SKalle Valo 		tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
84358619b14SKalle Valo 		B43_WARN_ON(tmp > 15);
84458619b14SKalle Valo 		flipped = bitrev4(tmp);
84558619b14SKalle Valo 		if (flipped < 10 && flipped >= 8)
84658619b14SKalle Valo 			flipped = 7;
84758619b14SKalle Valo 		else if (flipped >= 10)
84858619b14SKalle Valo 			flipped -= 3;
84958619b14SKalle Valo 		flipped = (bitrev4(flipped) << 1) | 0x0020;
85058619b14SKalle Valo 		b43_radio_write16(dev, 0x0078, flipped);
85158619b14SKalle Valo 
85258619b14SKalle Valo 		b43_calc_nrssi_threshold(dev);
85358619b14SKalle Valo 
85458619b14SKalle Valo 		phy_stacksave(0x0406);
85558619b14SKalle Valo 		b43_phy_write(dev, 0x0406, 0x7E28);
85658619b14SKalle Valo 
85758619b14SKalle Valo 		b43_phy_set(dev, 0x042B, 0x0800);
85858619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_RADIO_BITFIELD, 0x1000);
85958619b14SKalle Valo 
86058619b14SKalle Valo 		phy_stacksave(0x04A0);
86158619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A0, 0xC0C0, 0x0008);
86258619b14SKalle Valo 		phy_stacksave(0x04A1);
86358619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A1, 0xC0C0, 0x0605);
86458619b14SKalle Valo 		phy_stacksave(0x04A2);
86558619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A2, 0xC0C0, 0x0204);
86658619b14SKalle Valo 		phy_stacksave(0x04A8);
86758619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A8, 0xC0C0, 0x0803);
86858619b14SKalle Valo 		phy_stacksave(0x04AB);
86958619b14SKalle Valo 		b43_phy_maskset(dev, 0x04AB, 0xC0C0, 0x0605);
87058619b14SKalle Valo 
87158619b14SKalle Valo 		phy_stacksave(0x04A7);
87258619b14SKalle Valo 		b43_phy_write(dev, 0x04A7, 0x0002);
87358619b14SKalle Valo 		phy_stacksave(0x04A3);
87458619b14SKalle Valo 		b43_phy_write(dev, 0x04A3, 0x287A);
87558619b14SKalle Valo 		phy_stacksave(0x04A9);
87658619b14SKalle Valo 		b43_phy_write(dev, 0x04A9, 0x2027);
87758619b14SKalle Valo 		phy_stacksave(0x0493);
87858619b14SKalle Valo 		b43_phy_write(dev, 0x0493, 0x32F5);
87958619b14SKalle Valo 		phy_stacksave(0x04AA);
88058619b14SKalle Valo 		b43_phy_write(dev, 0x04AA, 0x2027);
88158619b14SKalle Valo 		phy_stacksave(0x04AC);
88258619b14SKalle Valo 		b43_phy_write(dev, 0x04AC, 0x32F5);
88358619b14SKalle Valo 		break;
88458619b14SKalle Valo 	case B43_INTERFMODE_MANUALWLAN:
88558619b14SKalle Valo 		if (b43_phy_read(dev, 0x0033) & 0x0800)
88658619b14SKalle Valo 			break;
88758619b14SKalle Valo 
88858619b14SKalle Valo 		gphy->aci_enable = true;
88958619b14SKalle Valo 
89058619b14SKalle Valo 		phy_stacksave(B43_PHY_RADIO_BITFIELD);
89158619b14SKalle Valo 		phy_stacksave(B43_PHY_G_CRS);
89258619b14SKalle Valo 		if (phy->rev < 2) {
89358619b14SKalle Valo 			phy_stacksave(0x0406);
89458619b14SKalle Valo 		} else {
89558619b14SKalle Valo 			phy_stacksave(0x04C0);
89658619b14SKalle Valo 			phy_stacksave(0x04C1);
89758619b14SKalle Valo 		}
89858619b14SKalle Valo 		phy_stacksave(0x0033);
89958619b14SKalle Valo 		phy_stacksave(0x04A7);
90058619b14SKalle Valo 		phy_stacksave(0x04A3);
90158619b14SKalle Valo 		phy_stacksave(0x04A9);
90258619b14SKalle Valo 		phy_stacksave(0x04AA);
90358619b14SKalle Valo 		phy_stacksave(0x04AC);
90458619b14SKalle Valo 		phy_stacksave(0x0493);
90558619b14SKalle Valo 		phy_stacksave(0x04A1);
90658619b14SKalle Valo 		phy_stacksave(0x04A0);
90758619b14SKalle Valo 		phy_stacksave(0x04A2);
90858619b14SKalle Valo 		phy_stacksave(0x048A);
90958619b14SKalle Valo 		phy_stacksave(0x04A8);
91058619b14SKalle Valo 		phy_stacksave(0x04AB);
91158619b14SKalle Valo 		if (phy->rev == 2) {
91258619b14SKalle Valo 			phy_stacksave(0x04AD);
91358619b14SKalle Valo 			phy_stacksave(0x04AE);
91458619b14SKalle Valo 		} else if (phy->rev >= 3) {
91558619b14SKalle Valo 			phy_stacksave(0x04AD);
91658619b14SKalle Valo 			phy_stacksave(0x0415);
91758619b14SKalle Valo 			phy_stacksave(0x0416);
91858619b14SKalle Valo 			phy_stacksave(0x0417);
91958619b14SKalle Valo 			ofdmtab_stacksave(0x1A00, 0x2);
92058619b14SKalle Valo 			ofdmtab_stacksave(0x1A00, 0x3);
92158619b14SKalle Valo 		}
92258619b14SKalle Valo 		phy_stacksave(0x042B);
92358619b14SKalle Valo 		phy_stacksave(0x048C);
92458619b14SKalle Valo 
92558619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_RADIO_BITFIELD, ~0x1000);
92658619b14SKalle Valo 		b43_phy_maskset(dev, B43_PHY_G_CRS, 0xFFFC, 0x0002);
92758619b14SKalle Valo 
92858619b14SKalle Valo 		b43_phy_write(dev, 0x0033, 0x0800);
92958619b14SKalle Valo 		b43_phy_write(dev, 0x04A3, 0x2027);
93058619b14SKalle Valo 		b43_phy_write(dev, 0x04A9, 0x1CA8);
93158619b14SKalle Valo 		b43_phy_write(dev, 0x0493, 0x287A);
93258619b14SKalle Valo 		b43_phy_write(dev, 0x04AA, 0x1CA8);
93358619b14SKalle Valo 		b43_phy_write(dev, 0x04AC, 0x287A);
93458619b14SKalle Valo 
93558619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A0, 0xFFC0, 0x001A);
93658619b14SKalle Valo 		b43_phy_write(dev, 0x04A7, 0x000D);
93758619b14SKalle Valo 
93858619b14SKalle Valo 		if (phy->rev < 2) {
93958619b14SKalle Valo 			b43_phy_write(dev, 0x0406, 0xFF0D);
94058619b14SKalle Valo 		} else if (phy->rev == 2) {
94158619b14SKalle Valo 			b43_phy_write(dev, 0x04C0, 0xFFFF);
94258619b14SKalle Valo 			b43_phy_write(dev, 0x04C1, 0x00A9);
94358619b14SKalle Valo 		} else {
94458619b14SKalle Valo 			b43_phy_write(dev, 0x04C0, 0x00C1);
94558619b14SKalle Valo 			b43_phy_write(dev, 0x04C1, 0x0059);
94658619b14SKalle Valo 		}
94758619b14SKalle Valo 
94858619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A1, 0xC0FF, 0x1800);
94958619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A1, 0xFFC0, 0x0015);
95058619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A8, 0xCFFF, 0x1000);
95158619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A8, 0xF0FF, 0x0A00);
95258619b14SKalle Valo 		b43_phy_maskset(dev, 0x04AB, 0xCFFF, 0x1000);
95358619b14SKalle Valo 		b43_phy_maskset(dev, 0x04AB, 0xF0FF, 0x0800);
95458619b14SKalle Valo 		b43_phy_maskset(dev, 0x04AB, 0xFFCF, 0x0010);
95558619b14SKalle Valo 		b43_phy_maskset(dev, 0x04AB, 0xFFF0, 0x0005);
95658619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A8, 0xFFCF, 0x0010);
95758619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A8, 0xFFF0, 0x0006);
95858619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A2, 0xF0FF, 0x0800);
95958619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A0, 0xF0FF, 0x0500);
96058619b14SKalle Valo 		b43_phy_maskset(dev, 0x04A2, 0xFFF0, 0x000B);
96158619b14SKalle Valo 
96258619b14SKalle Valo 		if (phy->rev >= 3) {
96358619b14SKalle Valo 			b43_phy_mask(dev, 0x048A, 0x7FFF);
96458619b14SKalle Valo 			b43_phy_maskset(dev, 0x0415, 0x8000, 0x36D8);
96558619b14SKalle Valo 			b43_phy_maskset(dev, 0x0416, 0x8000, 0x36D8);
96658619b14SKalle Valo 			b43_phy_maskset(dev, 0x0417, 0xFE00, 0x016D);
96758619b14SKalle Valo 		} else {
96858619b14SKalle Valo 			b43_phy_set(dev, 0x048A, 0x1000);
96958619b14SKalle Valo 			b43_phy_maskset(dev, 0x048A, 0x9FFF, 0x2000);
97058619b14SKalle Valo 			b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
97158619b14SKalle Valo 		}
97258619b14SKalle Valo 		if (phy->rev >= 2) {
97358619b14SKalle Valo 			b43_phy_set(dev, 0x042B, 0x0800);
97458619b14SKalle Valo 		}
97558619b14SKalle Valo 		b43_phy_maskset(dev, 0x048C, 0xF0FF, 0x0200);
97658619b14SKalle Valo 		if (phy->rev == 2) {
97758619b14SKalle Valo 			b43_phy_maskset(dev, 0x04AE, 0xFF00, 0x007F);
97858619b14SKalle Valo 			b43_phy_maskset(dev, 0x04AD, 0x00FF, 0x1300);
97958619b14SKalle Valo 		} else if (phy->rev >= 6) {
98058619b14SKalle Valo 			b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
98158619b14SKalle Valo 			b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
98258619b14SKalle Valo 			b43_phy_mask(dev, 0x04AD, 0x00FF);
98358619b14SKalle Valo 		}
98458619b14SKalle Valo 		b43_calc_nrssi_slope(dev);
98558619b14SKalle Valo 		break;
98658619b14SKalle Valo 	default:
98758619b14SKalle Valo 		B43_WARN_ON(1);
98858619b14SKalle Valo 	}
98958619b14SKalle Valo }
99058619b14SKalle Valo 
99158619b14SKalle Valo static void
b43_radio_interference_mitigation_disable(struct b43_wldev * dev,int mode)99258619b14SKalle Valo b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
99358619b14SKalle Valo {
99458619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
99558619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
99658619b14SKalle Valo 	u32 *stack = gphy->interfstack;
99758619b14SKalle Valo 
99858619b14SKalle Valo 	switch (mode) {
99958619b14SKalle Valo 	case B43_INTERFMODE_NONWLAN:
100058619b14SKalle Valo 		if (phy->rev != 1) {
100158619b14SKalle Valo 			b43_phy_mask(dev, 0x042B, ~0x0800);
100258619b14SKalle Valo 			b43_phy_set(dev, B43_PHY_G_CRS, 0x4000);
100358619b14SKalle Valo 			break;
100458619b14SKalle Valo 		}
100558619b14SKalle Valo 		radio_stackrestore(0x0078);
100658619b14SKalle Valo 		b43_calc_nrssi_threshold(dev);
100758619b14SKalle Valo 		phy_stackrestore(0x0406);
100858619b14SKalle Valo 		b43_phy_mask(dev, 0x042B, ~0x0800);
100958619b14SKalle Valo 		if (!dev->bad_frames_preempt) {
101058619b14SKalle Valo 			b43_phy_mask(dev, B43_PHY_RADIO_BITFIELD, ~(1 << 11));
101158619b14SKalle Valo 		}
101258619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_G_CRS, 0x4000);
101358619b14SKalle Valo 		phy_stackrestore(0x04A0);
101458619b14SKalle Valo 		phy_stackrestore(0x04A1);
101558619b14SKalle Valo 		phy_stackrestore(0x04A2);
101658619b14SKalle Valo 		phy_stackrestore(0x04A8);
101758619b14SKalle Valo 		phy_stackrestore(0x04AB);
101858619b14SKalle Valo 		phy_stackrestore(0x04A7);
101958619b14SKalle Valo 		phy_stackrestore(0x04A3);
102058619b14SKalle Valo 		phy_stackrestore(0x04A9);
102158619b14SKalle Valo 		phy_stackrestore(0x0493);
102258619b14SKalle Valo 		phy_stackrestore(0x04AA);
102358619b14SKalle Valo 		phy_stackrestore(0x04AC);
102458619b14SKalle Valo 		break;
102558619b14SKalle Valo 	case B43_INTERFMODE_MANUALWLAN:
102658619b14SKalle Valo 		if (!(b43_phy_read(dev, 0x0033) & 0x0800))
102758619b14SKalle Valo 			break;
102858619b14SKalle Valo 
102958619b14SKalle Valo 		gphy->aci_enable = false;
103058619b14SKalle Valo 
103158619b14SKalle Valo 		phy_stackrestore(B43_PHY_RADIO_BITFIELD);
103258619b14SKalle Valo 		phy_stackrestore(B43_PHY_G_CRS);
103358619b14SKalle Valo 		phy_stackrestore(0x0033);
103458619b14SKalle Valo 		phy_stackrestore(0x04A3);
103558619b14SKalle Valo 		phy_stackrestore(0x04A9);
103658619b14SKalle Valo 		phy_stackrestore(0x0493);
103758619b14SKalle Valo 		phy_stackrestore(0x04AA);
103858619b14SKalle Valo 		phy_stackrestore(0x04AC);
103958619b14SKalle Valo 		phy_stackrestore(0x04A0);
104058619b14SKalle Valo 		phy_stackrestore(0x04A7);
104158619b14SKalle Valo 		if (phy->rev >= 2) {
104258619b14SKalle Valo 			phy_stackrestore(0x04C0);
104358619b14SKalle Valo 			phy_stackrestore(0x04C1);
104458619b14SKalle Valo 		} else
104558619b14SKalle Valo 			phy_stackrestore(0x0406);
104658619b14SKalle Valo 		phy_stackrestore(0x04A1);
104758619b14SKalle Valo 		phy_stackrestore(0x04AB);
104858619b14SKalle Valo 		phy_stackrestore(0x04A8);
104958619b14SKalle Valo 		if (phy->rev == 2) {
105058619b14SKalle Valo 			phy_stackrestore(0x04AD);
105158619b14SKalle Valo 			phy_stackrestore(0x04AE);
105258619b14SKalle Valo 		} else if (phy->rev >= 3) {
105358619b14SKalle Valo 			phy_stackrestore(0x04AD);
105458619b14SKalle Valo 			phy_stackrestore(0x0415);
105558619b14SKalle Valo 			phy_stackrestore(0x0416);
105658619b14SKalle Valo 			phy_stackrestore(0x0417);
105758619b14SKalle Valo 			ofdmtab_stackrestore(0x1A00, 0x2);
105858619b14SKalle Valo 			ofdmtab_stackrestore(0x1A00, 0x3);
105958619b14SKalle Valo 		}
106058619b14SKalle Valo 		phy_stackrestore(0x04A2);
106158619b14SKalle Valo 		phy_stackrestore(0x048A);
106258619b14SKalle Valo 		phy_stackrestore(0x042B);
106358619b14SKalle Valo 		phy_stackrestore(0x048C);
106458619b14SKalle Valo 		b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW);
106558619b14SKalle Valo 		b43_calc_nrssi_slope(dev);
106658619b14SKalle Valo 		break;
106758619b14SKalle Valo 	default:
106858619b14SKalle Valo 		B43_WARN_ON(1);
106958619b14SKalle Valo 	}
107058619b14SKalle Valo }
107158619b14SKalle Valo 
107258619b14SKalle Valo #undef phy_stacksave
107358619b14SKalle Valo #undef phy_stackrestore
107458619b14SKalle Valo #undef radio_stacksave
107558619b14SKalle Valo #undef radio_stackrestore
107658619b14SKalle Valo #undef ofdmtab_stacksave
107758619b14SKalle Valo #undef ofdmtab_stackrestore
107858619b14SKalle Valo 
b43_radio_core_calibration_value(struct b43_wldev * dev)107958619b14SKalle Valo static u16 b43_radio_core_calibration_value(struct b43_wldev *dev)
108058619b14SKalle Valo {
108158619b14SKalle Valo 	u16 reg, index, ret;
108258619b14SKalle Valo 
108358619b14SKalle Valo 	static const u8 rcc_table[] = {
108458619b14SKalle Valo 		0x02, 0x03, 0x01, 0x0F,
108558619b14SKalle Valo 		0x06, 0x07, 0x05, 0x0F,
108658619b14SKalle Valo 		0x0A, 0x0B, 0x09, 0x0F,
108758619b14SKalle Valo 		0x0E, 0x0F, 0x0D, 0x0F,
108858619b14SKalle Valo 	};
108958619b14SKalle Valo 
109058619b14SKalle Valo 	reg = b43_radio_read16(dev, 0x60);
109158619b14SKalle Valo 	index = (reg & 0x001E) >> 1;
109258619b14SKalle Valo 	ret = rcc_table[index] << 1;
109358619b14SKalle Valo 	ret |= (reg & 0x0001);
109458619b14SKalle Valo 	ret |= 0x0020;
109558619b14SKalle Valo 
109658619b14SKalle Valo 	return ret;
109758619b14SKalle Valo }
109858619b14SKalle Valo 
109958619b14SKalle Valo #define LPD(L, P, D)	(((L) << 2) | ((P) << 1) | ((D) << 0))
radio2050_rfover_val(struct b43_wldev * dev,u16 phy_register,unsigned int lpd)110058619b14SKalle Valo static u16 radio2050_rfover_val(struct b43_wldev *dev,
110158619b14SKalle Valo 				u16 phy_register, unsigned int lpd)
110258619b14SKalle Valo {
110358619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
110458619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
110558619b14SKalle Valo 	struct ssb_sprom *sprom = dev->dev->bus_sprom;
110658619b14SKalle Valo 
110758619b14SKalle Valo 	if (!phy->gmode)
110858619b14SKalle Valo 		return 0;
110958619b14SKalle Valo 
111058619b14SKalle Valo 	if (has_loopback_gain(phy)) {
111158619b14SKalle Valo 		int max_lb_gain = gphy->max_lb_gain;
111258619b14SKalle Valo 		u16 extlna;
111358619b14SKalle Valo 		u16 i;
111458619b14SKalle Valo 
111558619b14SKalle Valo 		if (phy->radio_rev == 8)
111658619b14SKalle Valo 			max_lb_gain += 0x3E;
111758619b14SKalle Valo 		else
111858619b14SKalle Valo 			max_lb_gain += 0x26;
111958619b14SKalle Valo 		if (max_lb_gain >= 0x46) {
112058619b14SKalle Valo 			extlna = 0x3000;
112158619b14SKalle Valo 			max_lb_gain -= 0x46;
112258619b14SKalle Valo 		} else if (max_lb_gain >= 0x3A) {
112358619b14SKalle Valo 			extlna = 0x1000;
112458619b14SKalle Valo 			max_lb_gain -= 0x3A;
112558619b14SKalle Valo 		} else if (max_lb_gain >= 0x2E) {
112658619b14SKalle Valo 			extlna = 0x2000;
112758619b14SKalle Valo 			max_lb_gain -= 0x2E;
112858619b14SKalle Valo 		} else {
112958619b14SKalle Valo 			extlna = 0;
113058619b14SKalle Valo 			max_lb_gain -= 0x10;
113158619b14SKalle Valo 		}
113258619b14SKalle Valo 
113358619b14SKalle Valo 		for (i = 0; i < 16; i++) {
113458619b14SKalle Valo 			max_lb_gain -= (i * 6);
113558619b14SKalle Valo 			if (max_lb_gain < 6)
113658619b14SKalle Valo 				break;
113758619b14SKalle Valo 		}
113858619b14SKalle Valo 
113958619b14SKalle Valo 		if ((phy->rev < 7) ||
114058619b14SKalle Valo 		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
114158619b14SKalle Valo 			if (phy_register == B43_PHY_RFOVER) {
114258619b14SKalle Valo 				return 0x1B3;
114358619b14SKalle Valo 			} else if (phy_register == B43_PHY_RFOVERVAL) {
114458619b14SKalle Valo 				extlna |= (i << 8);
114558619b14SKalle Valo 				switch (lpd) {
114658619b14SKalle Valo 				case LPD(0, 1, 1):
114758619b14SKalle Valo 					return 0x0F92;
114858619b14SKalle Valo 				case LPD(0, 0, 1):
114958619b14SKalle Valo 				case LPD(1, 0, 1):
115058619b14SKalle Valo 					return (0x0092 | extlna);
115158619b14SKalle Valo 				case LPD(1, 0, 0):
115258619b14SKalle Valo 					return (0x0093 | extlna);
115358619b14SKalle Valo 				}
115458619b14SKalle Valo 				B43_WARN_ON(1);
115558619b14SKalle Valo 			}
115658619b14SKalle Valo 			B43_WARN_ON(1);
115758619b14SKalle Valo 		} else {
115858619b14SKalle Valo 			if (phy_register == B43_PHY_RFOVER) {
115958619b14SKalle Valo 				return 0x9B3;
116058619b14SKalle Valo 			} else if (phy_register == B43_PHY_RFOVERVAL) {
116158619b14SKalle Valo 				if (extlna)
116258619b14SKalle Valo 					extlna |= 0x8000;
116358619b14SKalle Valo 				extlna |= (i << 8);
116458619b14SKalle Valo 				switch (lpd) {
116558619b14SKalle Valo 				case LPD(0, 1, 1):
116658619b14SKalle Valo 					return 0x8F92;
116758619b14SKalle Valo 				case LPD(0, 0, 1):
116858619b14SKalle Valo 					return (0x8092 | extlna);
116958619b14SKalle Valo 				case LPD(1, 0, 1):
117058619b14SKalle Valo 					return (0x2092 | extlna);
117158619b14SKalle Valo 				case LPD(1, 0, 0):
117258619b14SKalle Valo 					return (0x2093 | extlna);
117358619b14SKalle Valo 				}
117458619b14SKalle Valo 				B43_WARN_ON(1);
117558619b14SKalle Valo 			}
117658619b14SKalle Valo 			B43_WARN_ON(1);
117758619b14SKalle Valo 		}
117858619b14SKalle Valo 	} else {
117958619b14SKalle Valo 		if ((phy->rev < 7) ||
118058619b14SKalle Valo 		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
118158619b14SKalle Valo 			if (phy_register == B43_PHY_RFOVER) {
118258619b14SKalle Valo 				return 0x1B3;
118358619b14SKalle Valo 			} else if (phy_register == B43_PHY_RFOVERVAL) {
118458619b14SKalle Valo 				switch (lpd) {
118558619b14SKalle Valo 				case LPD(0, 1, 1):
118658619b14SKalle Valo 					return 0x0FB2;
118758619b14SKalle Valo 				case LPD(0, 0, 1):
118858619b14SKalle Valo 					return 0x00B2;
118958619b14SKalle Valo 				case LPD(1, 0, 1):
119058619b14SKalle Valo 					return 0x30B2;
119158619b14SKalle Valo 				case LPD(1, 0, 0):
119258619b14SKalle Valo 					return 0x30B3;
119358619b14SKalle Valo 				}
119458619b14SKalle Valo 				B43_WARN_ON(1);
119558619b14SKalle Valo 			}
119658619b14SKalle Valo 			B43_WARN_ON(1);
119758619b14SKalle Valo 		} else {
119858619b14SKalle Valo 			if (phy_register == B43_PHY_RFOVER) {
119958619b14SKalle Valo 				return 0x9B3;
120058619b14SKalle Valo 			} else if (phy_register == B43_PHY_RFOVERVAL) {
120158619b14SKalle Valo 				switch (lpd) {
120258619b14SKalle Valo 				case LPD(0, 1, 1):
120358619b14SKalle Valo 					return 0x8FB2;
120458619b14SKalle Valo 				case LPD(0, 0, 1):
120558619b14SKalle Valo 					return 0x80B2;
120658619b14SKalle Valo 				case LPD(1, 0, 1):
120758619b14SKalle Valo 					return 0x20B2;
120858619b14SKalle Valo 				case LPD(1, 0, 0):
120958619b14SKalle Valo 					return 0x20B3;
121058619b14SKalle Valo 				}
121158619b14SKalle Valo 				B43_WARN_ON(1);
121258619b14SKalle Valo 			}
121358619b14SKalle Valo 			B43_WARN_ON(1);
121458619b14SKalle Valo 		}
121558619b14SKalle Valo 	}
121658619b14SKalle Valo 	return 0;
121758619b14SKalle Valo }
121858619b14SKalle Valo 
121958619b14SKalle Valo struct init2050_saved_values {
122058619b14SKalle Valo 	/* Core registers */
122158619b14SKalle Valo 	u16 reg_3EC;
122258619b14SKalle Valo 	u16 reg_3E6;
122358619b14SKalle Valo 	u16 reg_3F4;
122458619b14SKalle Valo 	/* Radio registers */
122558619b14SKalle Valo 	u16 radio_43;
122658619b14SKalle Valo 	u16 radio_51;
122758619b14SKalle Valo 	u16 radio_52;
122858619b14SKalle Valo 	/* PHY registers */
122958619b14SKalle Valo 	u16 phy_pgactl;
123058619b14SKalle Valo 	u16 phy_cck_5A;
123158619b14SKalle Valo 	u16 phy_cck_59;
123258619b14SKalle Valo 	u16 phy_cck_58;
123358619b14SKalle Valo 	u16 phy_cck_30;
123458619b14SKalle Valo 	u16 phy_rfover;
123558619b14SKalle Valo 	u16 phy_rfoverval;
123658619b14SKalle Valo 	u16 phy_analogover;
123758619b14SKalle Valo 	u16 phy_analogoverval;
123858619b14SKalle Valo 	u16 phy_crs0;
123958619b14SKalle Valo 	u16 phy_classctl;
124058619b14SKalle Valo 	u16 phy_lo_mask;
124158619b14SKalle Valo 	u16 phy_lo_ctl;
124258619b14SKalle Valo 	u16 phy_syncctl;
124358619b14SKalle Valo };
124458619b14SKalle Valo 
b43_radio_init2050(struct b43_wldev * dev)124558619b14SKalle Valo static u16 b43_radio_init2050(struct b43_wldev *dev)
124658619b14SKalle Valo {
124758619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
124858619b14SKalle Valo 	struct init2050_saved_values sav;
124958619b14SKalle Valo 	u16 rcc;
125058619b14SKalle Valo 	u16 radio78;
125158619b14SKalle Valo 	u16 ret;
125258619b14SKalle Valo 	u16 i, j;
125358619b14SKalle Valo 	u32 tmp1 = 0, tmp2 = 0;
125458619b14SKalle Valo 
125558619b14SKalle Valo 	memset(&sav, 0, sizeof(sav));	/* get rid of "may be used uninitialized..." */
125658619b14SKalle Valo 
125758619b14SKalle Valo 	sav.radio_43 = b43_radio_read16(dev, 0x43);
125858619b14SKalle Valo 	sav.radio_51 = b43_radio_read16(dev, 0x51);
125958619b14SKalle Valo 	sav.radio_52 = b43_radio_read16(dev, 0x52);
126058619b14SKalle Valo 	sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
126158619b14SKalle Valo 	sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
126258619b14SKalle Valo 	sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
126358619b14SKalle Valo 	sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
126458619b14SKalle Valo 
126558619b14SKalle Valo 	if (phy->type == B43_PHYTYPE_B) {
126658619b14SKalle Valo 		sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
126758619b14SKalle Valo 		sav.reg_3EC = b43_read16(dev, 0x3EC);
126858619b14SKalle Valo 
126958619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
127058619b14SKalle Valo 		b43_write16(dev, 0x3EC, 0x3F3F);
127158619b14SKalle Valo 	} else if (phy->gmode || phy->rev >= 2) {
127258619b14SKalle Valo 		sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
127358619b14SKalle Valo 		sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
127458619b14SKalle Valo 		sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
127558619b14SKalle Valo 		sav.phy_analogoverval =
127658619b14SKalle Valo 		    b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
127758619b14SKalle Valo 		sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
127858619b14SKalle Valo 		sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
127958619b14SKalle Valo 
128058619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003);
128158619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC);
128258619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF);
128358619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC);
128458619b14SKalle Valo 		if (has_loopback_gain(phy)) {
128558619b14SKalle Valo 			sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
128658619b14SKalle Valo 			sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
128758619b14SKalle Valo 
128858619b14SKalle Valo 			if (phy->rev >= 3)
128958619b14SKalle Valo 				b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
129058619b14SKalle Valo 			else
129158619b14SKalle Valo 				b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
129258619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_LO_CTL, 0);
129358619b14SKalle Valo 		}
129458619b14SKalle Valo 
129558619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVERVAL,
129658619b14SKalle Valo 			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
129758619b14SKalle Valo 						   LPD(0, 1, 1)));
129858619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVER,
129958619b14SKalle Valo 			      radio2050_rfover_val(dev, B43_PHY_RFOVER, 0));
130058619b14SKalle Valo 	}
130158619b14SKalle Valo 	b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
130258619b14SKalle Valo 
130358619b14SKalle Valo 	sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
130458619b14SKalle Valo 	b43_phy_mask(dev, B43_PHY_SYNCCTL, 0xFF7F);
130558619b14SKalle Valo 	sav.reg_3E6 = b43_read16(dev, 0x3E6);
130658619b14SKalle Valo 	sav.reg_3F4 = b43_read16(dev, 0x3F4);
130758619b14SKalle Valo 
130858619b14SKalle Valo 	if (phy->analog == 0) {
130958619b14SKalle Valo 		b43_write16(dev, 0x03E6, 0x0122);
131058619b14SKalle Valo 	} else {
131158619b14SKalle Valo 		if (phy->analog >= 2) {
131258619b14SKalle Valo 			b43_phy_maskset(dev, B43_PHY_CCK(0x03), 0xFFBF, 0x40);
131358619b14SKalle Valo 		}
131458619b14SKalle Valo 		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
131558619b14SKalle Valo 			    (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
131658619b14SKalle Valo 	}
131758619b14SKalle Valo 
131858619b14SKalle Valo 	rcc = b43_radio_core_calibration_value(dev);
131958619b14SKalle Valo 
132058619b14SKalle Valo 	if (phy->type == B43_PHYTYPE_B)
132158619b14SKalle Valo 		b43_radio_write16(dev, 0x78, 0x26);
132258619b14SKalle Valo 	if (phy->gmode || phy->rev >= 2) {
132358619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVERVAL,
132458619b14SKalle Valo 			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
132558619b14SKalle Valo 						   LPD(0, 1, 1)));
132658619b14SKalle Valo 	}
132758619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
132858619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
132958619b14SKalle Valo 	if (phy->gmode || phy->rev >= 2) {
133058619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVERVAL,
133158619b14SKalle Valo 			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
133258619b14SKalle Valo 						   LPD(0, 0, 1)));
133358619b14SKalle Valo 	}
133458619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
133558619b14SKalle Valo 	b43_radio_set(dev, 0x51, 0x0004);
133658619b14SKalle Valo 	if (phy->radio_rev == 8) {
133758619b14SKalle Valo 		b43_radio_write16(dev, 0x43, 0x1F);
133858619b14SKalle Valo 	} else {
133958619b14SKalle Valo 		b43_radio_write16(dev, 0x52, 0);
134058619b14SKalle Valo 		b43_radio_maskset(dev, 0x43, 0xFFF0, 0x0009);
134158619b14SKalle Valo 	}
134258619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
134358619b14SKalle Valo 
134458619b14SKalle Valo 	for (i = 0; i < 16; i++) {
134558619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
134658619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
134758619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
134858619b14SKalle Valo 		if (phy->gmode || phy->rev >= 2) {
134958619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
135058619b14SKalle Valo 				      radio2050_rfover_val(dev,
135158619b14SKalle Valo 							   B43_PHY_RFOVERVAL,
135258619b14SKalle Valo 							   LPD(1, 0, 1)));
135358619b14SKalle Valo 		}
135458619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
135558619b14SKalle Valo 		udelay(10);
135658619b14SKalle Valo 		if (phy->gmode || phy->rev >= 2) {
135758619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
135858619b14SKalle Valo 				      radio2050_rfover_val(dev,
135958619b14SKalle Valo 							   B43_PHY_RFOVERVAL,
136058619b14SKalle Valo 							   LPD(1, 0, 1)));
136158619b14SKalle Valo 		}
136258619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
136358619b14SKalle Valo 		udelay(10);
136458619b14SKalle Valo 		if (phy->gmode || phy->rev >= 2) {
136558619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
136658619b14SKalle Valo 				      radio2050_rfover_val(dev,
136758619b14SKalle Valo 							   B43_PHY_RFOVERVAL,
136858619b14SKalle Valo 							   LPD(1, 0, 0)));
136958619b14SKalle Valo 		}
137058619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
137158619b14SKalle Valo 		udelay(20);
137258619b14SKalle Valo 		tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
137358619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
137458619b14SKalle Valo 		if (phy->gmode || phy->rev >= 2) {
137558619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
137658619b14SKalle Valo 				      radio2050_rfover_val(dev,
137758619b14SKalle Valo 							   B43_PHY_RFOVERVAL,
137858619b14SKalle Valo 							   LPD(1, 0, 1)));
137958619b14SKalle Valo 		}
138058619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
138158619b14SKalle Valo 	}
138258619b14SKalle Valo 	udelay(10);
138358619b14SKalle Valo 
138458619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
138558619b14SKalle Valo 	tmp1++;
138658619b14SKalle Valo 	tmp1 >>= 9;
138758619b14SKalle Valo 
138858619b14SKalle Valo 	for (i = 0; i < 16; i++) {
138958619b14SKalle Valo 		radio78 = (bitrev4(i) << 1) | 0x0020;
139058619b14SKalle Valo 		b43_radio_write16(dev, 0x78, radio78);
139158619b14SKalle Valo 		udelay(10);
139258619b14SKalle Valo 		for (j = 0; j < 16; j++) {
139358619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
139458619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
139558619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
139658619b14SKalle Valo 			if (phy->gmode || phy->rev >= 2) {
139758619b14SKalle Valo 				b43_phy_write(dev, B43_PHY_RFOVERVAL,
139858619b14SKalle Valo 					      radio2050_rfover_val(dev,
139958619b14SKalle Valo 								   B43_PHY_RFOVERVAL,
140058619b14SKalle Valo 								   LPD(1, 0,
140158619b14SKalle Valo 								       1)));
140258619b14SKalle Valo 			}
140358619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
140458619b14SKalle Valo 			udelay(10);
140558619b14SKalle Valo 			if (phy->gmode || phy->rev >= 2) {
140658619b14SKalle Valo 				b43_phy_write(dev, B43_PHY_RFOVERVAL,
140758619b14SKalle Valo 					      radio2050_rfover_val(dev,
140858619b14SKalle Valo 								   B43_PHY_RFOVERVAL,
140958619b14SKalle Valo 								   LPD(1, 0,
141058619b14SKalle Valo 								       1)));
141158619b14SKalle Valo 			}
141258619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
141358619b14SKalle Valo 			udelay(10);
141458619b14SKalle Valo 			if (phy->gmode || phy->rev >= 2) {
141558619b14SKalle Valo 				b43_phy_write(dev, B43_PHY_RFOVERVAL,
141658619b14SKalle Valo 					      radio2050_rfover_val(dev,
141758619b14SKalle Valo 								   B43_PHY_RFOVERVAL,
141858619b14SKalle Valo 								   LPD(1, 0,
141958619b14SKalle Valo 								       0)));
142058619b14SKalle Valo 			}
142158619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
142258619b14SKalle Valo 			udelay(10);
142358619b14SKalle Valo 			tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
142458619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
142558619b14SKalle Valo 			if (phy->gmode || phy->rev >= 2) {
142658619b14SKalle Valo 				b43_phy_write(dev, B43_PHY_RFOVERVAL,
142758619b14SKalle Valo 					      radio2050_rfover_val(dev,
142858619b14SKalle Valo 								   B43_PHY_RFOVERVAL,
142958619b14SKalle Valo 								   LPD(1, 0,
143058619b14SKalle Valo 								       1)));
143158619b14SKalle Valo 			}
143258619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
143358619b14SKalle Valo 		}
143458619b14SKalle Valo 		tmp2++;
143558619b14SKalle Valo 		tmp2 >>= 8;
143658619b14SKalle Valo 		if (tmp1 < tmp2)
143758619b14SKalle Valo 			break;
143858619b14SKalle Valo 	}
143958619b14SKalle Valo 
144058619b14SKalle Valo 	/* Restore the registers */
144158619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl);
144258619b14SKalle Valo 	b43_radio_write16(dev, 0x51, sav.radio_51);
144358619b14SKalle Valo 	b43_radio_write16(dev, 0x52, sav.radio_52);
144458619b14SKalle Valo 	b43_radio_write16(dev, 0x43, sav.radio_43);
144558619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
144658619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
144758619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
144858619b14SKalle Valo 	b43_write16(dev, 0x3E6, sav.reg_3E6);
144958619b14SKalle Valo 	if (phy->analog != 0)
145058619b14SKalle Valo 		b43_write16(dev, 0x3F4, sav.reg_3F4);
145158619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
145258619b14SKalle Valo 	b43_synth_pu_workaround(dev, phy->channel);
145358619b14SKalle Valo 	if (phy->type == B43_PHYTYPE_B) {
145458619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
145558619b14SKalle Valo 		b43_write16(dev, 0x3EC, sav.reg_3EC);
145658619b14SKalle Valo 	} else if (phy->gmode) {
145758619b14SKalle Valo 		b43_write16(dev, B43_MMIO_PHY_RADIO,
145858619b14SKalle Valo 			    b43_read16(dev, B43_MMIO_PHY_RADIO)
145958619b14SKalle Valo 			    & 0x7FFF);
146058619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover);
146158619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval);
146258619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover);
146358619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
146458619b14SKalle Valo 			      sav.phy_analogoverval);
146558619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0);
146658619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl);
146758619b14SKalle Valo 		if (has_loopback_gain(phy)) {
146858619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask);
146958619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl);
147058619b14SKalle Valo 		}
147158619b14SKalle Valo 	}
147258619b14SKalle Valo 	if (i > 15)
147358619b14SKalle Valo 		ret = radio78;
147458619b14SKalle Valo 	else
147558619b14SKalle Valo 		ret = rcc;
147658619b14SKalle Valo 
147758619b14SKalle Valo 	return ret;
147858619b14SKalle Valo }
147958619b14SKalle Valo 
b43_phy_initb5(struct b43_wldev * dev)148058619b14SKalle Valo static void b43_phy_initb5(struct b43_wldev *dev)
148158619b14SKalle Valo {
148258619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
148358619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
148458619b14SKalle Valo 	u16 offset, value;
148558619b14SKalle Valo 	u8 old_channel;
148658619b14SKalle Valo 
148758619b14SKalle Valo 	if (phy->analog == 1) {
148858619b14SKalle Valo 		b43_radio_set(dev, 0x007A, 0x0050);
148958619b14SKalle Valo 	}
149058619b14SKalle Valo 	if ((dev->dev->board_vendor != SSB_BOARDVENDOR_BCM) &&
149158619b14SKalle Valo 	    (dev->dev->board_type != SSB_BOARD_BU4306)) {
149258619b14SKalle Valo 		value = 0x2120;
149358619b14SKalle Valo 		for (offset = 0x00A8; offset < 0x00C7; offset++) {
149458619b14SKalle Valo 			b43_phy_write(dev, offset, value);
149558619b14SKalle Valo 			value += 0x202;
149658619b14SKalle Valo 		}
149758619b14SKalle Valo 	}
149858619b14SKalle Valo 	b43_phy_maskset(dev, 0x0035, 0xF0FF, 0x0700);
149958619b14SKalle Valo 	if (phy->radio_ver == 0x2050)
150058619b14SKalle Valo 		b43_phy_write(dev, 0x0038, 0x0667);
150158619b14SKalle Valo 
150258619b14SKalle Valo 	if (phy->gmode || phy->rev >= 2) {
150358619b14SKalle Valo 		if (phy->radio_ver == 0x2050) {
150458619b14SKalle Valo 			b43_radio_set(dev, 0x007A, 0x0020);
150558619b14SKalle Valo 			b43_radio_set(dev, 0x0051, 0x0004);
150658619b14SKalle Valo 		}
150758619b14SKalle Valo 		b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
150858619b14SKalle Valo 
150958619b14SKalle Valo 		b43_phy_set(dev, 0x0802, 0x0100);
151058619b14SKalle Valo 		b43_phy_set(dev, 0x042B, 0x2000);
151158619b14SKalle Valo 
151258619b14SKalle Valo 		b43_phy_write(dev, 0x001C, 0x186A);
151358619b14SKalle Valo 
151458619b14SKalle Valo 		b43_phy_maskset(dev, 0x0013, 0x00FF, 0x1900);
151558619b14SKalle Valo 		b43_phy_maskset(dev, 0x0035, 0xFFC0, 0x0064);
151658619b14SKalle Valo 		b43_phy_maskset(dev, 0x005D, 0xFF80, 0x000A);
151758619b14SKalle Valo 	}
151858619b14SKalle Valo 
151958619b14SKalle Valo 	if (dev->bad_frames_preempt) {
152058619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_RADIO_BITFIELD, (1 << 11));
152158619b14SKalle Valo 	}
152258619b14SKalle Valo 
152358619b14SKalle Valo 	if (phy->analog == 1) {
152458619b14SKalle Valo 		b43_phy_write(dev, 0x0026, 0xCE00);
152558619b14SKalle Valo 		b43_phy_write(dev, 0x0021, 0x3763);
152658619b14SKalle Valo 		b43_phy_write(dev, 0x0022, 0x1BC3);
152758619b14SKalle Valo 		b43_phy_write(dev, 0x0023, 0x06F9);
152858619b14SKalle Valo 		b43_phy_write(dev, 0x0024, 0x037E);
152958619b14SKalle Valo 	} else
153058619b14SKalle Valo 		b43_phy_write(dev, 0x0026, 0xCC00);
153158619b14SKalle Valo 	b43_phy_write(dev, 0x0030, 0x00C6);
153258619b14SKalle Valo 	b43_write16(dev, 0x03EC, 0x3F22);
153358619b14SKalle Valo 
153458619b14SKalle Valo 	if (phy->analog == 1)
153558619b14SKalle Valo 		b43_phy_write(dev, 0x0020, 0x3E1C);
153658619b14SKalle Valo 	else
153758619b14SKalle Valo 		b43_phy_write(dev, 0x0020, 0x301C);
153858619b14SKalle Valo 
153958619b14SKalle Valo 	if (phy->analog == 0)
154058619b14SKalle Valo 		b43_write16(dev, 0x03E4, 0x3000);
154158619b14SKalle Valo 
154258619b14SKalle Valo 	old_channel = phy->channel;
154358619b14SKalle Valo 	/* Force to channel 7, even if not supported. */
154458619b14SKalle Valo 	b43_gphy_channel_switch(dev, 7, 0);
154558619b14SKalle Valo 
154658619b14SKalle Valo 	if (phy->radio_ver != 0x2050) {
154758619b14SKalle Valo 		b43_radio_write16(dev, 0x0075, 0x0080);
154858619b14SKalle Valo 		b43_radio_write16(dev, 0x0079, 0x0081);
154958619b14SKalle Valo 	}
155058619b14SKalle Valo 
155158619b14SKalle Valo 	b43_radio_write16(dev, 0x0050, 0x0020);
155258619b14SKalle Valo 	b43_radio_write16(dev, 0x0050, 0x0023);
155358619b14SKalle Valo 
155458619b14SKalle Valo 	if (phy->radio_ver == 0x2050) {
155558619b14SKalle Valo 		b43_radio_write16(dev, 0x0050, 0x0020);
155658619b14SKalle Valo 		b43_radio_write16(dev, 0x005A, 0x0070);
155758619b14SKalle Valo 	}
155858619b14SKalle Valo 
155958619b14SKalle Valo 	b43_radio_write16(dev, 0x005B, 0x007B);
156058619b14SKalle Valo 	b43_radio_write16(dev, 0x005C, 0x00B0);
156158619b14SKalle Valo 
156258619b14SKalle Valo 	b43_radio_set(dev, 0x007A, 0x0007);
156358619b14SKalle Valo 
156458619b14SKalle Valo 	b43_gphy_channel_switch(dev, old_channel, 0);
156558619b14SKalle Valo 
156658619b14SKalle Valo 	b43_phy_write(dev, 0x0014, 0x0080);
156758619b14SKalle Valo 	b43_phy_write(dev, 0x0032, 0x00CA);
156858619b14SKalle Valo 	b43_phy_write(dev, 0x002A, 0x88A3);
156958619b14SKalle Valo 
157058619b14SKalle Valo 	b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control);
157158619b14SKalle Valo 
157258619b14SKalle Valo 	if (phy->radio_ver == 0x2050)
157358619b14SKalle Valo 		b43_radio_write16(dev, 0x005D, 0x000D);
157458619b14SKalle Valo 
157558619b14SKalle Valo 	b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
157658619b14SKalle Valo }
157758619b14SKalle Valo 
15782d96c1edSAlexander A. Klimov /* https://bcm-v4.sipsolutions.net/802.11/PHY/Init/B6 */
b43_phy_initb6(struct b43_wldev * dev)157958619b14SKalle Valo static void b43_phy_initb6(struct b43_wldev *dev)
158058619b14SKalle Valo {
158158619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
158258619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
158358619b14SKalle Valo 	u16 offset, val;
158458619b14SKalle Valo 	u8 old_channel;
158558619b14SKalle Valo 
158658619b14SKalle Valo 	b43_phy_write(dev, 0x003E, 0x817A);
158758619b14SKalle Valo 	b43_radio_write16(dev, 0x007A,
158858619b14SKalle Valo 			  (b43_radio_read16(dev, 0x007A) | 0x0058));
158958619b14SKalle Valo 	if (phy->radio_rev == 4 || phy->radio_rev == 5) {
159058619b14SKalle Valo 		b43_radio_write16(dev, 0x51, 0x37);
159158619b14SKalle Valo 		b43_radio_write16(dev, 0x52, 0x70);
159258619b14SKalle Valo 		b43_radio_write16(dev, 0x53, 0xB3);
159358619b14SKalle Valo 		b43_radio_write16(dev, 0x54, 0x9B);
159458619b14SKalle Valo 		b43_radio_write16(dev, 0x5A, 0x88);
159558619b14SKalle Valo 		b43_radio_write16(dev, 0x5B, 0x88);
159658619b14SKalle Valo 		b43_radio_write16(dev, 0x5D, 0x88);
159758619b14SKalle Valo 		b43_radio_write16(dev, 0x5E, 0x88);
159858619b14SKalle Valo 		b43_radio_write16(dev, 0x7D, 0x88);
159958619b14SKalle Valo 		b43_hf_write(dev, b43_hf_read(dev)
160058619b14SKalle Valo 			     | B43_HF_TSSIRPSMW);
160158619b14SKalle Valo 	}
160258619b14SKalle Valo 	B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7);	/* We had code for these revs here... */
160358619b14SKalle Valo 	if (phy->radio_rev == 8) {
160458619b14SKalle Valo 		b43_radio_write16(dev, 0x51, 0);
160558619b14SKalle Valo 		b43_radio_write16(dev, 0x52, 0x40);
160658619b14SKalle Valo 		b43_radio_write16(dev, 0x53, 0xB7);
160758619b14SKalle Valo 		b43_radio_write16(dev, 0x54, 0x98);
160858619b14SKalle Valo 		b43_radio_write16(dev, 0x5A, 0x88);
160958619b14SKalle Valo 		b43_radio_write16(dev, 0x5B, 0x6B);
161058619b14SKalle Valo 		b43_radio_write16(dev, 0x5C, 0x0F);
161158619b14SKalle Valo 		if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_ALTIQ) {
161258619b14SKalle Valo 			b43_radio_write16(dev, 0x5D, 0xFA);
161358619b14SKalle Valo 			b43_radio_write16(dev, 0x5E, 0xD8);
161458619b14SKalle Valo 		} else {
161558619b14SKalle Valo 			b43_radio_write16(dev, 0x5D, 0xF5);
161658619b14SKalle Valo 			b43_radio_write16(dev, 0x5E, 0xB8);
161758619b14SKalle Valo 		}
161858619b14SKalle Valo 		b43_radio_write16(dev, 0x0073, 0x0003);
161958619b14SKalle Valo 		b43_radio_write16(dev, 0x007D, 0x00A8);
162058619b14SKalle Valo 		b43_radio_write16(dev, 0x007C, 0x0001);
162158619b14SKalle Valo 		b43_radio_write16(dev, 0x007E, 0x0008);
162258619b14SKalle Valo 	}
162358619b14SKalle Valo 	val = 0x1E1F;
162458619b14SKalle Valo 	for (offset = 0x0088; offset < 0x0098; offset++) {
162558619b14SKalle Valo 		b43_phy_write(dev, offset, val);
162658619b14SKalle Valo 		val -= 0x0202;
162758619b14SKalle Valo 	}
162858619b14SKalle Valo 	val = 0x3E3F;
162958619b14SKalle Valo 	for (offset = 0x0098; offset < 0x00A8; offset++) {
163058619b14SKalle Valo 		b43_phy_write(dev, offset, val);
163158619b14SKalle Valo 		val -= 0x0202;
163258619b14SKalle Valo 	}
163358619b14SKalle Valo 	val = 0x2120;
163458619b14SKalle Valo 	for (offset = 0x00A8; offset < 0x00C8; offset++) {
163558619b14SKalle Valo 		b43_phy_write(dev, offset, (val & 0x3F3F));
163658619b14SKalle Valo 		val += 0x0202;
163758619b14SKalle Valo 	}
163858619b14SKalle Valo 	if (phy->type == B43_PHYTYPE_G) {
163958619b14SKalle Valo 		b43_radio_set(dev, 0x007A, 0x0020);
164058619b14SKalle Valo 		b43_radio_set(dev, 0x0051, 0x0004);
164158619b14SKalle Valo 		b43_phy_set(dev, 0x0802, 0x0100);
164258619b14SKalle Valo 		b43_phy_set(dev, 0x042B, 0x2000);
164358619b14SKalle Valo 		b43_phy_write(dev, 0x5B, 0);
164458619b14SKalle Valo 		b43_phy_write(dev, 0x5C, 0);
164558619b14SKalle Valo 	}
164658619b14SKalle Valo 
164758619b14SKalle Valo 	old_channel = phy->channel;
164858619b14SKalle Valo 	if (old_channel >= 8)
164958619b14SKalle Valo 		b43_gphy_channel_switch(dev, 1, 0);
165058619b14SKalle Valo 	else
165158619b14SKalle Valo 		b43_gphy_channel_switch(dev, 13, 0);
165258619b14SKalle Valo 
165358619b14SKalle Valo 	b43_radio_write16(dev, 0x0050, 0x0020);
165458619b14SKalle Valo 	b43_radio_write16(dev, 0x0050, 0x0023);
165558619b14SKalle Valo 	udelay(40);
165658619b14SKalle Valo 	if (phy->radio_rev < 6 || phy->radio_rev == 8) {
165758619b14SKalle Valo 		b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C)
165858619b14SKalle Valo 					      | 0x0002));
165958619b14SKalle Valo 		b43_radio_write16(dev, 0x50, 0x20);
166058619b14SKalle Valo 	}
166158619b14SKalle Valo 	if (phy->radio_rev <= 2) {
166258619b14SKalle Valo 		b43_radio_write16(dev, 0x50, 0x20);
166358619b14SKalle Valo 		b43_radio_write16(dev, 0x5A, 0x70);
166458619b14SKalle Valo 		b43_radio_write16(dev, 0x5B, 0x7B);
166558619b14SKalle Valo 		b43_radio_write16(dev, 0x5C, 0xB0);
166658619b14SKalle Valo 	}
166758619b14SKalle Valo 	b43_radio_maskset(dev, 0x007A, 0x00F8, 0x0007);
166858619b14SKalle Valo 
166958619b14SKalle Valo 	b43_gphy_channel_switch(dev, old_channel, 0);
167058619b14SKalle Valo 
167158619b14SKalle Valo 	b43_phy_write(dev, 0x0014, 0x0200);
167258619b14SKalle Valo 	if (phy->radio_rev >= 6)
167358619b14SKalle Valo 		b43_phy_write(dev, 0x2A, 0x88C2);
167458619b14SKalle Valo 	else
167558619b14SKalle Valo 		b43_phy_write(dev, 0x2A, 0x8AC0);
167658619b14SKalle Valo 	b43_phy_write(dev, 0x0038, 0x0668);
167758619b14SKalle Valo 	b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control);
167858619b14SKalle Valo 	if (phy->radio_rev == 4 || phy->radio_rev == 5)
167958619b14SKalle Valo 		b43_phy_maskset(dev, 0x5D, 0xFF80, 0x0003);
168058619b14SKalle Valo 	if (phy->radio_rev <= 2)
168158619b14SKalle Valo 		b43_radio_write16(dev, 0x005D, 0x000D);
168258619b14SKalle Valo 
168358619b14SKalle Valo 	if (phy->analog == 4) {
168458619b14SKalle Valo 		b43_write16(dev, 0x3E4, 9);
168558619b14SKalle Valo 		b43_phy_mask(dev, 0x61, 0x0FFF);
168658619b14SKalle Valo 	} else {
168758619b14SKalle Valo 		b43_phy_maskset(dev, 0x0002, 0xFFC0, 0x0004);
168858619b14SKalle Valo 	}
168958619b14SKalle Valo 	if (phy->type == B43_PHYTYPE_B)
169058619b14SKalle Valo 		B43_WARN_ON(1);
169158619b14SKalle Valo 	else if (phy->type == B43_PHYTYPE_G)
169258619b14SKalle Valo 		b43_write16(dev, 0x03E6, 0x0);
169358619b14SKalle Valo }
169458619b14SKalle Valo 
b43_calc_loopback_gain(struct b43_wldev * dev)169558619b14SKalle Valo static void b43_calc_loopback_gain(struct b43_wldev *dev)
169658619b14SKalle Valo {
169758619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
169858619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
169958619b14SKalle Valo 	u16 backup_phy[16] = { 0 };
170058619b14SKalle Valo 	u16 backup_radio[3];
170158619b14SKalle Valo 	u16 backup_bband;
170258619b14SKalle Valo 	u16 i, j, loop_i_max;
170358619b14SKalle Valo 	u16 trsw_rx;
170458619b14SKalle Valo 	u16 loop1_outer_done, loop1_inner_done;
170558619b14SKalle Valo 
170658619b14SKalle Valo 	backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0);
170758619b14SKalle Valo 	backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
170858619b14SKalle Valo 	backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER);
170958619b14SKalle Valo 	backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL);
171058619b14SKalle Valo 	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
171158619b14SKalle Valo 		backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
171258619b14SKalle Valo 		backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
171358619b14SKalle Valo 	}
171458619b14SKalle Valo 	backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
171558619b14SKalle Valo 	backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
171658619b14SKalle Valo 	backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
171758619b14SKalle Valo 	backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
171858619b14SKalle Valo 	backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
171958619b14SKalle Valo 	backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
172058619b14SKalle Valo 	backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
172158619b14SKalle Valo 	backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
172258619b14SKalle Valo 	backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
172358619b14SKalle Valo 	backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
172458619b14SKalle Valo 	backup_bband = gphy->bbatt.att;
172558619b14SKalle Valo 	backup_radio[0] = b43_radio_read16(dev, 0x52);
172658619b14SKalle Valo 	backup_radio[1] = b43_radio_read16(dev, 0x43);
172758619b14SKalle Valo 	backup_radio[2] = b43_radio_read16(dev, 0x7A);
172858619b14SKalle Valo 
172958619b14SKalle Valo 	b43_phy_mask(dev, B43_PHY_CRS0, 0x3FFF);
173058619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_CCKBBANDCFG, 0x8000);
173158619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_RFOVER, 0x0002);
173258619b14SKalle Valo 	b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xFFFD);
173358619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_RFOVER, 0x0001);
173458619b14SKalle Valo 	b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xFFFE);
173558619b14SKalle Valo 	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
173658619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0001);
173758619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFE);
173858619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0002);
173958619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFD);
174058619b14SKalle Valo 	}
174158619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_RFOVER, 0x000C);
174258619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x000C);
174358619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_RFOVER, 0x0030);
174458619b14SKalle Valo 	b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xFFCF, 0x10);
174558619b14SKalle Valo 
174658619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
174758619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
174858619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
174958619b14SKalle Valo 
175058619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_CCK(0x0A), 0x2000);
175158619b14SKalle Valo 	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
175258619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0004);
175358619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFB);
175458619b14SKalle Valo 	}
175558619b14SKalle Valo 	b43_phy_maskset(dev, B43_PHY_CCK(0x03), 0xFF9F, 0x40);
175658619b14SKalle Valo 
175758619b14SKalle Valo 	if (phy->radio_rev == 8) {
175858619b14SKalle Valo 		b43_radio_write16(dev, 0x43, 0x000F);
175958619b14SKalle Valo 	} else {
176058619b14SKalle Valo 		b43_radio_write16(dev, 0x52, 0);
176158619b14SKalle Valo 		b43_radio_maskset(dev, 0x43, 0xFFF0, 0x9);
176258619b14SKalle Valo 	}
176358619b14SKalle Valo 	b43_gphy_set_baseband_attenuation(dev, 11);
176458619b14SKalle Valo 
176558619b14SKalle Valo 	if (phy->rev >= 3)
176658619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
176758619b14SKalle Valo 	else
176858619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
176958619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_LO_CTL, 0);
177058619b14SKalle Valo 
177158619b14SKalle Valo 	b43_phy_maskset(dev, B43_PHY_CCK(0x2B), 0xFFC0, 0x01);
177258619b14SKalle Valo 	b43_phy_maskset(dev, B43_PHY_CCK(0x2B), 0xC0FF, 0x800);
177358619b14SKalle Valo 
177458619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_RFOVER, 0x0100);
177558619b14SKalle Valo 	b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF);
177658619b14SKalle Valo 
177758619b14SKalle Valo 	if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA) {
177858619b14SKalle Valo 		if (phy->rev >= 7) {
177958619b14SKalle Valo 			b43_phy_set(dev, B43_PHY_RFOVER, 0x0800);
178058619b14SKalle Valo 			b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000);
178158619b14SKalle Valo 		}
178258619b14SKalle Valo 	}
178358619b14SKalle Valo 	b43_radio_mask(dev, 0x7A, 0x00F7);
178458619b14SKalle Valo 
178558619b14SKalle Valo 	j = 0;
178658619b14SKalle Valo 	loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
178758619b14SKalle Valo 	for (i = 0; i < loop_i_max; i++) {
178858619b14SKalle Valo 		for (j = 0; j < 16; j++) {
178958619b14SKalle Valo 			b43_radio_write16(dev, 0x43, i);
179058619b14SKalle Valo 			b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xF0FF, (j << 8));
179158619b14SKalle Valo 			b43_phy_maskset(dev, B43_PHY_PGACTL, 0x0FFF, 0xA000);
179258619b14SKalle Valo 			b43_phy_set(dev, B43_PHY_PGACTL, 0xF000);
179358619b14SKalle Valo 			udelay(20);
179458619b14SKalle Valo 			if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
179558619b14SKalle Valo 				goto exit_loop1;
179658619b14SKalle Valo 		}
179758619b14SKalle Valo 	}
179858619b14SKalle Valo       exit_loop1:
179958619b14SKalle Valo 	loop1_outer_done = i;
180058619b14SKalle Valo 	loop1_inner_done = j;
180158619b14SKalle Valo 	if (j >= 8) {
180258619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x30);
180358619b14SKalle Valo 		trsw_rx = 0x1B;
180458619b14SKalle Valo 		for (j = j - 8; j < 16; j++) {
180558619b14SKalle Valo 			b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xF0FF, (j << 8));
180658619b14SKalle Valo 			b43_phy_maskset(dev, B43_PHY_PGACTL, 0x0FFF, 0xA000);
180758619b14SKalle Valo 			b43_phy_set(dev, B43_PHY_PGACTL, 0xF000);
180858619b14SKalle Valo 			udelay(20);
180958619b14SKalle Valo 			trsw_rx -= 3;
181058619b14SKalle Valo 			if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
181158619b14SKalle Valo 				goto exit_loop2;
181258619b14SKalle Valo 		}
181358619b14SKalle Valo 	} else
181458619b14SKalle Valo 		trsw_rx = 0x18;
181558619b14SKalle Valo       exit_loop2:
181658619b14SKalle Valo 
181758619b14SKalle Valo 	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
181858619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
181958619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
182058619b14SKalle Valo 	}
182158619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
182258619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
182358619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
182458619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
182558619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
182658619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
182758619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
182858619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
182958619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
183058619b14SKalle Valo 
183158619b14SKalle Valo 	b43_gphy_set_baseband_attenuation(dev, backup_bband);
183258619b14SKalle Valo 
183358619b14SKalle Valo 	b43_radio_write16(dev, 0x52, backup_radio[0]);
183458619b14SKalle Valo 	b43_radio_write16(dev, 0x43, backup_radio[1]);
183558619b14SKalle Valo 	b43_radio_write16(dev, 0x7A, backup_radio[2]);
183658619b14SKalle Valo 
183758619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003);
183858619b14SKalle Valo 	udelay(10);
183958619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]);
184058619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]);
184158619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]);
184258619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]);
184358619b14SKalle Valo 
184458619b14SKalle Valo 	gphy->max_lb_gain =
184558619b14SKalle Valo 	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
184658619b14SKalle Valo 	gphy->trsw_rx_gain = trsw_rx * 2;
184758619b14SKalle Valo }
184858619b14SKalle Valo 
b43_hardware_pctl_early_init(struct b43_wldev * dev)184958619b14SKalle Valo static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
185058619b14SKalle Valo {
185158619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
185258619b14SKalle Valo 
185358619b14SKalle Valo 	if (!b43_has_hardware_pctl(dev)) {
185458619b14SKalle Valo 		b43_phy_write(dev, 0x047A, 0xC111);
185558619b14SKalle Valo 		return;
185658619b14SKalle Valo 	}
185758619b14SKalle Valo 
185858619b14SKalle Valo 	b43_phy_mask(dev, 0x0036, 0xFEFF);
185958619b14SKalle Valo 	b43_phy_write(dev, 0x002F, 0x0202);
186058619b14SKalle Valo 	b43_phy_set(dev, 0x047C, 0x0002);
186158619b14SKalle Valo 	b43_phy_set(dev, 0x047A, 0xF000);
186258619b14SKalle Valo 	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
186358619b14SKalle Valo 		b43_phy_maskset(dev, 0x047A, 0xFF0F, 0x0010);
186458619b14SKalle Valo 		b43_phy_set(dev, 0x005D, 0x8000);
186558619b14SKalle Valo 		b43_phy_maskset(dev, 0x004E, 0xFFC0, 0x0010);
186658619b14SKalle Valo 		b43_phy_write(dev, 0x002E, 0xC07F);
186758619b14SKalle Valo 		b43_phy_set(dev, 0x0036, 0x0400);
186858619b14SKalle Valo 	} else {
186958619b14SKalle Valo 		b43_phy_set(dev, 0x0036, 0x0200);
187058619b14SKalle Valo 		b43_phy_set(dev, 0x0036, 0x0400);
187158619b14SKalle Valo 		b43_phy_mask(dev, 0x005D, 0x7FFF);
187258619b14SKalle Valo 		b43_phy_mask(dev, 0x004F, 0xFFFE);
187358619b14SKalle Valo 		b43_phy_maskset(dev, 0x004E, 0xFFC0, 0x0010);
187458619b14SKalle Valo 		b43_phy_write(dev, 0x002E, 0xC07F);
187558619b14SKalle Valo 		b43_phy_maskset(dev, 0x047A, 0xFF0F, 0x0010);
187658619b14SKalle Valo 	}
187758619b14SKalle Valo }
187858619b14SKalle Valo 
187958619b14SKalle Valo /* Hardware power control for G-PHY */
b43_hardware_pctl_init_gphy(struct b43_wldev * dev)188058619b14SKalle Valo static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
188158619b14SKalle Valo {
188258619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
188358619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
188458619b14SKalle Valo 
188558619b14SKalle Valo 	if (!b43_has_hardware_pctl(dev)) {
188658619b14SKalle Valo 		/* No hardware power control */
188758619b14SKalle Valo 		b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL);
188858619b14SKalle Valo 		return;
188958619b14SKalle Valo 	}
189058619b14SKalle Valo 
189158619b14SKalle Valo 	b43_phy_maskset(dev, 0x0036, 0xFFC0, (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
189258619b14SKalle Valo 	b43_phy_maskset(dev, 0x0478, 0xFF00, (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
189358619b14SKalle Valo 	b43_gphy_tssi_power_lt_init(dev);
189458619b14SKalle Valo 	b43_gphy_gain_lt_init(dev);
189558619b14SKalle Valo 	b43_phy_mask(dev, 0x0060, 0xFFBF);
189658619b14SKalle Valo 	b43_phy_write(dev, 0x0014, 0x0000);
189758619b14SKalle Valo 
189858619b14SKalle Valo 	B43_WARN_ON(phy->rev < 6);
189958619b14SKalle Valo 	b43_phy_set(dev, 0x0478, 0x0800);
190058619b14SKalle Valo 	b43_phy_mask(dev, 0x0478, 0xFEFF);
190158619b14SKalle Valo 	b43_phy_mask(dev, 0x0801, 0xFFBF);
190258619b14SKalle Valo 
190358619b14SKalle Valo 	b43_gphy_dc_lt_init(dev, 1);
190458619b14SKalle Valo 
190558619b14SKalle Valo 	/* Enable hardware pctl in firmware. */
190658619b14SKalle Valo 	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
190758619b14SKalle Valo }
190858619b14SKalle Valo 
190958619b14SKalle Valo /* Initialize B/G PHY power control */
b43_phy_init_pctl(struct b43_wldev * dev)191058619b14SKalle Valo static void b43_phy_init_pctl(struct b43_wldev *dev)
191158619b14SKalle Valo {
191258619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
191358619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
191458619b14SKalle Valo 	struct b43_rfatt old_rfatt;
191558619b14SKalle Valo 	struct b43_bbatt old_bbatt;
191658619b14SKalle Valo 	u8 old_tx_control = 0;
191758619b14SKalle Valo 
191858619b14SKalle Valo 	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
191958619b14SKalle Valo 
192058619b14SKalle Valo 	if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) &&
192158619b14SKalle Valo 	    (dev->dev->board_type == SSB_BOARD_BU4306))
192258619b14SKalle Valo 		return;
192358619b14SKalle Valo 
192458619b14SKalle Valo 	b43_phy_write(dev, 0x0028, 0x8018);
192558619b14SKalle Valo 
192658619b14SKalle Valo 	/* This does something with the Analog... */
192758619b14SKalle Valo 	b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0)
192858619b14SKalle Valo 		    & 0xFFDF);
192958619b14SKalle Valo 
193058619b14SKalle Valo 	if (!phy->gmode)
193158619b14SKalle Valo 		return;
193258619b14SKalle Valo 	b43_hardware_pctl_early_init(dev);
193358619b14SKalle Valo 	if (gphy->cur_idle_tssi == 0) {
193458619b14SKalle Valo 		if (phy->radio_ver == 0x2050 && phy->analog == 0) {
193558619b14SKalle Valo 			b43_radio_maskset(dev, 0x0076, 0x00F7, 0x0084);
193658619b14SKalle Valo 		} else {
193758619b14SKalle Valo 			struct b43_rfatt rfatt;
193858619b14SKalle Valo 			struct b43_bbatt bbatt;
193958619b14SKalle Valo 
194058619b14SKalle Valo 			memcpy(&old_rfatt, &gphy->rfatt, sizeof(old_rfatt));
194158619b14SKalle Valo 			memcpy(&old_bbatt, &gphy->bbatt, sizeof(old_bbatt));
194258619b14SKalle Valo 			old_tx_control = gphy->tx_control;
194358619b14SKalle Valo 
194458619b14SKalle Valo 			bbatt.att = 11;
194558619b14SKalle Valo 			if (phy->radio_rev == 8) {
194658619b14SKalle Valo 				rfatt.att = 15;
194758619b14SKalle Valo 				rfatt.with_padmix = true;
194858619b14SKalle Valo 			} else {
194958619b14SKalle Valo 				rfatt.att = 9;
195058619b14SKalle Valo 				rfatt.with_padmix = false;
195158619b14SKalle Valo 			}
195258619b14SKalle Valo 			b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
195358619b14SKalle Valo 		}
195458619b14SKalle Valo 		b43_dummy_transmission(dev, false, true);
195558619b14SKalle Valo 		gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
195658619b14SKalle Valo 		if (B43_DEBUG) {
195758619b14SKalle Valo 			/* Current-Idle-TSSI sanity check. */
195858619b14SKalle Valo 			if (abs(gphy->cur_idle_tssi - gphy->tgt_idle_tssi) >= 20) {
195958619b14SKalle Valo 				b43dbg(dev->wl,
196058619b14SKalle Valo 				       "!WARNING! Idle-TSSI phy->cur_idle_tssi "
196158619b14SKalle Valo 				       "measuring failed. (cur=%d, tgt=%d). Disabling TX power "
196258619b14SKalle Valo 				       "adjustment.\n", gphy->cur_idle_tssi,
196358619b14SKalle Valo 				       gphy->tgt_idle_tssi);
196458619b14SKalle Valo 				gphy->cur_idle_tssi = 0;
196558619b14SKalle Valo 			}
196658619b14SKalle Valo 		}
196758619b14SKalle Valo 		if (phy->radio_ver == 0x2050 && phy->analog == 0) {
196858619b14SKalle Valo 			b43_radio_mask(dev, 0x0076, 0xFF7B);
196958619b14SKalle Valo 		} else {
197058619b14SKalle Valo 			b43_set_txpower_g(dev, &old_bbatt,
197158619b14SKalle Valo 					  &old_rfatt, old_tx_control);
197258619b14SKalle Valo 		}
197358619b14SKalle Valo 	}
197458619b14SKalle Valo 	b43_hardware_pctl_init_gphy(dev);
197558619b14SKalle Valo 	b43_shm_clear_tssi(dev);
197658619b14SKalle Valo }
197758619b14SKalle Valo 
b43_phy_inita(struct b43_wldev * dev)19789791333aSGuenter Roeck static void b43_phy_inita(struct b43_wldev *dev)
19799791333aSGuenter Roeck {
19809791333aSGuenter Roeck 	struct b43_phy *phy = &dev->phy;
19819791333aSGuenter Roeck 
19829791333aSGuenter Roeck 	might_sleep();
19839791333aSGuenter Roeck 
19849791333aSGuenter Roeck 	if (phy->rev >= 6) {
19859791333aSGuenter Roeck 		if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
19869791333aSGuenter Roeck 			b43_phy_set(dev, B43_PHY_ENCORE, 0x0010);
19879791333aSGuenter Roeck 		else
19889791333aSGuenter Roeck 			b43_phy_mask(dev, B43_PHY_ENCORE, ~0x1010);
19899791333aSGuenter Roeck 	}
19909791333aSGuenter Roeck 
19919791333aSGuenter Roeck 	b43_wa_all(dev);
19929791333aSGuenter Roeck 
19939791333aSGuenter Roeck 	if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)
19949791333aSGuenter Roeck 		b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF);
19959791333aSGuenter Roeck }
19969791333aSGuenter Roeck 
b43_phy_initg(struct b43_wldev * dev)199758619b14SKalle Valo static void b43_phy_initg(struct b43_wldev *dev)
199858619b14SKalle Valo {
199958619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
200058619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
200158619b14SKalle Valo 	u16 tmp;
200258619b14SKalle Valo 
200358619b14SKalle Valo 	if (phy->rev == 1)
200458619b14SKalle Valo 		b43_phy_initb5(dev);
200558619b14SKalle Valo 	else
200658619b14SKalle Valo 		b43_phy_initb6(dev);
200758619b14SKalle Valo 
200858619b14SKalle Valo 	if (phy->rev >= 2 || phy->gmode)
200958619b14SKalle Valo 		b43_phy_inita(dev);
201058619b14SKalle Valo 
201158619b14SKalle Valo 	if (phy->rev >= 2) {
201258619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_ANALOGOVER, 0);
201358619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0);
201458619b14SKalle Valo 	}
201558619b14SKalle Valo 	if (phy->rev == 2) {
201658619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVER, 0);
201758619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
201858619b14SKalle Valo 	}
201958619b14SKalle Valo 	if (phy->rev > 5) {
202058619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVER, 0x400);
202158619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
202258619b14SKalle Valo 	}
202358619b14SKalle Valo 	if (phy->gmode || phy->rev >= 2) {
202458619b14SKalle Valo 		tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM);
202558619b14SKalle Valo 		tmp &= B43_PHYVER_VERSION;
202658619b14SKalle Valo 		if (tmp == 3 || tmp == 5) {
202758619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816);
202858619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
202958619b14SKalle Valo 		}
203058619b14SKalle Valo 		if (tmp == 5) {
203158619b14SKalle Valo 			b43_phy_maskset(dev, B43_PHY_OFDM(0xCC), 0x00FF, 0x1F00);
203258619b14SKalle Valo 		}
203358619b14SKalle Valo 	}
203458619b14SKalle Valo 	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
203558619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
203658619b14SKalle Valo 	if (phy->radio_rev == 8) {
203758619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x80);
203858619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_OFDM(0x3E), 0x4);
203958619b14SKalle Valo 	}
204058619b14SKalle Valo 	if (has_loopback_gain(phy))
204158619b14SKalle Valo 		b43_calc_loopback_gain(dev);
204258619b14SKalle Valo 
204358619b14SKalle Valo 	if (phy->radio_rev != 8) {
204458619b14SKalle Valo 		if (gphy->initval == 0xFFFF)
204558619b14SKalle Valo 			gphy->initval = b43_radio_init2050(dev);
204658619b14SKalle Valo 		else
204758619b14SKalle Valo 			b43_radio_write16(dev, 0x0078, gphy->initval);
204858619b14SKalle Valo 	}
204958619b14SKalle Valo 	b43_lo_g_init(dev);
205058619b14SKalle Valo 	if (has_tx_magnification(phy)) {
205158619b14SKalle Valo 		b43_radio_write16(dev, 0x52,
205258619b14SKalle Valo 				  (b43_radio_read16(dev, 0x52) & 0xFF00)
205358619b14SKalle Valo 				  | gphy->lo_control->tx_bias | gphy->
205458619b14SKalle Valo 				  lo_control->tx_magn);
205558619b14SKalle Valo 	} else {
205658619b14SKalle Valo 		b43_radio_maskset(dev, 0x52, 0xFFF0, gphy->lo_control->tx_bias);
205758619b14SKalle Valo 	}
205858619b14SKalle Valo 	if (phy->rev >= 6) {
205958619b14SKalle Valo 		b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12));
206058619b14SKalle Valo 	}
206158619b14SKalle Valo 	if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)
206258619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
206358619b14SKalle Valo 	else
206458619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
206558619b14SKalle Valo 	if (phy->rev < 2)
206658619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
206758619b14SKalle Valo 	else
206858619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
206958619b14SKalle Valo 	if (phy->gmode || phy->rev >= 2) {
207058619b14SKalle Valo 		b43_lo_g_adjust(dev);
207158619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
207258619b14SKalle Valo 	}
207358619b14SKalle Valo 
207458619b14SKalle Valo 	if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) {
207558619b14SKalle Valo 		/* The specs state to update the NRSSI LT with
207658619b14SKalle Valo 		 * the value 0x7FFFFFFF here. I think that is some weird
207758619b14SKalle Valo 		 * compiler optimization in the original driver.
207858619b14SKalle Valo 		 * Essentially, what we do here is resetting all NRSSI LT
207958619b14SKalle Valo 		 * entries to -32 (see the clamp_val() in nrssi_hw_update())
208058619b14SKalle Valo 		 */
208158619b14SKalle Valo 		b43_nrssi_hw_update(dev, 0xFFFF);	//FIXME?
208258619b14SKalle Valo 		b43_calc_nrssi_threshold(dev);
208358619b14SKalle Valo 	} else if (phy->gmode || phy->rev >= 2) {
208458619b14SKalle Valo 		if (gphy->nrssi[0] == -1000) {
208558619b14SKalle Valo 			B43_WARN_ON(gphy->nrssi[1] != -1000);
208658619b14SKalle Valo 			b43_calc_nrssi_slope(dev);
208758619b14SKalle Valo 		} else
208858619b14SKalle Valo 			b43_calc_nrssi_threshold(dev);
208958619b14SKalle Valo 	}
209058619b14SKalle Valo 	if (phy->radio_rev == 8)
209158619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230);
209258619b14SKalle Valo 	b43_phy_init_pctl(dev);
209358619b14SKalle Valo 	/* FIXME: The spec says in the following if, the 0 should be replaced
209458619b14SKalle Valo 	   'if OFDM may not be used in the current locale'
209558619b14SKalle Valo 	   but OFDM is legal everywhere */
209658619b14SKalle Valo 	if ((dev->dev->chip_id == 0x4306
209758619b14SKalle Valo 	     && dev->dev->chip_pkg == 2) || 0) {
209858619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF);
209958619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF);
210058619b14SKalle Valo 	}
210158619b14SKalle Valo }
210258619b14SKalle Valo 
b43_gphy_channel_switch(struct b43_wldev * dev,unsigned int channel,bool synthetic_pu_workaround)210358619b14SKalle Valo void b43_gphy_channel_switch(struct b43_wldev *dev,
210458619b14SKalle Valo 			     unsigned int channel,
210558619b14SKalle Valo 			     bool synthetic_pu_workaround)
210658619b14SKalle Valo {
210758619b14SKalle Valo 	if (synthetic_pu_workaround)
210858619b14SKalle Valo 		b43_synth_pu_workaround(dev, channel);
210958619b14SKalle Valo 
211058619b14SKalle Valo 	b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
211158619b14SKalle Valo 
211258619b14SKalle Valo 	if (channel == 14) {
211358619b14SKalle Valo 		if (dev->dev->bus_sprom->country_code ==
211458619b14SKalle Valo 		    SSB_SPROM1CCODE_JAPAN)
211558619b14SKalle Valo 			b43_hf_write(dev,
211658619b14SKalle Valo 				     b43_hf_read(dev) & ~B43_HF_ACPR);
211758619b14SKalle Valo 		else
211858619b14SKalle Valo 			b43_hf_write(dev,
211958619b14SKalle Valo 				     b43_hf_read(dev) | B43_HF_ACPR);
212058619b14SKalle Valo 		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
212158619b14SKalle Valo 			    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
212258619b14SKalle Valo 			    | (1 << 11));
212358619b14SKalle Valo 	} else {
212458619b14SKalle Valo 		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
212558619b14SKalle Valo 			    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
212658619b14SKalle Valo 			    & 0xF7BF);
212758619b14SKalle Valo 	}
212858619b14SKalle Valo }
212958619b14SKalle Valo 
default_baseband_attenuation(struct b43_wldev * dev,struct b43_bbatt * bb)213058619b14SKalle Valo static void default_baseband_attenuation(struct b43_wldev *dev,
213158619b14SKalle Valo 					 struct b43_bbatt *bb)
213258619b14SKalle Valo {
213358619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
213458619b14SKalle Valo 
213558619b14SKalle Valo 	if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
213658619b14SKalle Valo 		bb->att = 0;
213758619b14SKalle Valo 	else
213858619b14SKalle Valo 		bb->att = 2;
213958619b14SKalle Valo }
214058619b14SKalle Valo 
default_radio_attenuation(struct b43_wldev * dev,struct b43_rfatt * rf)214158619b14SKalle Valo static void default_radio_attenuation(struct b43_wldev *dev,
214258619b14SKalle Valo 				      struct b43_rfatt *rf)
214358619b14SKalle Valo {
214458619b14SKalle Valo 	struct b43_bus_dev *bdev = dev->dev;
214558619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
214658619b14SKalle Valo 
214758619b14SKalle Valo 	rf->with_padmix = false;
214858619b14SKalle Valo 
214958619b14SKalle Valo 	if (dev->dev->board_vendor == SSB_BOARDVENDOR_BCM &&
215058619b14SKalle Valo 	    dev->dev->board_type == SSB_BOARD_BCM4309G) {
215158619b14SKalle Valo 		if (dev->dev->board_rev < 0x43) {
215258619b14SKalle Valo 			rf->att = 2;
215358619b14SKalle Valo 			return;
215458619b14SKalle Valo 		} else if (dev->dev->board_rev < 0x51) {
215558619b14SKalle Valo 			rf->att = 3;
215658619b14SKalle Valo 			return;
215758619b14SKalle Valo 		}
215858619b14SKalle Valo 	}
215958619b14SKalle Valo 
216058619b14SKalle Valo 	switch (phy->radio_ver) {
216158619b14SKalle Valo 	case 0x2053:
216258619b14SKalle Valo 		switch (phy->radio_rev) {
216358619b14SKalle Valo 		case 1:
216458619b14SKalle Valo 			rf->att = 6;
216558619b14SKalle Valo 			return;
216658619b14SKalle Valo 		}
216758619b14SKalle Valo 		break;
216858619b14SKalle Valo 	case 0x2050:
216958619b14SKalle Valo 		switch (phy->radio_rev) {
217058619b14SKalle Valo 		case 0:
217158619b14SKalle Valo 			rf->att = 5;
217258619b14SKalle Valo 			return;
217358619b14SKalle Valo 		case 1:
217458619b14SKalle Valo 			if (phy->type == B43_PHYTYPE_G) {
217558619b14SKalle Valo 				if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
217658619b14SKalle Valo 				    && bdev->board_type == SSB_BOARD_BCM4309G
217758619b14SKalle Valo 				    && bdev->board_rev >= 30)
217858619b14SKalle Valo 					rf->att = 3;
217958619b14SKalle Valo 				else if (bdev->board_vendor ==
218058619b14SKalle Valo 					 SSB_BOARDVENDOR_BCM
218158619b14SKalle Valo 					 && bdev->board_type ==
218258619b14SKalle Valo 					 SSB_BOARD_BU4306)
218358619b14SKalle Valo 					rf->att = 3;
218458619b14SKalle Valo 				else
218558619b14SKalle Valo 					rf->att = 1;
218658619b14SKalle Valo 			} else {
218758619b14SKalle Valo 				if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
218858619b14SKalle Valo 				    && bdev->board_type == SSB_BOARD_BCM4309G
218958619b14SKalle Valo 				    && bdev->board_rev >= 30)
219058619b14SKalle Valo 					rf->att = 7;
219158619b14SKalle Valo 				else
219258619b14SKalle Valo 					rf->att = 6;
219358619b14SKalle Valo 			}
219458619b14SKalle Valo 			return;
219558619b14SKalle Valo 		case 2:
219658619b14SKalle Valo 			if (phy->type == B43_PHYTYPE_G) {
219758619b14SKalle Valo 				if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
219858619b14SKalle Valo 				    && bdev->board_type == SSB_BOARD_BCM4309G
219958619b14SKalle Valo 				    && bdev->board_rev >= 30)
220058619b14SKalle Valo 					rf->att = 3;
220158619b14SKalle Valo 				else if (bdev->board_vendor ==
220258619b14SKalle Valo 					 SSB_BOARDVENDOR_BCM
220358619b14SKalle Valo 					 && bdev->board_type ==
220458619b14SKalle Valo 					 SSB_BOARD_BU4306)
220558619b14SKalle Valo 					rf->att = 5;
220658619b14SKalle Valo 				else if (bdev->chip_id == 0x4320)
220758619b14SKalle Valo 					rf->att = 4;
220858619b14SKalle Valo 				else
220958619b14SKalle Valo 					rf->att = 3;
221058619b14SKalle Valo 			} else
221158619b14SKalle Valo 				rf->att = 6;
221258619b14SKalle Valo 			return;
221358619b14SKalle Valo 		case 3:
221458619b14SKalle Valo 			rf->att = 5;
221558619b14SKalle Valo 			return;
221658619b14SKalle Valo 		case 4:
221758619b14SKalle Valo 		case 5:
221858619b14SKalle Valo 			rf->att = 1;
221958619b14SKalle Valo 			return;
222058619b14SKalle Valo 		case 6:
222158619b14SKalle Valo 		case 7:
222258619b14SKalle Valo 			rf->att = 5;
222358619b14SKalle Valo 			return;
222458619b14SKalle Valo 		case 8:
222558619b14SKalle Valo 			rf->att = 0xA;
222658619b14SKalle Valo 			rf->with_padmix = true;
222758619b14SKalle Valo 			return;
222858619b14SKalle Valo 		case 9:
222958619b14SKalle Valo 		default:
223058619b14SKalle Valo 			rf->att = 5;
223158619b14SKalle Valo 			return;
223258619b14SKalle Valo 		}
223358619b14SKalle Valo 	}
223458619b14SKalle Valo 	rf->att = 5;
223558619b14SKalle Valo }
223658619b14SKalle Valo 
default_tx_control(struct b43_wldev * dev)223758619b14SKalle Valo static u16 default_tx_control(struct b43_wldev *dev)
223858619b14SKalle Valo {
223958619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
224058619b14SKalle Valo 
224158619b14SKalle Valo 	if (phy->radio_ver != 0x2050)
224258619b14SKalle Valo 		return 0;
224358619b14SKalle Valo 	if (phy->radio_rev == 1)
224458619b14SKalle Valo 		return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX;
224558619b14SKalle Valo 	if (phy->radio_rev < 6)
224658619b14SKalle Valo 		return B43_TXCTL_PA2DB;
224758619b14SKalle Valo 	if (phy->radio_rev == 8)
224858619b14SKalle Valo 		return B43_TXCTL_TXMIX;
224958619b14SKalle Valo 	return 0;
225058619b14SKalle Valo }
225158619b14SKalle Valo 
b43_gphy_aci_detect(struct b43_wldev * dev,u8 channel)225258619b14SKalle Valo static u8 b43_gphy_aci_detect(struct b43_wldev *dev, u8 channel)
225358619b14SKalle Valo {
225458619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
225558619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
225658619b14SKalle Valo 	u8 ret = 0;
225758619b14SKalle Valo 	u16 saved, rssi, temp;
225858619b14SKalle Valo 	int i, j = 0;
225958619b14SKalle Valo 
226058619b14SKalle Valo 	saved = b43_phy_read(dev, 0x0403);
226158619b14SKalle Valo 	b43_switch_channel(dev, channel);
226258619b14SKalle Valo 	b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
226358619b14SKalle Valo 	if (gphy->aci_hw_rssi)
226458619b14SKalle Valo 		rssi = b43_phy_read(dev, 0x048A) & 0x3F;
226558619b14SKalle Valo 	else
226658619b14SKalle Valo 		rssi = saved & 0x3F;
226758619b14SKalle Valo 	/* clamp temp to signed 5bit */
226858619b14SKalle Valo 	if (rssi > 32)
226958619b14SKalle Valo 		rssi -= 64;
227058619b14SKalle Valo 	for (i = 0; i < 100; i++) {
227158619b14SKalle Valo 		temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F;
227258619b14SKalle Valo 		if (temp > 32)
227358619b14SKalle Valo 			temp -= 64;
227458619b14SKalle Valo 		if (temp < rssi)
227558619b14SKalle Valo 			j++;
227658619b14SKalle Valo 		if (j >= 20)
227758619b14SKalle Valo 			ret = 1;
227858619b14SKalle Valo 	}
227958619b14SKalle Valo 	b43_phy_write(dev, 0x0403, saved);
228058619b14SKalle Valo 
228158619b14SKalle Valo 	return ret;
228258619b14SKalle Valo }
228358619b14SKalle Valo 
b43_gphy_aci_scan(struct b43_wldev * dev)228458619b14SKalle Valo static u8 b43_gphy_aci_scan(struct b43_wldev *dev)
228558619b14SKalle Valo {
228658619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
2287e31fbe10SColin Ian King 	u8 ret[13] = { 0 };
228858619b14SKalle Valo 	unsigned int channel = phy->channel;
228958619b14SKalle Valo 	unsigned int i, j, start, end;
229058619b14SKalle Valo 
229158619b14SKalle Valo 	if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
229258619b14SKalle Valo 		return 0;
229358619b14SKalle Valo 
229458619b14SKalle Valo 	b43_phy_lock(dev);
229558619b14SKalle Valo 	b43_radio_lock(dev);
229658619b14SKalle Valo 	b43_phy_mask(dev, 0x0802, 0xFFFC);
229758619b14SKalle Valo 	b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF);
229858619b14SKalle Valo 	b43_set_all_gains(dev, 3, 8, 1);
229958619b14SKalle Valo 
2300*9b793db5SDan Carpenter 	start = (channel > 5) ? channel - 5 : 1;
230158619b14SKalle Valo 	end = (channel + 5 < 14) ? channel + 5 : 13;
230258619b14SKalle Valo 
230358619b14SKalle Valo 	for (i = start; i <= end; i++) {
230458619b14SKalle Valo 		if (abs(channel - i) > 2)
230558619b14SKalle Valo 			ret[i - 1] = b43_gphy_aci_detect(dev, i);
230658619b14SKalle Valo 	}
230758619b14SKalle Valo 	b43_switch_channel(dev, channel);
230858619b14SKalle Valo 	b43_phy_maskset(dev, 0x0802, 0xFFFC, 0x0003);
230958619b14SKalle Valo 	b43_phy_mask(dev, 0x0403, 0xFFF8);
231058619b14SKalle Valo 	b43_phy_set(dev, B43_PHY_G_CRS, 0x8000);
231158619b14SKalle Valo 	b43_set_original_gains(dev);
231258619b14SKalle Valo 	for (i = 0; i < 13; i++) {
231358619b14SKalle Valo 		if (!ret[i])
231458619b14SKalle Valo 			continue;
231558619b14SKalle Valo 		end = (i + 5 < 13) ? i + 5 : 13;
231658619b14SKalle Valo 		for (j = i; j < end; j++)
231758619b14SKalle Valo 			ret[j] = 1;
231858619b14SKalle Valo 	}
231958619b14SKalle Valo 	b43_radio_unlock(dev);
232058619b14SKalle Valo 	b43_phy_unlock(dev);
232158619b14SKalle Valo 
232258619b14SKalle Valo 	return ret[channel - 1];
232358619b14SKalle Valo }
232458619b14SKalle Valo 
b43_tssi2dbm_ad(s32 num,s32 den)232558619b14SKalle Valo static s32 b43_tssi2dbm_ad(s32 num, s32 den)
232658619b14SKalle Valo {
232758619b14SKalle Valo 	if (num < 0)
232858619b14SKalle Valo 		return num / den;
232958619b14SKalle Valo 	else
233058619b14SKalle Valo 		return (num + den / 2) / den;
233158619b14SKalle Valo }
233258619b14SKalle Valo 
b43_tssi2dbm_entry(s8 entry[],u8 index,s16 pab0,s16 pab1,s16 pab2)233358619b14SKalle Valo static s8 b43_tssi2dbm_entry(s8 entry[], u8 index,
233458619b14SKalle Valo 			     s16 pab0, s16 pab1, s16 pab2)
233558619b14SKalle Valo {
233658619b14SKalle Valo 	s32 m1, m2, f = 256, q, delta;
233758619b14SKalle Valo 	s8 i = 0;
233858619b14SKalle Valo 
233958619b14SKalle Valo 	m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
234058619b14SKalle Valo 	m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
234158619b14SKalle Valo 	do {
234258619b14SKalle Valo 		if (i > 15)
234358619b14SKalle Valo 			return -EINVAL;
234458619b14SKalle Valo 		q = b43_tssi2dbm_ad(f * 4096 -
234558619b14SKalle Valo 				    b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
234658619b14SKalle Valo 		delta = abs(q - f);
234758619b14SKalle Valo 		f = q;
234858619b14SKalle Valo 		i++;
234958619b14SKalle Valo 	} while (delta >= 2);
235058619b14SKalle Valo 	entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
235158619b14SKalle Valo 	return 0;
235258619b14SKalle Valo }
235358619b14SKalle Valo 
b43_generate_dyn_tssi2dbm_tab(struct b43_wldev * dev,s16 pab0,s16 pab1,s16 pab2)235458619b14SKalle Valo u8 *b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev,
235558619b14SKalle Valo 				  s16 pab0, s16 pab1, s16 pab2)
235658619b14SKalle Valo {
235758619b14SKalle Valo 	unsigned int i;
235858619b14SKalle Valo 	u8 *tab;
235958619b14SKalle Valo 	int err;
236058619b14SKalle Valo 
236158619b14SKalle Valo 	tab = kmalloc(64, GFP_KERNEL);
236258619b14SKalle Valo 	if (!tab) {
236358619b14SKalle Valo 		b43err(dev->wl, "Could not allocate memory "
236458619b14SKalle Valo 		       "for tssi2dbm table\n");
236558619b14SKalle Valo 		return NULL;
236658619b14SKalle Valo 	}
236758619b14SKalle Valo 	for (i = 0; i < 64; i++) {
236858619b14SKalle Valo 		err = b43_tssi2dbm_entry(tab, i, pab0, pab1, pab2);
236958619b14SKalle Valo 		if (err) {
237058619b14SKalle Valo 			b43err(dev->wl, "Could not generate "
237158619b14SKalle Valo 			       "tssi2dBm table\n");
237258619b14SKalle Valo 			kfree(tab);
237358619b14SKalle Valo 			return NULL;
237458619b14SKalle Valo 		}
237558619b14SKalle Valo 	}
237658619b14SKalle Valo 
237758619b14SKalle Valo 	return tab;
237858619b14SKalle Valo }
237958619b14SKalle Valo 
238058619b14SKalle Valo /* Initialise the TSSI->dBm lookup table */
b43_gphy_init_tssi2dbm_table(struct b43_wldev * dev)238158619b14SKalle Valo static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
238258619b14SKalle Valo {
238358619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
238458619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
238558619b14SKalle Valo 	s16 pab0, pab1, pab2;
238658619b14SKalle Valo 
238758619b14SKalle Valo 	pab0 = (s16) (dev->dev->bus_sprom->pa0b0);
238858619b14SKalle Valo 	pab1 = (s16) (dev->dev->bus_sprom->pa0b1);
238958619b14SKalle Valo 	pab2 = (s16) (dev->dev->bus_sprom->pa0b2);
239058619b14SKalle Valo 
239158619b14SKalle Valo 	B43_WARN_ON((dev->dev->chip_id == 0x4301) &&
239258619b14SKalle Valo 		    (phy->radio_ver != 0x2050)); /* Not supported anymore */
239358619b14SKalle Valo 
239458619b14SKalle Valo 	gphy->dyn_tssi_tbl = false;
239558619b14SKalle Valo 
239658619b14SKalle Valo 	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
239758619b14SKalle Valo 	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
239858619b14SKalle Valo 		/* The pabX values are set in SPROM. Use them. */
239958619b14SKalle Valo 		if ((s8) dev->dev->bus_sprom->itssi_bg != 0 &&
240058619b14SKalle Valo 		    (s8) dev->dev->bus_sprom->itssi_bg != -1) {
240158619b14SKalle Valo 			gphy->tgt_idle_tssi =
240258619b14SKalle Valo 				(s8) (dev->dev->bus_sprom->itssi_bg);
240358619b14SKalle Valo 		} else
240458619b14SKalle Valo 			gphy->tgt_idle_tssi = 62;
240558619b14SKalle Valo 		gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
240658619b14SKalle Valo 							       pab1, pab2);
240758619b14SKalle Valo 		if (!gphy->tssi2dbm)
240858619b14SKalle Valo 			return -ENOMEM;
240958619b14SKalle Valo 		gphy->dyn_tssi_tbl = true;
241058619b14SKalle Valo 	} else {
241158619b14SKalle Valo 		/* pabX values not set in SPROM. */
241258619b14SKalle Valo 		gphy->tgt_idle_tssi = 52;
241358619b14SKalle Valo 		gphy->tssi2dbm = b43_tssi2dbm_g_table;
241458619b14SKalle Valo 	}
241558619b14SKalle Valo 
241658619b14SKalle Valo 	return 0;
241758619b14SKalle Valo }
241858619b14SKalle Valo 
b43_gphy_op_allocate(struct b43_wldev * dev)241958619b14SKalle Valo static int b43_gphy_op_allocate(struct b43_wldev *dev)
242058619b14SKalle Valo {
242158619b14SKalle Valo 	struct b43_phy_g *gphy;
242258619b14SKalle Valo 	struct b43_txpower_lo_control *lo;
242358619b14SKalle Valo 	int err;
242458619b14SKalle Valo 
242558619b14SKalle Valo 	gphy = kzalloc(sizeof(*gphy), GFP_KERNEL);
242658619b14SKalle Valo 	if (!gphy) {
242758619b14SKalle Valo 		err = -ENOMEM;
242858619b14SKalle Valo 		goto error;
242958619b14SKalle Valo 	}
243058619b14SKalle Valo 	dev->phy.g = gphy;
243158619b14SKalle Valo 
243258619b14SKalle Valo 	lo = kzalloc(sizeof(*lo), GFP_KERNEL);
243358619b14SKalle Valo 	if (!lo) {
243458619b14SKalle Valo 		err = -ENOMEM;
243558619b14SKalle Valo 		goto err_free_gphy;
243658619b14SKalle Valo 	}
243758619b14SKalle Valo 	gphy->lo_control = lo;
243858619b14SKalle Valo 
243958619b14SKalle Valo 	err = b43_gphy_init_tssi2dbm_table(dev);
244058619b14SKalle Valo 	if (err)
244158619b14SKalle Valo 		goto err_free_lo;
244258619b14SKalle Valo 
244358619b14SKalle Valo 	return 0;
244458619b14SKalle Valo 
244558619b14SKalle Valo err_free_lo:
244658619b14SKalle Valo 	kfree(lo);
244758619b14SKalle Valo err_free_gphy:
244858619b14SKalle Valo 	kfree(gphy);
244958619b14SKalle Valo error:
245058619b14SKalle Valo 	return err;
245158619b14SKalle Valo }
245258619b14SKalle Valo 
b43_gphy_op_prepare_structs(struct b43_wldev * dev)245358619b14SKalle Valo static void b43_gphy_op_prepare_structs(struct b43_wldev *dev)
245458619b14SKalle Valo {
245558619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
245658619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
245758619b14SKalle Valo 	const void *tssi2dbm;
245858619b14SKalle Valo 	int tgt_idle_tssi;
245958619b14SKalle Valo 	struct b43_txpower_lo_control *lo;
246058619b14SKalle Valo 	unsigned int i;
246158619b14SKalle Valo 
246258619b14SKalle Valo 	/* tssi2dbm table is constant, so it is initialized at alloc time.
246358619b14SKalle Valo 	 * Save a copy of the pointer. */
246458619b14SKalle Valo 	tssi2dbm = gphy->tssi2dbm;
246558619b14SKalle Valo 	tgt_idle_tssi = gphy->tgt_idle_tssi;
246658619b14SKalle Valo 	/* Save the LO pointer. */
246758619b14SKalle Valo 	lo = gphy->lo_control;
246858619b14SKalle Valo 
246958619b14SKalle Valo 	/* Zero out the whole PHY structure. */
247058619b14SKalle Valo 	memset(gphy, 0, sizeof(*gphy));
247158619b14SKalle Valo 
247258619b14SKalle Valo 	/* Restore pointers. */
247358619b14SKalle Valo 	gphy->tssi2dbm = tssi2dbm;
247458619b14SKalle Valo 	gphy->tgt_idle_tssi = tgt_idle_tssi;
247558619b14SKalle Valo 	gphy->lo_control = lo;
247658619b14SKalle Valo 
247758619b14SKalle Valo 	memset(gphy->minlowsig, 0xFF, sizeof(gphy->minlowsig));
247858619b14SKalle Valo 
247958619b14SKalle Valo 	/* NRSSI */
248058619b14SKalle Valo 	for (i = 0; i < ARRAY_SIZE(gphy->nrssi); i++)
248158619b14SKalle Valo 		gphy->nrssi[i] = -1000;
248258619b14SKalle Valo 	for (i = 0; i < ARRAY_SIZE(gphy->nrssi_lt); i++)
248358619b14SKalle Valo 		gphy->nrssi_lt[i] = i;
248458619b14SKalle Valo 
248558619b14SKalle Valo 	gphy->lofcal = 0xFFFF;
248658619b14SKalle Valo 	gphy->initval = 0xFFFF;
248758619b14SKalle Valo 
248858619b14SKalle Valo 	gphy->interfmode = B43_INTERFMODE_NONE;
248958619b14SKalle Valo 
249058619b14SKalle Valo 	/* OFDM-table address caching. */
249158619b14SKalle Valo 	gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
249258619b14SKalle Valo 
249358619b14SKalle Valo 	gphy->average_tssi = 0xFF;
249458619b14SKalle Valo 
249558619b14SKalle Valo 	/* Local Osciallator structure */
249658619b14SKalle Valo 	lo->tx_bias = 0xFF;
249758619b14SKalle Valo 	INIT_LIST_HEAD(&lo->calib_list);
249858619b14SKalle Valo }
249958619b14SKalle Valo 
b43_gphy_op_free(struct b43_wldev * dev)250058619b14SKalle Valo static void b43_gphy_op_free(struct b43_wldev *dev)
250158619b14SKalle Valo {
250258619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
250358619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
250458619b14SKalle Valo 
250558619b14SKalle Valo 	kfree(gphy->lo_control);
250658619b14SKalle Valo 
250758619b14SKalle Valo 	if (gphy->dyn_tssi_tbl)
250858619b14SKalle Valo 		kfree(gphy->tssi2dbm);
250958619b14SKalle Valo 	gphy->dyn_tssi_tbl = false;
251058619b14SKalle Valo 	gphy->tssi2dbm = NULL;
251158619b14SKalle Valo 
251258619b14SKalle Valo 	kfree(gphy);
251358619b14SKalle Valo 	dev->phy.g = NULL;
251458619b14SKalle Valo }
251558619b14SKalle Valo 
b43_gphy_op_prepare_hardware(struct b43_wldev * dev)251658619b14SKalle Valo static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev)
251758619b14SKalle Valo {
251858619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
251958619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
252058619b14SKalle Valo 	struct b43_txpower_lo_control *lo = gphy->lo_control;
252158619b14SKalle Valo 
252258619b14SKalle Valo 	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
252358619b14SKalle Valo 
252458619b14SKalle Valo 	default_baseband_attenuation(dev, &gphy->bbatt);
252558619b14SKalle Valo 	default_radio_attenuation(dev, &gphy->rfatt);
252658619b14SKalle Valo 	gphy->tx_control = (default_tx_control(dev) << 4);
252758619b14SKalle Valo 	generate_rfatt_list(dev, &lo->rfatt_list);
252858619b14SKalle Valo 	generate_bbatt_list(dev, &lo->bbatt_list);
252958619b14SKalle Valo 
253058619b14SKalle Valo 	/* Commit previous writes */
253158619b14SKalle Valo 	b43_read32(dev, B43_MMIO_MACCTL);
253258619b14SKalle Valo 
253358619b14SKalle Valo 	if (phy->rev == 1) {
253458619b14SKalle Valo 		/* Workaround: Temporarly disable gmode through the early init
253558619b14SKalle Valo 		 * phase, as the gmode stuff is not needed for phy rev 1 */
253658619b14SKalle Valo 		phy->gmode = false;
253758619b14SKalle Valo 		b43_wireless_core_reset(dev, 0);
253858619b14SKalle Valo 		b43_phy_initg(dev);
253958619b14SKalle Valo 		phy->gmode = true;
254058619b14SKalle Valo 		b43_wireless_core_reset(dev, 1);
254158619b14SKalle Valo 	}
254258619b14SKalle Valo 
254358619b14SKalle Valo 	return 0;
254458619b14SKalle Valo }
254558619b14SKalle Valo 
b43_gphy_op_init(struct b43_wldev * dev)254658619b14SKalle Valo static int b43_gphy_op_init(struct b43_wldev *dev)
254758619b14SKalle Valo {
254858619b14SKalle Valo 	b43_phy_initg(dev);
254958619b14SKalle Valo 
255058619b14SKalle Valo 	return 0;
255158619b14SKalle Valo }
255258619b14SKalle Valo 
b43_gphy_op_exit(struct b43_wldev * dev)255358619b14SKalle Valo static void b43_gphy_op_exit(struct b43_wldev *dev)
255458619b14SKalle Valo {
255558619b14SKalle Valo 	b43_lo_g_cleanup(dev);
255658619b14SKalle Valo }
255758619b14SKalle Valo 
b43_gphy_op_read(struct b43_wldev * dev,u16 reg)255858619b14SKalle Valo static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg)
255958619b14SKalle Valo {
256058619b14SKalle Valo 	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
256158619b14SKalle Valo 	return b43_read16(dev, B43_MMIO_PHY_DATA);
256258619b14SKalle Valo }
256358619b14SKalle Valo 
b43_gphy_op_write(struct b43_wldev * dev,u16 reg,u16 value)256458619b14SKalle Valo static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
256558619b14SKalle Valo {
256658619b14SKalle Valo 	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
256758619b14SKalle Valo 	b43_write16(dev, B43_MMIO_PHY_DATA, value);
256858619b14SKalle Valo }
256958619b14SKalle Valo 
b43_gphy_op_radio_read(struct b43_wldev * dev,u16 reg)257058619b14SKalle Valo static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg)
257158619b14SKalle Valo {
257258619b14SKalle Valo 	/* Register 1 is a 32-bit register. */
257358619b14SKalle Valo 	B43_WARN_ON(reg == 1);
257458619b14SKalle Valo 	/* G-PHY needs 0x80 for read access. */
257558619b14SKalle Valo 	reg |= 0x80;
257658619b14SKalle Valo 
257758619b14SKalle Valo 	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
257858619b14SKalle Valo 	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
257958619b14SKalle Valo }
258058619b14SKalle Valo 
b43_gphy_op_radio_write(struct b43_wldev * dev,u16 reg,u16 value)258158619b14SKalle Valo static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
258258619b14SKalle Valo {
258358619b14SKalle Valo 	/* Register 1 is a 32-bit register. */
258458619b14SKalle Valo 	B43_WARN_ON(reg == 1);
258558619b14SKalle Valo 
258658619b14SKalle Valo 	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
258758619b14SKalle Valo 	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
258858619b14SKalle Valo }
258958619b14SKalle Valo 
b43_gphy_op_supports_hwpctl(struct b43_wldev * dev)259058619b14SKalle Valo static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev)
259158619b14SKalle Valo {
259258619b14SKalle Valo 	return (dev->phy.rev >= 6);
259358619b14SKalle Valo }
259458619b14SKalle Valo 
b43_gphy_op_software_rfkill(struct b43_wldev * dev,bool blocked)259558619b14SKalle Valo static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
259658619b14SKalle Valo 					bool blocked)
259758619b14SKalle Valo {
259858619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
259958619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
260058619b14SKalle Valo 	unsigned int channel;
260158619b14SKalle Valo 
260258619b14SKalle Valo 	might_sleep();
260358619b14SKalle Valo 
260458619b14SKalle Valo 	if (!blocked) {
260558619b14SKalle Valo 		/* Turn radio ON */
260658619b14SKalle Valo 		if (phy->radio_on)
260758619b14SKalle Valo 			return;
260858619b14SKalle Valo 
260958619b14SKalle Valo 		b43_phy_write(dev, 0x0015, 0x8000);
261058619b14SKalle Valo 		b43_phy_write(dev, 0x0015, 0xCC00);
261158619b14SKalle Valo 		b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
261258619b14SKalle Valo 		if (gphy->radio_off_context.valid) {
261358619b14SKalle Valo 			/* Restore the RFover values. */
261458619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_RFOVER,
261558619b14SKalle Valo 				      gphy->radio_off_context.rfover);
261658619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
261758619b14SKalle Valo 				      gphy->radio_off_context.rfoverval);
261858619b14SKalle Valo 			gphy->radio_off_context.valid = false;
261958619b14SKalle Valo 		}
262058619b14SKalle Valo 		channel = phy->channel;
262158619b14SKalle Valo 		b43_gphy_channel_switch(dev, 6, 1);
262258619b14SKalle Valo 		b43_gphy_channel_switch(dev, channel, 0);
262358619b14SKalle Valo 	} else {
262458619b14SKalle Valo 		/* Turn radio OFF */
262558619b14SKalle Valo 		u16 rfover, rfoverval;
262658619b14SKalle Valo 
262758619b14SKalle Valo 		rfover = b43_phy_read(dev, B43_PHY_RFOVER);
262858619b14SKalle Valo 		rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
262958619b14SKalle Valo 		gphy->radio_off_context.rfover = rfover;
263058619b14SKalle Valo 		gphy->radio_off_context.rfoverval = rfoverval;
263158619b14SKalle Valo 		gphy->radio_off_context.valid = true;
263258619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
263358619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
263458619b14SKalle Valo 	}
263558619b14SKalle Valo }
263658619b14SKalle Valo 
b43_gphy_op_switch_channel(struct b43_wldev * dev,unsigned int new_channel)263758619b14SKalle Valo static int b43_gphy_op_switch_channel(struct b43_wldev *dev,
263858619b14SKalle Valo 				      unsigned int new_channel)
263958619b14SKalle Valo {
264058619b14SKalle Valo 	if ((new_channel < 1) || (new_channel > 14))
264158619b14SKalle Valo 		return -EINVAL;
264258619b14SKalle Valo 	b43_gphy_channel_switch(dev, new_channel, 0);
264358619b14SKalle Valo 
264458619b14SKalle Valo 	return 0;
264558619b14SKalle Valo }
264658619b14SKalle Valo 
b43_gphy_op_get_default_chan(struct b43_wldev * dev)264758619b14SKalle Valo static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev)
264858619b14SKalle Valo {
264958619b14SKalle Valo 	return 1; /* Default to channel 1 */
265058619b14SKalle Valo }
265158619b14SKalle Valo 
b43_gphy_op_set_rx_antenna(struct b43_wldev * dev,int antenna)265258619b14SKalle Valo static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
265358619b14SKalle Valo {
265458619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
265558619b14SKalle Valo 	u16 tmp;
265658619b14SKalle Valo 	int autodiv = 0;
265758619b14SKalle Valo 
265858619b14SKalle Valo 	if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
265958619b14SKalle Valo 		autodiv = 1;
266058619b14SKalle Valo 
266158619b14SKalle Valo 	b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
266258619b14SKalle Valo 
266358619b14SKalle Valo 	b43_phy_maskset(dev, B43_PHY_BBANDCFG, ~B43_PHY_BBANDCFG_RXANT,
266458619b14SKalle Valo 			(autodiv ? B43_ANTENNA_AUTO1 : antenna) <<
266558619b14SKalle Valo 			B43_PHY_BBANDCFG_RXANT_SHIFT);
266658619b14SKalle Valo 
266758619b14SKalle Valo 	if (autodiv) {
266858619b14SKalle Valo 		tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
266958619b14SKalle Valo 		if (antenna == B43_ANTENNA_AUTO1)
267058619b14SKalle Valo 			tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
267158619b14SKalle Valo 		else
267258619b14SKalle Valo 			tmp |= B43_PHY_ANTDWELL_AUTODIV1;
267358619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
267458619b14SKalle Valo 	}
267558619b14SKalle Valo 
267658619b14SKalle Valo 	tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
267758619b14SKalle Valo 	if (autodiv)
267858619b14SKalle Valo 		tmp |= B43_PHY_ANTWRSETT_ARXDIV;
267958619b14SKalle Valo 	else
268058619b14SKalle Valo 		tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
268158619b14SKalle Valo 	b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
268258619b14SKalle Valo 
268358619b14SKalle Valo 	if (autodiv)
268458619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_ANTWRSETT, B43_PHY_ANTWRSETT_ARXDIV);
268558619b14SKalle Valo 	else {
268658619b14SKalle Valo 		b43_phy_mask(dev, B43_PHY_ANTWRSETT,
268758619b14SKalle Valo 			     B43_PHY_ANTWRSETT_ARXDIV);
268858619b14SKalle Valo 	}
268958619b14SKalle Valo 
269058619b14SKalle Valo 	if (phy->rev >= 2) {
269158619b14SKalle Valo 		b43_phy_set(dev, B43_PHY_OFDM61, B43_PHY_OFDM61_10);
269258619b14SKalle Valo 		b43_phy_maskset(dev, B43_PHY_DIVSRCHGAINBACK, 0xFF00, 0x15);
269358619b14SKalle Valo 
269458619b14SKalle Valo 		if (phy->rev == 2)
269558619b14SKalle Valo 			b43_phy_write(dev, B43_PHY_ADIVRELATED, 8);
269658619b14SKalle Valo 		else
269758619b14SKalle Valo 			b43_phy_maskset(dev, B43_PHY_ADIVRELATED, 0xFF00, 8);
269858619b14SKalle Valo 	}
269958619b14SKalle Valo 	if (phy->rev >= 6)
270058619b14SKalle Valo 		b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
270158619b14SKalle Valo 
270258619b14SKalle Valo 	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
270358619b14SKalle Valo }
270458619b14SKalle Valo 
b43_gphy_op_interf_mitigation(struct b43_wldev * dev,enum b43_interference_mitigation mode)270558619b14SKalle Valo static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev,
270658619b14SKalle Valo 					 enum b43_interference_mitigation mode)
270758619b14SKalle Valo {
270858619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
270958619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
271058619b14SKalle Valo 	int currentmode;
271158619b14SKalle Valo 
271258619b14SKalle Valo 	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
271358619b14SKalle Valo 	if ((phy->rev == 0) || (!phy->gmode))
271458619b14SKalle Valo 		return -ENODEV;
271558619b14SKalle Valo 
271658619b14SKalle Valo 	gphy->aci_wlan_automatic = false;
271758619b14SKalle Valo 	switch (mode) {
271858619b14SKalle Valo 	case B43_INTERFMODE_AUTOWLAN:
271958619b14SKalle Valo 		gphy->aci_wlan_automatic = true;
272058619b14SKalle Valo 		if (gphy->aci_enable)
272158619b14SKalle Valo 			mode = B43_INTERFMODE_MANUALWLAN;
272258619b14SKalle Valo 		else
272358619b14SKalle Valo 			mode = B43_INTERFMODE_NONE;
272458619b14SKalle Valo 		break;
272558619b14SKalle Valo 	case B43_INTERFMODE_NONE:
272658619b14SKalle Valo 	case B43_INTERFMODE_NONWLAN:
272758619b14SKalle Valo 	case B43_INTERFMODE_MANUALWLAN:
272858619b14SKalle Valo 		break;
272958619b14SKalle Valo 	default:
273058619b14SKalle Valo 		return -EINVAL;
273158619b14SKalle Valo 	}
273258619b14SKalle Valo 
273358619b14SKalle Valo 	currentmode = gphy->interfmode;
273458619b14SKalle Valo 	if (currentmode == mode)
273558619b14SKalle Valo 		return 0;
273658619b14SKalle Valo 	if (currentmode != B43_INTERFMODE_NONE)
273758619b14SKalle Valo 		b43_radio_interference_mitigation_disable(dev, currentmode);
273858619b14SKalle Valo 
273958619b14SKalle Valo 	if (mode == B43_INTERFMODE_NONE) {
274058619b14SKalle Valo 		gphy->aci_enable = false;
274158619b14SKalle Valo 		gphy->aci_hw_rssi = false;
274258619b14SKalle Valo 	} else
274358619b14SKalle Valo 		b43_radio_interference_mitigation_enable(dev, mode);
274458619b14SKalle Valo 	gphy->interfmode = mode;
274558619b14SKalle Valo 
274658619b14SKalle Valo 	return 0;
274758619b14SKalle Valo }
274858619b14SKalle Valo 
27492d96c1edSAlexander A. Klimov /* https://bcm-specs.sipsolutions.net/EstimatePowerOut
275058619b14SKalle Valo  * This function converts a TSSI value to dBm in Q5.2
275158619b14SKalle Valo  */
b43_gphy_estimate_power_out(struct b43_wldev * dev,s8 tssi)275258619b14SKalle Valo static s8 b43_gphy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
275358619b14SKalle Valo {
275458619b14SKalle Valo 	struct b43_phy_g *gphy = dev->phy.g;
275558619b14SKalle Valo 	s8 dbm;
275658619b14SKalle Valo 	s32 tmp;
275758619b14SKalle Valo 
275858619b14SKalle Valo 	tmp = (gphy->tgt_idle_tssi - gphy->cur_idle_tssi + tssi);
275958619b14SKalle Valo 	tmp = clamp_val(tmp, 0x00, 0x3F);
276058619b14SKalle Valo 	dbm = gphy->tssi2dbm[tmp];
276158619b14SKalle Valo 
276258619b14SKalle Valo 	return dbm;
276358619b14SKalle Valo }
276458619b14SKalle Valo 
b43_put_attenuation_into_ranges(struct b43_wldev * dev,int * _bbatt,int * _rfatt)276558619b14SKalle Valo static void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
276658619b14SKalle Valo 					    int *_bbatt, int *_rfatt)
276758619b14SKalle Valo {
276858619b14SKalle Valo 	int rfatt = *_rfatt;
276958619b14SKalle Valo 	int bbatt = *_bbatt;
277058619b14SKalle Valo 	struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
277158619b14SKalle Valo 
277258619b14SKalle Valo 	/* Get baseband and radio attenuation values into their permitted ranges.
277358619b14SKalle Valo 	 * Radio attenuation affects power level 4 times as much as baseband. */
277458619b14SKalle Valo 
277558619b14SKalle Valo 	/* Range constants */
277658619b14SKalle Valo 	const int rf_min = lo->rfatt_list.min_val;
277758619b14SKalle Valo 	const int rf_max = lo->rfatt_list.max_val;
277858619b14SKalle Valo 	const int bb_min = lo->bbatt_list.min_val;
277958619b14SKalle Valo 	const int bb_max = lo->bbatt_list.max_val;
278058619b14SKalle Valo 
278158619b14SKalle Valo 	while (1) {
278258619b14SKalle Valo 		if (rfatt > rf_max && bbatt > bb_max - 4)
278358619b14SKalle Valo 			break;	/* Can not get it into ranges */
278458619b14SKalle Valo 		if (rfatt < rf_min && bbatt < bb_min + 4)
278558619b14SKalle Valo 			break;	/* Can not get it into ranges */
278658619b14SKalle Valo 		if (bbatt > bb_max && rfatt > rf_max - 1)
278758619b14SKalle Valo 			break;	/* Can not get it into ranges */
278858619b14SKalle Valo 		if (bbatt < bb_min && rfatt < rf_min + 1)
278958619b14SKalle Valo 			break;	/* Can not get it into ranges */
279058619b14SKalle Valo 
279158619b14SKalle Valo 		if (bbatt > bb_max) {
279258619b14SKalle Valo 			bbatt -= 4;
279358619b14SKalle Valo 			rfatt += 1;
279458619b14SKalle Valo 			continue;
279558619b14SKalle Valo 		}
279658619b14SKalle Valo 		if (bbatt < bb_min) {
279758619b14SKalle Valo 			bbatt += 4;
279858619b14SKalle Valo 			rfatt -= 1;
279958619b14SKalle Valo 			continue;
280058619b14SKalle Valo 		}
280158619b14SKalle Valo 		if (rfatt > rf_max) {
280258619b14SKalle Valo 			rfatt -= 1;
280358619b14SKalle Valo 			bbatt += 4;
280458619b14SKalle Valo 			continue;
280558619b14SKalle Valo 		}
280658619b14SKalle Valo 		if (rfatt < rf_min) {
280758619b14SKalle Valo 			rfatt += 1;
280858619b14SKalle Valo 			bbatt -= 4;
280958619b14SKalle Valo 			continue;
281058619b14SKalle Valo 		}
281158619b14SKalle Valo 		break;
281258619b14SKalle Valo 	}
281358619b14SKalle Valo 
281458619b14SKalle Valo 	*_rfatt = clamp_val(rfatt, rf_min, rf_max);
281558619b14SKalle Valo 	*_bbatt = clamp_val(bbatt, bb_min, bb_max);
281658619b14SKalle Valo }
281758619b14SKalle Valo 
b43_gphy_op_adjust_txpower(struct b43_wldev * dev)281858619b14SKalle Valo static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
281958619b14SKalle Valo {
282058619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
282158619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
282258619b14SKalle Valo 	int rfatt, bbatt;
282358619b14SKalle Valo 	u8 tx_control;
282458619b14SKalle Valo 
282558619b14SKalle Valo 	b43_mac_suspend(dev);
282658619b14SKalle Valo 
282758619b14SKalle Valo 	/* Calculate the new attenuation values. */
282858619b14SKalle Valo 	bbatt = gphy->bbatt.att;
282958619b14SKalle Valo 	bbatt += gphy->bbatt_delta;
283058619b14SKalle Valo 	rfatt = gphy->rfatt.att;
283158619b14SKalle Valo 	rfatt += gphy->rfatt_delta;
283258619b14SKalle Valo 
283358619b14SKalle Valo 	b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
283458619b14SKalle Valo 	tx_control = gphy->tx_control;
283558619b14SKalle Valo 	if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
283658619b14SKalle Valo 		if (rfatt <= 1) {
283758619b14SKalle Valo 			if (tx_control == 0) {
283858619b14SKalle Valo 				tx_control =
283958619b14SKalle Valo 				    B43_TXCTL_PA2DB |
284058619b14SKalle Valo 				    B43_TXCTL_TXMIX;
284158619b14SKalle Valo 				rfatt += 2;
284258619b14SKalle Valo 				bbatt += 2;
284358619b14SKalle Valo 			} else if (dev->dev->bus_sprom->
284458619b14SKalle Valo 				   boardflags_lo &
284558619b14SKalle Valo 				   B43_BFL_PACTRL) {
284658619b14SKalle Valo 				bbatt += 4 * (rfatt - 2);
284758619b14SKalle Valo 				rfatt = 2;
284858619b14SKalle Valo 			}
284958619b14SKalle Valo 		} else if (rfatt > 4 && tx_control) {
285058619b14SKalle Valo 			tx_control = 0;
285158619b14SKalle Valo 			if (bbatt < 3) {
285258619b14SKalle Valo 				rfatt -= 3;
285358619b14SKalle Valo 				bbatt += 2;
285458619b14SKalle Valo 			} else {
285558619b14SKalle Valo 				rfatt -= 2;
285658619b14SKalle Valo 				bbatt -= 2;
285758619b14SKalle Valo 			}
285858619b14SKalle Valo 		}
285958619b14SKalle Valo 	}
286058619b14SKalle Valo 	/* Save the control values */
286158619b14SKalle Valo 	gphy->tx_control = tx_control;
286258619b14SKalle Valo 	b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
286358619b14SKalle Valo 	gphy->rfatt.att = rfatt;
286458619b14SKalle Valo 	gphy->bbatt.att = bbatt;
286558619b14SKalle Valo 
286658619b14SKalle Valo 	if (b43_debug(dev, B43_DBG_XMITPOWER))
286758619b14SKalle Valo 		b43dbg(dev->wl, "Adjusting TX power\n");
286858619b14SKalle Valo 
286958619b14SKalle Valo 	/* Adjust the hardware */
287058619b14SKalle Valo 	b43_phy_lock(dev);
287158619b14SKalle Valo 	b43_radio_lock(dev);
287258619b14SKalle Valo 	b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt,
287358619b14SKalle Valo 			  gphy->tx_control);
287458619b14SKalle Valo 	b43_radio_unlock(dev);
287558619b14SKalle Valo 	b43_phy_unlock(dev);
287658619b14SKalle Valo 
287758619b14SKalle Valo 	b43_mac_enable(dev);
287858619b14SKalle Valo }
287958619b14SKalle Valo 
b43_gphy_op_recalc_txpower(struct b43_wldev * dev,bool ignore_tssi)288058619b14SKalle Valo static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
288158619b14SKalle Valo 							bool ignore_tssi)
288258619b14SKalle Valo {
288358619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
288458619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
288558619b14SKalle Valo 	unsigned int average_tssi;
288658619b14SKalle Valo 	int cck_result, ofdm_result;
288758619b14SKalle Valo 	int estimated_pwr, desired_pwr, pwr_adjust;
288858619b14SKalle Valo 	int rfatt_delta, bbatt_delta;
288958619b14SKalle Valo 	unsigned int max_pwr;
289058619b14SKalle Valo 
289158619b14SKalle Valo 	/* First get the average TSSI */
289258619b14SKalle Valo 	cck_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_CCK);
289358619b14SKalle Valo 	ofdm_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_OFDM_G);
289458619b14SKalle Valo 	if ((cck_result < 0) && (ofdm_result < 0)) {
289558619b14SKalle Valo 		/* No TSSI information available */
289658619b14SKalle Valo 		if (!ignore_tssi)
289758619b14SKalle Valo 			goto no_adjustment_needed;
289858619b14SKalle Valo 		cck_result = 0;
289958619b14SKalle Valo 		ofdm_result = 0;
290058619b14SKalle Valo 	}
290158619b14SKalle Valo 	if (cck_result < 0)
290258619b14SKalle Valo 		average_tssi = ofdm_result;
290358619b14SKalle Valo 	else if (ofdm_result < 0)
290458619b14SKalle Valo 		average_tssi = cck_result;
290558619b14SKalle Valo 	else
290658619b14SKalle Valo 		average_tssi = (cck_result + ofdm_result) / 2;
290758619b14SKalle Valo 	/* Merge the average with the stored value. */
290858619b14SKalle Valo 	if (likely(gphy->average_tssi != 0xFF))
290958619b14SKalle Valo 		average_tssi = (average_tssi + gphy->average_tssi) / 2;
291058619b14SKalle Valo 	gphy->average_tssi = average_tssi;
291158619b14SKalle Valo 	B43_WARN_ON(average_tssi >= B43_TSSI_MAX);
291258619b14SKalle Valo 
291358619b14SKalle Valo 	/* Estimate the TX power emission based on the TSSI */
291458619b14SKalle Valo 	estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi);
291558619b14SKalle Valo 
291658619b14SKalle Valo 	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
291758619b14SKalle Valo 	max_pwr = dev->dev->bus_sprom->maxpwr_bg;
291858619b14SKalle Valo 	if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)
291958619b14SKalle Valo 		max_pwr -= 3; /* minus 0.75 */
292058619b14SKalle Valo 	if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) {
292158619b14SKalle Valo 		b43warn(dev->wl,
292258619b14SKalle Valo 			"Invalid max-TX-power value in SPROM.\n");
292358619b14SKalle Valo 		max_pwr = INT_TO_Q52(20); /* fake it */
292458619b14SKalle Valo 		dev->dev->bus_sprom->maxpwr_bg = max_pwr;
292558619b14SKalle Valo 	}
292658619b14SKalle Valo 
292758619b14SKalle Valo 	/* Get desired power (in Q5.2) */
292858619b14SKalle Valo 	if (phy->desired_txpower < 0)
292958619b14SKalle Valo 		desired_pwr = INT_TO_Q52(0);
293058619b14SKalle Valo 	else
293158619b14SKalle Valo 		desired_pwr = INT_TO_Q52(phy->desired_txpower);
293258619b14SKalle Valo 	/* And limit it. max_pwr already is Q5.2 */
293358619b14SKalle Valo 	desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
293458619b14SKalle Valo 	if (b43_debug(dev, B43_DBG_XMITPOWER)) {
293558619b14SKalle Valo 		b43dbg(dev->wl,
293658619b14SKalle Valo 		       "[TX power]  current = " Q52_FMT
293758619b14SKalle Valo 		       " dBm,  desired = " Q52_FMT
293858619b14SKalle Valo 		       " dBm,  max = " Q52_FMT "\n",
293958619b14SKalle Valo 		       Q52_ARG(estimated_pwr),
294058619b14SKalle Valo 		       Q52_ARG(desired_pwr),
294158619b14SKalle Valo 		       Q52_ARG(max_pwr));
294258619b14SKalle Valo 	}
294358619b14SKalle Valo 
294458619b14SKalle Valo 	/* Calculate the adjustment delta. */
294558619b14SKalle Valo 	pwr_adjust = desired_pwr - estimated_pwr;
294658619b14SKalle Valo 	if (pwr_adjust == 0)
294758619b14SKalle Valo 		goto no_adjustment_needed;
294858619b14SKalle Valo 
294958619b14SKalle Valo 	/* RF attenuation delta. */
295058619b14SKalle Valo 	rfatt_delta = ((pwr_adjust + 7) / 8);
295158619b14SKalle Valo 	/* Lower attenuation => Bigger power output. Negate it. */
295258619b14SKalle Valo 	rfatt_delta = -rfatt_delta;
295358619b14SKalle Valo 
295458619b14SKalle Valo 	/* Baseband attenuation delta. */
295558619b14SKalle Valo 	bbatt_delta = pwr_adjust / 2;
295658619b14SKalle Valo 	/* Lower attenuation => Bigger power output. Negate it. */
295758619b14SKalle Valo 	bbatt_delta = -bbatt_delta;
295858619b14SKalle Valo 	/* RF att affects power level 4 times as much as
295958619b14SKalle Valo 	 * Baseband attennuation. Subtract it. */
296058619b14SKalle Valo 	bbatt_delta -= 4 * rfatt_delta;
296158619b14SKalle Valo 
296258619b14SKalle Valo #if B43_DEBUG
296358619b14SKalle Valo 	if (b43_debug(dev, B43_DBG_XMITPOWER)) {
296458619b14SKalle Valo 		int dbm = pwr_adjust < 0 ? -pwr_adjust : pwr_adjust;
296558619b14SKalle Valo 		b43dbg(dev->wl,
296658619b14SKalle Valo 		       "[TX power deltas]  %s" Q52_FMT " dBm   =>   "
296758619b14SKalle Valo 		       "bbatt-delta = %d,  rfatt-delta = %d\n",
296858619b14SKalle Valo 		       (pwr_adjust < 0 ? "-" : ""), Q52_ARG(dbm),
296958619b14SKalle Valo 		       bbatt_delta, rfatt_delta);
297058619b14SKalle Valo 	}
297158619b14SKalle Valo #endif /* DEBUG */
297258619b14SKalle Valo 
297358619b14SKalle Valo 	/* So do we finally need to adjust something in hardware? */
297458619b14SKalle Valo 	if ((rfatt_delta == 0) && (bbatt_delta == 0))
297558619b14SKalle Valo 		goto no_adjustment_needed;
297658619b14SKalle Valo 
297758619b14SKalle Valo 	/* Save the deltas for later when we adjust the power. */
297858619b14SKalle Valo 	gphy->bbatt_delta = bbatt_delta;
297958619b14SKalle Valo 	gphy->rfatt_delta = rfatt_delta;
298058619b14SKalle Valo 
298158619b14SKalle Valo 	/* We need to adjust the TX power on the device. */
298258619b14SKalle Valo 	return B43_TXPWR_RES_NEED_ADJUST;
298358619b14SKalle Valo 
298458619b14SKalle Valo no_adjustment_needed:
298558619b14SKalle Valo 	return B43_TXPWR_RES_DONE;
298658619b14SKalle Valo }
298758619b14SKalle Valo 
b43_gphy_op_pwork_15sec(struct b43_wldev * dev)298858619b14SKalle Valo static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
298958619b14SKalle Valo {
299058619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
299158619b14SKalle Valo 	struct b43_phy_g *gphy = phy->g;
299258619b14SKalle Valo 
299358619b14SKalle Valo 	b43_mac_suspend(dev);
299458619b14SKalle Valo 	//TODO: update_aci_moving_average
299558619b14SKalle Valo 	if (gphy->aci_enable && gphy->aci_wlan_automatic) {
299658619b14SKalle Valo 		if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
299758619b14SKalle Valo 			if (0 /*TODO: bunch of conditions */ ) {
299858619b14SKalle Valo 				phy->ops->interf_mitigation(dev,
299958619b14SKalle Valo 					B43_INTERFMODE_MANUALWLAN);
300058619b14SKalle Valo 			}
300158619b14SKalle Valo 		} else if (0 /*TODO*/) {
300258619b14SKalle Valo 			   if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
300358619b14SKalle Valo 				phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
300458619b14SKalle Valo 		}
300558619b14SKalle Valo 	} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
300658619b14SKalle Valo 		   phy->rev == 1) {
300758619b14SKalle Valo 		//TODO: implement rev1 workaround
300858619b14SKalle Valo 	}
300958619b14SKalle Valo 	b43_lo_g_maintenance_work(dev);
301058619b14SKalle Valo 	b43_mac_enable(dev);
301158619b14SKalle Valo }
301258619b14SKalle Valo 
b43_gphy_op_pwork_60sec(struct b43_wldev * dev)301358619b14SKalle Valo static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
301458619b14SKalle Valo {
301558619b14SKalle Valo 	struct b43_phy *phy = &dev->phy;
301658619b14SKalle Valo 
301758619b14SKalle Valo 	if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI))
301858619b14SKalle Valo 		return;
301958619b14SKalle Valo 
302058619b14SKalle Valo 	b43_mac_suspend(dev);
302158619b14SKalle Valo 	b43_calc_nrssi_slope(dev);
302258619b14SKalle Valo 	if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
302358619b14SKalle Valo 		u8 old_chan = phy->channel;
302458619b14SKalle Valo 
302558619b14SKalle Valo 		/* VCO Calibration */
302658619b14SKalle Valo 		if (old_chan >= 8)
302758619b14SKalle Valo 			b43_switch_channel(dev, 1);
302858619b14SKalle Valo 		else
302958619b14SKalle Valo 			b43_switch_channel(dev, 13);
303058619b14SKalle Valo 		b43_switch_channel(dev, old_chan);
303158619b14SKalle Valo 	}
303258619b14SKalle Valo 	b43_mac_enable(dev);
303358619b14SKalle Valo }
303458619b14SKalle Valo 
303558619b14SKalle Valo const struct b43_phy_operations b43_phyops_g = {
303658619b14SKalle Valo 	.allocate		= b43_gphy_op_allocate,
303758619b14SKalle Valo 	.free			= b43_gphy_op_free,
303858619b14SKalle Valo 	.prepare_structs	= b43_gphy_op_prepare_structs,
303958619b14SKalle Valo 	.prepare_hardware	= b43_gphy_op_prepare_hardware,
304058619b14SKalle Valo 	.init			= b43_gphy_op_init,
304158619b14SKalle Valo 	.exit			= b43_gphy_op_exit,
304258619b14SKalle Valo 	.phy_read		= b43_gphy_op_read,
304358619b14SKalle Valo 	.phy_write		= b43_gphy_op_write,
304458619b14SKalle Valo 	.radio_read		= b43_gphy_op_radio_read,
304558619b14SKalle Valo 	.radio_write		= b43_gphy_op_radio_write,
304658619b14SKalle Valo 	.supports_hwpctl	= b43_gphy_op_supports_hwpctl,
304758619b14SKalle Valo 	.software_rfkill	= b43_gphy_op_software_rfkill,
304858619b14SKalle Valo 	.switch_analog		= b43_phyop_switch_analog_generic,
304958619b14SKalle Valo 	.switch_channel		= b43_gphy_op_switch_channel,
305058619b14SKalle Valo 	.get_default_chan	= b43_gphy_op_get_default_chan,
305158619b14SKalle Valo 	.set_rx_antenna		= b43_gphy_op_set_rx_antenna,
305258619b14SKalle Valo 	.interf_mitigation	= b43_gphy_op_interf_mitigation,
305358619b14SKalle Valo 	.recalc_txpower		= b43_gphy_op_recalc_txpower,
305458619b14SKalle Valo 	.adjust_txpower		= b43_gphy_op_adjust_txpower,
305558619b14SKalle Valo 	.pwork_15sec		= b43_gphy_op_pwork_15sec,
305658619b14SKalle Valo 	.pwork_60sec		= b43_gphy_op_pwork_60sec,
305758619b14SKalle Valo };
3058