162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci  Broadcom B43legacy wireless driver
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
762306a36Sopenharmony_ci		     Stefano Brivio <stefano.brivio@polimi.it>
862306a36Sopenharmony_ci		     Michael Buesch <m@bues.ch>
962306a36Sopenharmony_ci		     Danny van Dyk <kugelfang@gentoo.org>
1062306a36Sopenharmony_ci     Andreas Jaggi <andreas.jaggi@waterwave.ch>
1162306a36Sopenharmony_ci  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci  Some parts of the code in this file are derived from the ipw2200
1462306a36Sopenharmony_ci  driver  Copyright(c) 2003 - 2004 Intel Corporation.
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci*/
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/delay.h>
2062306a36Sopenharmony_ci#include <linux/pci.h>
2162306a36Sopenharmony_ci#include <linux/sched.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/types.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "b43legacy.h"
2662306a36Sopenharmony_ci#include "phy.h"
2762306a36Sopenharmony_ci#include "main.h"
2862306a36Sopenharmony_ci#include "radio.h"
2962306a36Sopenharmony_ci#include "ilt.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic const s8 b43legacy_tssi2dbm_b_table[] = {
3362306a36Sopenharmony_ci	0x4D, 0x4C, 0x4B, 0x4A,
3462306a36Sopenharmony_ci	0x4A, 0x49, 0x48, 0x47,
3562306a36Sopenharmony_ci	0x47, 0x46, 0x45, 0x45,
3662306a36Sopenharmony_ci	0x44, 0x43, 0x42, 0x42,
3762306a36Sopenharmony_ci	0x41, 0x40, 0x3F, 0x3E,
3862306a36Sopenharmony_ci	0x3D, 0x3C, 0x3B, 0x3A,
3962306a36Sopenharmony_ci	0x39, 0x38, 0x37, 0x36,
4062306a36Sopenharmony_ci	0x35, 0x34, 0x32, 0x31,
4162306a36Sopenharmony_ci	0x30, 0x2F, 0x2D, 0x2C,
4262306a36Sopenharmony_ci	0x2B, 0x29, 0x28, 0x26,
4362306a36Sopenharmony_ci	0x25, 0x23, 0x21, 0x1F,
4462306a36Sopenharmony_ci	0x1D, 0x1A, 0x17, 0x14,
4562306a36Sopenharmony_ci	0x10, 0x0C, 0x06, 0x00,
4662306a36Sopenharmony_ci	  -7,   -7,   -7,   -7,
4762306a36Sopenharmony_ci	  -7,   -7,   -7,   -7,
4862306a36Sopenharmony_ci	  -7,   -7,   -7,   -7,
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const s8 b43legacy_tssi2dbm_g_table[] = {
5262306a36Sopenharmony_ci	 77,  77,  77,  76,
5362306a36Sopenharmony_ci	 76,  76,  75,  75,
5462306a36Sopenharmony_ci	 74,  74,  73,  73,
5562306a36Sopenharmony_ci	 73,  72,  72,  71,
5662306a36Sopenharmony_ci	 71,  70,  70,  69,
5762306a36Sopenharmony_ci	 68,  68,  67,  67,
5862306a36Sopenharmony_ci	 66,  65,  65,  64,
5962306a36Sopenharmony_ci	 63,  63,  62,  61,
6062306a36Sopenharmony_ci	 60,  59,  58,  57,
6162306a36Sopenharmony_ci	 56,  55,  54,  53,
6262306a36Sopenharmony_ci	 52,  50,  49,  47,
6362306a36Sopenharmony_ci	 45,  43,  40,  37,
6462306a36Sopenharmony_ci	 33,  28,  22,  14,
6562306a36Sopenharmony_ci	  5,  -7, -20, -20,
6662306a36Sopenharmony_ci	-20, -20, -20, -20,
6762306a36Sopenharmony_ci	-20, -20, -20, -20,
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void b43legacy_phy_initg(struct b43legacy_wldev *dev);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Lock the PHY registers against concurrent access from the microcode.
7362306a36Sopenharmony_ci * This lock is nonrecursive. */
7462306a36Sopenharmony_civoid b43legacy_phy_lock(struct b43legacy_wldev *dev)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci#if B43legacy_DEBUG
7762306a36Sopenharmony_ci	B43legacy_WARN_ON(dev->phy.phy_locked);
7862306a36Sopenharmony_ci	dev->phy.phy_locked = 1;
7962306a36Sopenharmony_ci#endif
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (dev->dev->id.revision < 3) {
8262306a36Sopenharmony_ci		b43legacy_mac_suspend(dev);
8362306a36Sopenharmony_ci	} else {
8462306a36Sopenharmony_ci		if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
8562306a36Sopenharmony_ci			b43legacy_power_saving_ctl_bits(dev, -1, 1);
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_civoid b43legacy_phy_unlock(struct b43legacy_wldev *dev)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci#if B43legacy_DEBUG
9262306a36Sopenharmony_ci	B43legacy_WARN_ON(!dev->phy.phy_locked);
9362306a36Sopenharmony_ci	dev->phy.phy_locked = 0;
9462306a36Sopenharmony_ci#endif
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (dev->dev->id.revision < 3) {
9762306a36Sopenharmony_ci		b43legacy_mac_enable(dev);
9862306a36Sopenharmony_ci	} else {
9962306a36Sopenharmony_ci		if (!b43legacy_is_mode(dev->wl, NL80211_IFTYPE_AP))
10062306a36Sopenharmony_ci			b43legacy_power_saving_ctl_bits(dev, -1, -1);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciu16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
10762306a36Sopenharmony_ci	return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_civoid b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
11362306a36Sopenharmony_ci	b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_civoid b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	b43legacy_read32(dev, B43legacy_MMIO_MACCTL); /* Dummy read. */
12162306a36Sopenharmony_ci	if (phy->calibrated)
12262306a36Sopenharmony_ci		return;
12362306a36Sopenharmony_ci	if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
12462306a36Sopenharmony_ci		b43legacy_wireless_core_reset(dev, 0);
12562306a36Sopenharmony_ci		b43legacy_phy_initg(dev);
12662306a36Sopenharmony_ci		b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE);
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci	phy->calibrated = 1;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* initialize B PHY power control
13262306a36Sopenharmony_ci * as described in https://bcm-specs.sipsolutions.net/InitPowerControl
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_cistatic void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
13762306a36Sopenharmony_ci	u16 saved_batt = 0;
13862306a36Sopenharmony_ci	u16 saved_ratt = 0;
13962306a36Sopenharmony_ci	u16 saved_txctl1 = 0;
14062306a36Sopenharmony_ci	int must_reset_txpower = 0;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
14362306a36Sopenharmony_ci			  phy->type == B43legacy_PHYTYPE_G));
14462306a36Sopenharmony_ci	if (is_bcm_board_vendor(dev) &&
14562306a36Sopenharmony_ci	    (dev->dev->bus->boardinfo.type == 0x0416))
14662306a36Sopenharmony_ci		return;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0028, 0x8018);
14962306a36Sopenharmony_ci	b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (phy->type == B43legacy_PHYTYPE_G) {
15262306a36Sopenharmony_ci		if (!phy->gmode)
15362306a36Sopenharmony_ci			return;
15462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x047A, 0xC111);
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	if (phy->savedpctlreg != 0xFFFF)
15762306a36Sopenharmony_ci		return;
15862306a36Sopenharmony_ci#ifdef CONFIG_B43LEGACY_DEBUG
15962306a36Sopenharmony_ci	if (phy->manual_txpower_control)
16062306a36Sopenharmony_ci		return;
16162306a36Sopenharmony_ci#endif
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (phy->type == B43legacy_PHYTYPE_B &&
16462306a36Sopenharmony_ci	    phy->rev >= 2 &&
16562306a36Sopenharmony_ci	    phy->radio_ver == 0x2050)
16662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0076,
16762306a36Sopenharmony_ci					b43legacy_radio_read16(dev, 0x0076)
16862306a36Sopenharmony_ci					| 0x0084);
16962306a36Sopenharmony_ci	else {
17062306a36Sopenharmony_ci		saved_batt = phy->bbatt;
17162306a36Sopenharmony_ci		saved_ratt = phy->rfatt;
17262306a36Sopenharmony_ci		saved_txctl1 = phy->txctl1;
17362306a36Sopenharmony_ci		if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8)
17462306a36Sopenharmony_ci		    && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
17562306a36Sopenharmony_ci			b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
17662306a36Sopenharmony_ci		else
17762306a36Sopenharmony_ci			b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0);
17862306a36Sopenharmony_ci		must_reset_txpower = 1;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci	b43legacy_dummy_transmission(dev);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (must_reset_txpower)
18562306a36Sopenharmony_ci		b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt,
18662306a36Sopenharmony_ci					       saved_txctl1);
18762306a36Sopenharmony_ci	else
18862306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev,
18962306a36Sopenharmony_ci					0x0076) & 0xFF7B);
19062306a36Sopenharmony_ci	b43legacy_radio_clear_tssi(dev);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
19662306a36Sopenharmony_ci	u16 offset = 0x0000;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (phy->rev == 1)
19962306a36Sopenharmony_ci		offset = 0x4C00;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	b43legacy_ilt_write(dev, offset, 0x00FE);
20262306a36Sopenharmony_ci	b43legacy_ilt_write(dev, offset + 1, 0x000D);
20362306a36Sopenharmony_ci	b43legacy_ilt_write(dev, offset + 2, 0x0013);
20462306a36Sopenharmony_ci	b43legacy_ilt_write(dev, offset + 3, 0x0019);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (phy->rev == 1) {
20762306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x1800, 0x2710);
20862306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x1801, 0x9B83);
20962306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x1802, 0x9B83);
21062306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x1803, 0x0F8D);
21162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0455, 0x0004);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5)
21562306a36Sopenharmony_ci					  & 0x00FF) | 0x5700);
21662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
21762306a36Sopenharmony_ci					  & 0xFF80) | 0x000F);
21862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
21962306a36Sopenharmony_ci					  & 0xC07F) | 0x2B80);
22062306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C)
22162306a36Sopenharmony_ci					  & 0xF0FF) | 0x0300);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x007A,
22462306a36Sopenharmony_ci				b43legacy_radio_read16(dev, 0x007A)
22562306a36Sopenharmony_ci				| 0x0008);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
22862306a36Sopenharmony_ci			    & 0xFFF0) | 0x0008);
22962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1)
23062306a36Sopenharmony_ci			    & 0xF0FF) | 0x0600);
23162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2)
23262306a36Sopenharmony_ci			    & 0xF0FF) | 0x0700);
23362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
23462306a36Sopenharmony_ci			    & 0xF0FF) | 0x0100);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (phy->rev == 1)
23762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x04A2,
23862306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x04A2)
23962306a36Sopenharmony_ci				    & 0xFFF0) | 0x0007);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
24262306a36Sopenharmony_ci			    & 0xFF00) | 0x001C);
24362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
24462306a36Sopenharmony_ci			    & 0xC0FF) | 0x0200);
24562306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
24662306a36Sopenharmony_ci			    & 0xFF00) | 0x001C);
24762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
24862306a36Sopenharmony_ci			    & 0xFF00) | 0x0020);
24962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
25062306a36Sopenharmony_ci			    & 0xC0FF) | 0x0200);
25162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482)
25262306a36Sopenharmony_ci			    & 0xFF00) | 0x002E);
25362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
25462306a36Sopenharmony_ci			    & 0x00FF) | 0x1A00);
25562306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
25662306a36Sopenharmony_ci			    & 0xFF00) | 0x0028);
25762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
25862306a36Sopenharmony_ci			    & 0x00FF) | 0x2C00);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (phy->rev == 1) {
26162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0430, 0x092B);
26262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x041B,
26362306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x041B)
26462306a36Sopenharmony_ci				    & 0xFFE1) | 0x0002);
26562306a36Sopenharmony_ci	} else {
26662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x041B,
26762306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x041B) & 0xFFE1);
26862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x041F, 0x287A);
26962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0420,
27062306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x0420)
27162306a36Sopenharmony_ci				    & 0xFFF0) | 0x0004);
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (phy->rev > 2) {
27562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0422, 0x287A);
27662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0420,
27762306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x0420)
27862306a36Sopenharmony_ci				    & 0x0FFF) | 0x3000);
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8)
28262306a36Sopenharmony_ci			    & 0x8080) | 0x7874);
28362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x048E, 0x1C00);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (phy->rev == 1) {
28662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x04AB,
28762306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x04AB)
28862306a36Sopenharmony_ci				    & 0xF0FF) | 0x0600);
28962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x048B, 0x005E);
29062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x048C,
29162306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x048C) & 0xFF00)
29262306a36Sopenharmony_ci				    | 0x001E);
29362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x048D, 0x0002);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	b43legacy_ilt_write(dev, offset + 0x0800, 0);
29762306a36Sopenharmony_ci	b43legacy_ilt_write(dev, offset + 0x0801, 7);
29862306a36Sopenharmony_ci	b43legacy_ilt_write(dev, offset + 0x0802, 16);
29962306a36Sopenharmony_ci	b43legacy_ilt_write(dev, offset + 0x0803, 28);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (phy->rev >= 6) {
30262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0426,
30362306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x0426) & 0xFFFC));
30462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0426,
30562306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x0426) & 0xEFFF));
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
31262306a36Sopenharmony_ci	u16 i;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G);
31562306a36Sopenharmony_ci	if (phy->rev == 1) {
31662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0406, 0x4F19);
31762306a36Sopenharmony_ci		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
31862306a36Sopenharmony_ci				    (b43legacy_phy_read(dev,
31962306a36Sopenharmony_ci				    B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340);
32062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x042C, 0x005A);
32162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0427, 0x001A);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++)
32462306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x5800 + i,
32562306a36Sopenharmony_ci					    b43legacy_ilt_finefreqg[i]);
32662306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++)
32762306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x1800 + i,
32862306a36Sopenharmony_ci					    b43legacy_ilt_noiseg1[i]);
32962306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++)
33062306a36Sopenharmony_ci			b43legacy_ilt_write32(dev, 0x2000 + i,
33162306a36Sopenharmony_ci					      b43legacy_ilt_rotor[i]);
33262306a36Sopenharmony_ci	} else {
33362306a36Sopenharmony_ci		/* nrssi values are signed 6-bit values. Why 0x7654 here? */
33462306a36Sopenharmony_ci		b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		if (phy->rev == 2) {
33762306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C0, 0x1861);
33862306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C1, 0x0271);
33962306a36Sopenharmony_ci		} else if (phy->rev > 2) {
34062306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C0, 0x0098);
34162306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C1, 0x0070);
34262306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C9, 0x0080);
34362306a36Sopenharmony_ci		}
34462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev,
34562306a36Sopenharmony_ci				    0x042B) | 0x800);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci		for (i = 0; i < 64; i++)
34862306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x4000 + i, i);
34962306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++)
35062306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x1800 + i,
35162306a36Sopenharmony_ci					    b43legacy_ilt_noiseg2[i]);
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (phy->rev <= 2)
35562306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
35662306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x1400 + i,
35762306a36Sopenharmony_ci					    b43legacy_ilt_noisescaleg1[i]);
35862306a36Sopenharmony_ci	else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200))
35962306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
36062306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x1400 + i,
36162306a36Sopenharmony_ci					    b43legacy_ilt_noisescaleg3[i]);
36262306a36Sopenharmony_ci	else
36362306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
36462306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x1400 + i,
36562306a36Sopenharmony_ci					    b43legacy_ilt_noisescaleg2[i]);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (phy->rev == 2)
36862306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
36962306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x5000 + i,
37062306a36Sopenharmony_ci					    b43legacy_ilt_sigmasqr1[i]);
37162306a36Sopenharmony_ci	else if ((phy->rev > 2) && (phy->rev <= 8))
37262306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
37362306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x5000 + i,
37462306a36Sopenharmony_ci					    b43legacy_ilt_sigmasqr2[i]);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (phy->rev == 1) {
37762306a36Sopenharmony_ci		for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++)
37862306a36Sopenharmony_ci			b43legacy_ilt_write32(dev, 0x2400 + i,
37962306a36Sopenharmony_ci					      b43legacy_ilt_retard[i]);
38062306a36Sopenharmony_ci		for (i = 4; i < 20; i++)
38162306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x5400 + i, 0x0020);
38262306a36Sopenharmony_ci		b43legacy_phy_agcsetup(dev);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		if (is_bcm_board_vendor(dev) &&
38562306a36Sopenharmony_ci		    (dev->dev->bus->boardinfo.type == 0x0416) &&
38662306a36Sopenharmony_ci		    (dev->dev->bus->sprom.board_rev == 0x0017))
38762306a36Sopenharmony_ci			return;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x5001, 0x0002);
39062306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x5002, 0x0001);
39162306a36Sopenharmony_ci	} else {
39262306a36Sopenharmony_ci		for (i = 0; i <= 0x20; i++)
39362306a36Sopenharmony_ci			b43legacy_ilt_write(dev, 0x1000 + i, 0x0820);
39462306a36Sopenharmony_ci		b43legacy_phy_agcsetup(dev);
39562306a36Sopenharmony_ci		b43legacy_phy_read(dev, 0x0400); /* dummy read */
39662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0403, 0x1000);
39762306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x3C02, 0x000F);
39862306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x3C03, 0x0014);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		if (is_bcm_board_vendor(dev) &&
40162306a36Sopenharmony_ci		    (dev->dev->bus->boardinfo.type == 0x0416) &&
40262306a36Sopenharmony_ci		    (dev->dev->bus->sprom.board_rev == 0x0017))
40362306a36Sopenharmony_ci			return;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x0401, 0x0002);
40662306a36Sopenharmony_ci		b43legacy_ilt_write(dev, 0x0402, 0x0001);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/* Initialize the APHY portion of a GPHY. */
41162306a36Sopenharmony_cistatic void b43legacy_phy_inita(struct b43legacy_wldev *dev)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	might_sleep();
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	b43legacy_phy_setupg(dev);
41762306a36Sopenharmony_ci	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL)
41862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x046E, 0x03CF);
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic void b43legacy_phy_initb2(struct b43legacy_wldev *dev)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
42462306a36Sopenharmony_ci	u16 offset;
42562306a36Sopenharmony_ci	int val;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	b43legacy_write16(dev, 0x03EC, 0x3F22);
42862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0020, 0x301C);
42962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0026, 0x0000);
43062306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0030, 0x00C6);
43162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0088, 0x3E00);
43262306a36Sopenharmony_ci	val = 0x3C3D;
43362306a36Sopenharmony_ci	for (offset = 0x0089; offset < 0x00A7; offset++) {
43462306a36Sopenharmony_ci		b43legacy_phy_write(dev, offset, val);
43562306a36Sopenharmony_ci		val -= 0x0202;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x03E4, 0x3000);
43862306a36Sopenharmony_ci	b43legacy_radio_selectchannel(dev, phy->channel, 0);
43962306a36Sopenharmony_ci	if (phy->radio_ver != 0x2050) {
44062306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0075, 0x0080);
44162306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0079, 0x0081);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0050, 0x0020);
44462306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0050, 0x0023);
44562306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050) {
44662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0050, 0x0020);
44762306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005A, 0x0070);
44862306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005B, 0x007B);
44962306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
45062306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007A, 0x000F);
45162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0038, 0x0677);
45262306a36Sopenharmony_ci		b43legacy_radio_init2050(dev);
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0014, 0x0080);
45562306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0032, 0x00CA);
45662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0032, 0x00CC);
45762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0035, 0x07C2);
45862306a36Sopenharmony_ci	b43legacy_phy_lo_b_measure(dev);
45962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0026, 0xCC00);
46062306a36Sopenharmony_ci	if (phy->radio_ver != 0x2050)
46162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0026, 0xCE00);
46262306a36Sopenharmony_ci	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000);
46362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002A, 0x88A3);
46462306a36Sopenharmony_ci	if (phy->radio_ver != 0x2050)
46562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002A, 0x88C2);
46662306a36Sopenharmony_ci	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
46762306a36Sopenharmony_ci	b43legacy_phy_init_pctl(dev);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic void b43legacy_phy_initb4(struct b43legacy_wldev *dev)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
47362306a36Sopenharmony_ci	u16 offset;
47462306a36Sopenharmony_ci	u16 val;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	b43legacy_write16(dev, 0x03EC, 0x3F22);
47762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0020, 0x301C);
47862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0026, 0x0000);
47962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0030, 0x00C6);
48062306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0088, 0x3E00);
48162306a36Sopenharmony_ci	val = 0x3C3D;
48262306a36Sopenharmony_ci	for (offset = 0x0089; offset < 0x00A7; offset++) {
48362306a36Sopenharmony_ci		b43legacy_phy_write(dev, offset, val);
48462306a36Sopenharmony_ci		val -= 0x0202;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x03E4, 0x3000);
48762306a36Sopenharmony_ci	b43legacy_radio_selectchannel(dev, phy->channel, 0);
48862306a36Sopenharmony_ci	if (phy->radio_ver != 0x2050) {
48962306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0075, 0x0080);
49062306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0079, 0x0081);
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0050, 0x0020);
49362306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0050, 0x0023);
49462306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050) {
49562306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0050, 0x0020);
49662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005A, 0x0070);
49762306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005B, 0x007B);
49862306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
49962306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007A, 0x000F);
50062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0038, 0x0677);
50162306a36Sopenharmony_ci		b43legacy_radio_init2050(dev);
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0014, 0x0080);
50462306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0032, 0x00CA);
50562306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050)
50662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0032, 0x00E0);
50762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0035, 0x07C2);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	b43legacy_phy_lo_b_measure(dev);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0026, 0xCC00);
51262306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050)
51362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0026, 0xCE00);
51462306a36Sopenharmony_ci	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100);
51562306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002A, 0x88A3);
51662306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050)
51762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002A, 0x88C2);
51862306a36Sopenharmony_ci	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
51962306a36Sopenharmony_ci	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) {
52062306a36Sopenharmony_ci		b43legacy_calc_nrssi_slope(dev);
52162306a36Sopenharmony_ci		b43legacy_calc_nrssi_threshold(dev);
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci	b43legacy_phy_init_pctl(dev);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic void b43legacy_phy_initb5(struct b43legacy_wldev *dev)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
52962306a36Sopenharmony_ci	u16 offset;
53062306a36Sopenharmony_ci	u16 value;
53162306a36Sopenharmony_ci	u8 old_channel;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (phy->analog == 1)
53462306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007A,
53562306a36Sopenharmony_ci					b43legacy_radio_read16(dev, 0x007A)
53662306a36Sopenharmony_ci					| 0x0050);
53762306a36Sopenharmony_ci	if (!is_bcm_board_vendor(dev) &&
53862306a36Sopenharmony_ci	    (dev->dev->bus->boardinfo.type != 0x0416)) {
53962306a36Sopenharmony_ci		value = 0x2120;
54062306a36Sopenharmony_ci		for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
54162306a36Sopenharmony_ci			b43legacy_phy_write(dev, offset, value);
54262306a36Sopenharmony_ci			value += 0x0202;
54362306a36Sopenharmony_ci		}
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0035,
54662306a36Sopenharmony_ci			    (b43legacy_phy_read(dev, 0x0035) & 0xF0FF)
54762306a36Sopenharmony_ci			    | 0x0700);
54862306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050)
54962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0038, 0x0667);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (phy->gmode) {
55262306a36Sopenharmony_ci		if (phy->radio_ver == 0x2050) {
55362306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x007A,
55462306a36Sopenharmony_ci					b43legacy_radio_read16(dev, 0x007A)
55562306a36Sopenharmony_ci					| 0x0020);
55662306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x0051,
55762306a36Sopenharmony_ci					b43legacy_radio_read16(dev, 0x0051)
55862306a36Sopenharmony_ci					| 0x0004);
55962306a36Sopenharmony_ci		}
56062306a36Sopenharmony_ci		b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802)
56362306a36Sopenharmony_ci				    | 0x0100);
56462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B)
56562306a36Sopenharmony_ci				    | 0x2000);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x001C, 0x186A);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev,
57062306a36Sopenharmony_ci				    0x0013) & 0x00FF) | 0x1900);
57162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev,
57262306a36Sopenharmony_ci				    0x0035) & 0xFFC0) | 0x0064);
57362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
57462306a36Sopenharmony_ci				    0x005D) & 0xFF80) | 0x000A);
57562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x5B, 0x0000);
57662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x5C, 0x0000);
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (dev->bad_frames_preempt)
58062306a36Sopenharmony_ci		b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
58162306a36Sopenharmony_ci				    b43legacy_phy_read(dev,
58262306a36Sopenharmony_ci				    B43legacy_PHY_RADIO_BITFIELD) | (1 << 12));
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (phy->analog == 1) {
58562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0026, 0xCE00);
58662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0021, 0x3763);
58762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0022, 0x1BC3);
58862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0023, 0x06F9);
58962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0024, 0x037E);
59062306a36Sopenharmony_ci	} else
59162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0026, 0xCC00);
59262306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0030, 0x00C6);
59362306a36Sopenharmony_ci	b43legacy_write16(dev, 0x03EC, 0x3F22);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (phy->analog == 1)
59662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0020, 0x3E1C);
59762306a36Sopenharmony_ci	else
59862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0020, 0x301C);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (phy->analog == 0)
60162306a36Sopenharmony_ci		b43legacy_write16(dev, 0x03E4, 0x3000);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	old_channel = (phy->channel == 0xFF) ? 1 : phy->channel;
60462306a36Sopenharmony_ci	/* Force to channel 7, even if not supported. */
60562306a36Sopenharmony_ci	b43legacy_radio_selectchannel(dev, 7, 0);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (phy->radio_ver != 0x2050) {
60862306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0075, 0x0080);
60962306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0079, 0x0081);
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0050, 0x0020);
61362306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0050, 0x0023);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050) {
61662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0050, 0x0020);
61762306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005A, 0x0070);
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x005B, 0x007B);
62162306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x005C, 0x00B0);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev,
62462306a36Sopenharmony_ci				0x007A) | 0x0007);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	b43legacy_radio_selectchannel(dev, old_channel, 0);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0014, 0x0080);
62962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0032, 0x00CA);
63062306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002A, 0x88A3);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050)
63562306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005D, 0x000D);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) &
63862306a36Sopenharmony_ci			  0xFFC0) | 0x0004);
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
64462306a36Sopenharmony_ci	u16 offset;
64562306a36Sopenharmony_ci	u16 val;
64662306a36Sopenharmony_ci	u8 old_channel;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x003E, 0x817A);
64962306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x007A,
65062306a36Sopenharmony_ci				(b43legacy_radio_read16(dev, 0x007A) | 0x0058));
65162306a36Sopenharmony_ci	if (phy->radio_rev == 4 ||
65262306a36Sopenharmony_ci	     phy->radio_rev == 5) {
65362306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0051, 0x0037);
65462306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0052, 0x0070);
65562306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0053, 0x00B3);
65662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0054, 0x009B);
65762306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005A, 0x0088);
65862306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005B, 0x0088);
65962306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005D, 0x0088);
66062306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005E, 0x0088);
66162306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007D, 0x0088);
66262306a36Sopenharmony_ci		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
66362306a36Sopenharmony_ci				      B43legacy_UCODEFLAGS_OFFSET,
66462306a36Sopenharmony_ci				      (b43legacy_shm_read32(dev,
66562306a36Sopenharmony_ci				      B43legacy_SHM_SHARED,
66662306a36Sopenharmony_ci				      B43legacy_UCODEFLAGS_OFFSET)
66762306a36Sopenharmony_ci				      | 0x00000200));
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci	if (phy->radio_rev == 8) {
67062306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0051, 0x0000);
67162306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0052, 0x0040);
67262306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0053, 0x00B7);
67362306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0054, 0x0098);
67462306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005A, 0x0088);
67562306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005B, 0x006B);
67662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005C, 0x000F);
67762306a36Sopenharmony_ci		if (dev->dev->bus->sprom.boardflags_lo & 0x8000) {
67862306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x005D, 0x00FA);
67962306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x005E, 0x00D8);
68062306a36Sopenharmony_ci		} else {
68162306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x005D, 0x00F5);
68262306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x005E, 0x00B8);
68362306a36Sopenharmony_ci		}
68462306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0073, 0x0003);
68562306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007D, 0x00A8);
68662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007C, 0x0001);
68762306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007E, 0x0008);
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci	val = 0x1E1F;
69062306a36Sopenharmony_ci	for (offset = 0x0088; offset < 0x0098; offset++) {
69162306a36Sopenharmony_ci		b43legacy_phy_write(dev, offset, val);
69262306a36Sopenharmony_ci		val -= 0x0202;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci	val = 0x3E3F;
69562306a36Sopenharmony_ci	for (offset = 0x0098; offset < 0x00A8; offset++) {
69662306a36Sopenharmony_ci		b43legacy_phy_write(dev, offset, val);
69762306a36Sopenharmony_ci		val -= 0x0202;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci	val = 0x2120;
70062306a36Sopenharmony_ci	for (offset = 0x00A8; offset < 0x00C8; offset++) {
70162306a36Sopenharmony_ci		b43legacy_phy_write(dev, offset, (val & 0x3F3F));
70262306a36Sopenharmony_ci		val += 0x0202;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci	if (phy->type == B43legacy_PHYTYPE_G) {
70562306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007A,
70662306a36Sopenharmony_ci					b43legacy_radio_read16(dev, 0x007A) |
70762306a36Sopenharmony_ci					0x0020);
70862306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0051,
70962306a36Sopenharmony_ci					b43legacy_radio_read16(dev, 0x0051) |
71062306a36Sopenharmony_ci					0x0004);
71162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0802,
71262306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0802) | 0x0100);
71362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x042B,
71462306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x042B) | 0x2000);
71562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x5B, 0x0000);
71662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x5C, 0x0000);
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	old_channel = phy->channel;
72062306a36Sopenharmony_ci	if (old_channel >= 8)
72162306a36Sopenharmony_ci		b43legacy_radio_selectchannel(dev, 1, 0);
72262306a36Sopenharmony_ci	else
72362306a36Sopenharmony_ci		b43legacy_radio_selectchannel(dev, 13, 0);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0050, 0x0020);
72662306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0050, 0x0023);
72762306a36Sopenharmony_ci	udelay(40);
72862306a36Sopenharmony_ci	if (phy->radio_rev < 6 || phy->radio_rev == 8) {
72962306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007C,
73062306a36Sopenharmony_ci					(b43legacy_radio_read16(dev, 0x007C)
73162306a36Sopenharmony_ci					| 0x0002));
73262306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0050, 0x0020);
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci	if (phy->radio_rev <= 2) {
73562306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0050, 0x0020);
73662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005A, 0x0070);
73762306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005B, 0x007B);
73862306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x007A,
74162306a36Sopenharmony_ci				(b43legacy_radio_read16(dev,
74262306a36Sopenharmony_ci				0x007A) & 0x00F8) | 0x0007);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	b43legacy_radio_selectchannel(dev, old_channel, 0);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0014, 0x0200);
74762306a36Sopenharmony_ci	if (phy->radio_rev >= 6)
74862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002A, 0x88C2);
74962306a36Sopenharmony_ci	else
75062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002A, 0x8AC0);
75162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0038, 0x0668);
75262306a36Sopenharmony_ci	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
75362306a36Sopenharmony_ci	if (phy->radio_rev == 4 || phy->radio_rev == 5)
75462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
75562306a36Sopenharmony_ci				    0x005D) & 0xFF80) | 0x0003);
75662306a36Sopenharmony_ci	if (phy->radio_rev <= 2)
75762306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x005D, 0x000D);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (phy->analog == 4) {
76062306a36Sopenharmony_ci		b43legacy_write16(dev, 0x03E4, 0x0009);
76162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61)
76262306a36Sopenharmony_ci				    & 0xFFF);
76362306a36Sopenharmony_ci	} else
76462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev,
76562306a36Sopenharmony_ci				    0x0002) & 0xFFC0) | 0x0004);
76662306a36Sopenharmony_ci	if (phy->type == B43legacy_PHYTYPE_G)
76762306a36Sopenharmony_ci		b43legacy_write16(dev, 0x03E6, 0x0);
76862306a36Sopenharmony_ci	if (phy->type == B43legacy_PHYTYPE_B) {
76962306a36Sopenharmony_ci		b43legacy_write16(dev, 0x03E6, 0x8140);
77062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0016, 0x0410);
77162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0017, 0x0820);
77262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0062, 0x0007);
77362306a36Sopenharmony_ci		b43legacy_radio_init2050(dev);
77462306a36Sopenharmony_ci		b43legacy_phy_lo_g_measure(dev);
77562306a36Sopenharmony_ci		if (dev->dev->bus->sprom.boardflags_lo &
77662306a36Sopenharmony_ci		    B43legacy_BFL_RSSI) {
77762306a36Sopenharmony_ci			b43legacy_calc_nrssi_slope(dev);
77862306a36Sopenharmony_ci			b43legacy_calc_nrssi_threshold(dev);
77962306a36Sopenharmony_ci		}
78062306a36Sopenharmony_ci		b43legacy_phy_init_pctl(dev);
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
78762306a36Sopenharmony_ci	u16 backup_phy[15] = {0};
78862306a36Sopenharmony_ci	u16 backup_radio[3];
78962306a36Sopenharmony_ci	u16 backup_bband;
79062306a36Sopenharmony_ci	u16 i;
79162306a36Sopenharmony_ci	u16 loop1_cnt;
79262306a36Sopenharmony_ci	u16 loop1_done;
79362306a36Sopenharmony_ci	u16 loop1_omitted;
79462306a36Sopenharmony_ci	u16 loop2_done;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	backup_phy[0] = b43legacy_phy_read(dev, 0x0429);
79762306a36Sopenharmony_ci	backup_phy[1] = b43legacy_phy_read(dev, 0x0001);
79862306a36Sopenharmony_ci	backup_phy[2] = b43legacy_phy_read(dev, 0x0811);
79962306a36Sopenharmony_ci	backup_phy[3] = b43legacy_phy_read(dev, 0x0812);
80062306a36Sopenharmony_ci	if (phy->rev != 1) {
80162306a36Sopenharmony_ci		backup_phy[4] = b43legacy_phy_read(dev, 0x0814);
80262306a36Sopenharmony_ci		backup_phy[5] = b43legacy_phy_read(dev, 0x0815);
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci	backup_phy[6] = b43legacy_phy_read(dev, 0x005A);
80562306a36Sopenharmony_ci	backup_phy[7] = b43legacy_phy_read(dev, 0x0059);
80662306a36Sopenharmony_ci	backup_phy[8] = b43legacy_phy_read(dev, 0x0058);
80762306a36Sopenharmony_ci	backup_phy[9] = b43legacy_phy_read(dev, 0x000A);
80862306a36Sopenharmony_ci	backup_phy[10] = b43legacy_phy_read(dev, 0x0003);
80962306a36Sopenharmony_ci	backup_phy[11] = b43legacy_phy_read(dev, 0x080F);
81062306a36Sopenharmony_ci	backup_phy[12] = b43legacy_phy_read(dev, 0x0810);
81162306a36Sopenharmony_ci	backup_phy[13] = b43legacy_phy_read(dev, 0x002B);
81262306a36Sopenharmony_ci	backup_phy[14] = b43legacy_phy_read(dev, 0x0015);
81362306a36Sopenharmony_ci	b43legacy_phy_read(dev, 0x002D); /* dummy read */
81462306a36Sopenharmony_ci	backup_bband = phy->bbatt;
81562306a36Sopenharmony_ci	backup_radio[0] = b43legacy_radio_read16(dev, 0x0052);
81662306a36Sopenharmony_ci	backup_radio[1] = b43legacy_radio_read16(dev, 0x0043);
81762306a36Sopenharmony_ci	backup_radio[2] = b43legacy_radio_read16(dev, 0x007A);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0429,
82062306a36Sopenharmony_ci			    b43legacy_phy_read(dev, 0x0429) & 0x3FFF);
82162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0001,
82262306a36Sopenharmony_ci			    b43legacy_phy_read(dev, 0x0001) & 0x8000);
82362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0811,
82462306a36Sopenharmony_ci			    b43legacy_phy_read(dev, 0x0811) | 0x0002);
82562306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0812,
82662306a36Sopenharmony_ci			    b43legacy_phy_read(dev, 0x0812) & 0xFFFD);
82762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0811,
82862306a36Sopenharmony_ci			    b43legacy_phy_read(dev, 0x0811) | 0x0001);
82962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0812,
83062306a36Sopenharmony_ci			    b43legacy_phy_read(dev, 0x0812) & 0xFFFE);
83162306a36Sopenharmony_ci	if (phy->rev != 1) {
83262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0814,
83362306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0814) | 0x0001);
83462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0815,
83562306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
83662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0814,
83762306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0814) | 0x0002);
83862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0815,
83962306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0815) & 0xFFFD);
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) |
84262306a36Sopenharmony_ci			    0x000C);
84362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) |
84462306a36Sopenharmony_ci			    0x000C);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811)
84762306a36Sopenharmony_ci			    & 0xFFCF) | 0x0030);
84862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812)
84962306a36Sopenharmony_ci			    & 0xFFCF) | 0x0010);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x005A, 0x0780);
85262306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0059, 0xC810);
85362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0058, 0x000D);
85462306a36Sopenharmony_ci	if (phy->analog == 0)
85562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0003, 0x0122);
85662306a36Sopenharmony_ci	else
85762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x000A,
85862306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x000A)
85962306a36Sopenharmony_ci				    | 0x2000);
86062306a36Sopenharmony_ci	if (phy->rev != 1) {
86162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0814,
86262306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0814) | 0x0004);
86362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0815,
86462306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
86562306a36Sopenharmony_ci	}
86662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0003,
86762306a36Sopenharmony_ci			    (b43legacy_phy_read(dev, 0x0003)
86862306a36Sopenharmony_ci			     & 0xFF9F) | 0x0040);
86962306a36Sopenharmony_ci	if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) {
87062306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0052, 0x0000);
87162306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0043,
87262306a36Sopenharmony_ci					(b43legacy_radio_read16(dev, 0x0043)
87362306a36Sopenharmony_ci					 & 0xFFF0) | 0x0009);
87462306a36Sopenharmony_ci		loop1_cnt = 9;
87562306a36Sopenharmony_ci	} else if (phy->radio_rev == 8) {
87662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0043, 0x000F);
87762306a36Sopenharmony_ci		loop1_cnt = 15;
87862306a36Sopenharmony_ci	} else
87962306a36Sopenharmony_ci		loop1_cnt = 0;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	b43legacy_phy_set_baseband_attenuation(dev, 11);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (phy->rev >= 3)
88462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x080F, 0xC020);
88562306a36Sopenharmony_ci	else
88662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x080F, 0x8020);
88762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0810, 0x0000);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002B,
89062306a36Sopenharmony_ci			    (b43legacy_phy_read(dev, 0x002B)
89162306a36Sopenharmony_ci			     & 0xFFC0) | 0x0001);
89262306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002B,
89362306a36Sopenharmony_ci			    (b43legacy_phy_read(dev, 0x002B)
89462306a36Sopenharmony_ci			     & 0xC0FF) | 0x0800);
89562306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0811,
89662306a36Sopenharmony_ci			    b43legacy_phy_read(dev, 0x0811) | 0x0100);
89762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0812,
89862306a36Sopenharmony_ci			    b43legacy_phy_read(dev, 0x0812) & 0xCFFF);
89962306a36Sopenharmony_ci	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) {
90062306a36Sopenharmony_ci		if (phy->rev >= 7) {
90162306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x0811,
90262306a36Sopenharmony_ci					    b43legacy_phy_read(dev, 0x0811)
90362306a36Sopenharmony_ci					    | 0x0800);
90462306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x0812,
90562306a36Sopenharmony_ci					    b43legacy_phy_read(dev, 0x0812)
90662306a36Sopenharmony_ci					    | 0x8000);
90762306a36Sopenharmony_ci		}
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x007A,
91062306a36Sopenharmony_ci				b43legacy_radio_read16(dev, 0x007A)
91162306a36Sopenharmony_ci				& 0x00F7);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	for (i = 0; i < loop1_cnt; i++) {
91462306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0043, loop1_cnt);
91562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812,
91662306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x0812)
91762306a36Sopenharmony_ci				     & 0xF0FF) | (i << 8));
91862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015,
91962306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x0015)
92062306a36Sopenharmony_ci				     & 0x0FFF) | 0xA000);
92162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015,
92262306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x0015)
92362306a36Sopenharmony_ci				     & 0x0FFF) | 0xF000);
92462306a36Sopenharmony_ci		udelay(20);
92562306a36Sopenharmony_ci		if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
92662306a36Sopenharmony_ci			break;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci	loop1_done = i;
92962306a36Sopenharmony_ci	loop1_omitted = loop1_cnt - loop1_done;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	loop2_done = 0;
93262306a36Sopenharmony_ci	if (loop1_done >= 8) {
93362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812,
93462306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0812)
93562306a36Sopenharmony_ci				    | 0x0030);
93662306a36Sopenharmony_ci		for (i = loop1_done - 8; i < 16; i++) {
93762306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x0812,
93862306a36Sopenharmony_ci					    (b43legacy_phy_read(dev, 0x0812)
93962306a36Sopenharmony_ci					     & 0xF0FF) | (i << 8));
94062306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x0015,
94162306a36Sopenharmony_ci					    (b43legacy_phy_read(dev, 0x0015)
94262306a36Sopenharmony_ci					     & 0x0FFF) | 0xA000);
94362306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x0015,
94462306a36Sopenharmony_ci					    (b43legacy_phy_read(dev, 0x0015)
94562306a36Sopenharmony_ci					     & 0x0FFF) | 0xF000);
94662306a36Sopenharmony_ci			udelay(20);
94762306a36Sopenharmony_ci			if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
94862306a36Sopenharmony_ci				break;
94962306a36Sopenharmony_ci		}
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	if (phy->rev != 1) {
95362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0814, backup_phy[4]);
95462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0815, backup_phy[5]);
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x005A, backup_phy[6]);
95762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0059, backup_phy[7]);
95862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0058, backup_phy[8]);
95962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x000A, backup_phy[9]);
96062306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0003, backup_phy[10]);
96162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x080F, backup_phy[11]);
96262306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0810, backup_phy[12]);
96362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002B, backup_phy[13]);
96462306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0015, backup_phy[14]);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	b43legacy_phy_set_baseband_attenuation(dev, backup_bband);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0052, backup_radio[0]);
96962306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0043, backup_radio[1]);
97062306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x007A, backup_radio[2]);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003);
97362306a36Sopenharmony_ci	udelay(10);
97462306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0811, backup_phy[2]);
97562306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0812, backup_phy[3]);
97662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0429, backup_phy[0]);
97762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0001, backup_phy[1]);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
98062306a36Sopenharmony_ci	phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cistatic void b43legacy_phy_initg(struct b43legacy_wldev *dev)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
98662306a36Sopenharmony_ci	u16 tmp;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	if (phy->rev == 1)
98962306a36Sopenharmony_ci		b43legacy_phy_initb5(dev);
99062306a36Sopenharmony_ci	else
99162306a36Sopenharmony_ci		b43legacy_phy_initb6(dev);
99262306a36Sopenharmony_ci	if (phy->rev >= 2 && phy->gmode)
99362306a36Sopenharmony_ci		b43legacy_phy_inita(dev);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (phy->rev >= 2) {
99662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0814, 0x0000);
99762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0815, 0x0000);
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci	if (phy->rev == 2) {
100062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0811, 0x0000);
100162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, 0x00C0);
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci	if (phy->rev > 5) {
100462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0811, 0x0400);
100562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, 0x00C0);
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci	if (phy->gmode) {
100862306a36Sopenharmony_ci		tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF;
100962306a36Sopenharmony_ci		if (tmp == 3) {
101062306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C2, 0x1816);
101162306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C3, 0x8606);
101262306a36Sopenharmony_ci		}
101362306a36Sopenharmony_ci		if (tmp == 4 || tmp == 5) {
101462306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C2, 0x1816);
101562306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04C3, 0x8006);
101662306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x04CC,
101762306a36Sopenharmony_ci					    (b43legacy_phy_read(dev,
101862306a36Sopenharmony_ci					     0x04CC) & 0x00FF) |
101962306a36Sopenharmony_ci					     0x1F00);
102062306a36Sopenharmony_ci		}
102162306a36Sopenharmony_ci		if (phy->rev >= 2)
102262306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x047E, 0x0078);
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci	if (phy->radio_rev == 8) {
102562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801)
102662306a36Sopenharmony_ci				    | 0x0080);
102762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E)
102862306a36Sopenharmony_ci				    | 0x0004);
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci	if (phy->rev >= 2 && phy->gmode)
103162306a36Sopenharmony_ci		b43legacy_calc_loopback_gain(dev);
103262306a36Sopenharmony_ci	if (phy->radio_rev != 8) {
103362306a36Sopenharmony_ci		if (phy->initval == 0xFFFF)
103462306a36Sopenharmony_ci			phy->initval = b43legacy_radio_init2050(dev);
103562306a36Sopenharmony_ci		else
103662306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x0078, phy->initval);
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci	if (phy->txctl2 == 0xFFFF)
103962306a36Sopenharmony_ci		b43legacy_phy_lo_g_measure(dev);
104062306a36Sopenharmony_ci	else {
104162306a36Sopenharmony_ci		if (phy->radio_ver == 0x2050 && phy->radio_rev == 8)
104262306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x0052,
104362306a36Sopenharmony_ci						(phy->txctl1 << 4) |
104462306a36Sopenharmony_ci						phy->txctl2);
104562306a36Sopenharmony_ci		else
104662306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x0052,
104762306a36Sopenharmony_ci						(b43legacy_radio_read16(dev,
104862306a36Sopenharmony_ci						 0x0052) & 0xFFF0) |
104962306a36Sopenharmony_ci						 phy->txctl1);
105062306a36Sopenharmony_ci		if (phy->rev >= 6)
105162306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x0036,
105262306a36Sopenharmony_ci					    (b43legacy_phy_read(dev, 0x0036)
105362306a36Sopenharmony_ci					     & 0x0FFF) | (phy->txctl2 << 12));
105462306a36Sopenharmony_ci		if (dev->dev->bus->sprom.boardflags_lo &
105562306a36Sopenharmony_ci		    B43legacy_BFL_PACTRL)
105662306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x002E, 0x8075);
105762306a36Sopenharmony_ci		else
105862306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x002E, 0x807F);
105962306a36Sopenharmony_ci		if (phy->rev < 2)
106062306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x002F, 0x0101);
106162306a36Sopenharmony_ci		else
106262306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x002F, 0x0202);
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci	if (phy->gmode) {
106562306a36Sopenharmony_ci		b43legacy_phy_lo_adjust(dev, 0);
106662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x080F, 0x8078);
106762306a36Sopenharmony_ci	}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) {
107062306a36Sopenharmony_ci		/* The specs state to update the NRSSI LT with
107162306a36Sopenharmony_ci		 * the value 0x7FFFFFFF here. I think that is some weird
107262306a36Sopenharmony_ci		 * compiler optimization in the original driver.
107362306a36Sopenharmony_ci		 * Essentially, what we do here is resetting all NRSSI LT
107462306a36Sopenharmony_ci		 * entries to -32 (see the clamp_val() in nrssi_hw_update())
107562306a36Sopenharmony_ci		 */
107662306a36Sopenharmony_ci		b43legacy_nrssi_hw_update(dev, 0xFFFF);
107762306a36Sopenharmony_ci		b43legacy_calc_nrssi_threshold(dev);
107862306a36Sopenharmony_ci	} else if (phy->gmode || phy->rev >= 2) {
107962306a36Sopenharmony_ci		if (phy->nrssi[0] == -1000) {
108062306a36Sopenharmony_ci			B43legacy_WARN_ON(phy->nrssi[1] != -1000);
108162306a36Sopenharmony_ci			b43legacy_calc_nrssi_slope(dev);
108262306a36Sopenharmony_ci		} else {
108362306a36Sopenharmony_ci			B43legacy_WARN_ON(phy->nrssi[1] == -1000);
108462306a36Sopenharmony_ci			b43legacy_calc_nrssi_threshold(dev);
108562306a36Sopenharmony_ci		}
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci	if (phy->radio_rev == 8)
108862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0805, 0x3230);
108962306a36Sopenharmony_ci	b43legacy_phy_init_pctl(dev);
109062306a36Sopenharmony_ci	if (dev->dev->bus->chip_id == 0x4306
109162306a36Sopenharmony_ci	    && dev->dev->bus->chip_package == 2) {
109262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0429,
109362306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x0429) & 0xBFFF);
109462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x04C3,
109562306a36Sopenharmony_ci				    b43legacy_phy_read(dev, 0x04C3) & 0x7FFF);
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	int i;
110262306a36Sopenharmony_ci	u16 ret = 0;
110362306a36Sopenharmony_ci	unsigned long flags;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	local_irq_save(flags);
110662306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
110762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, 0xAFA0);
110862306a36Sopenharmony_ci		udelay(1);
110962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, 0xEFA0);
111062306a36Sopenharmony_ci		udelay(10);
111162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, 0xFFA0);
111262306a36Sopenharmony_ci		udelay(40);
111362306a36Sopenharmony_ci		ret += b43legacy_phy_read(dev, 0x002C);
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci	local_irq_restore(flags);
111662306a36Sopenharmony_ci	cond_resched();
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	return ret;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_civoid b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
112462306a36Sopenharmony_ci	u16 regstack[12] = { 0 };
112562306a36Sopenharmony_ci	u16 mls;
112662306a36Sopenharmony_ci	s16 fval;
112762306a36Sopenharmony_ci	int i;
112862306a36Sopenharmony_ci	int j;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	regstack[0] = b43legacy_phy_read(dev, 0x0015);
113162306a36Sopenharmony_ci	regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	if (phy->radio_ver == 0x2053) {
113462306a36Sopenharmony_ci		regstack[2] = b43legacy_phy_read(dev, 0x000A);
113562306a36Sopenharmony_ci		regstack[3] = b43legacy_phy_read(dev, 0x002A);
113662306a36Sopenharmony_ci		regstack[4] = b43legacy_phy_read(dev, 0x0035);
113762306a36Sopenharmony_ci		regstack[5] = b43legacy_phy_read(dev, 0x0003);
113862306a36Sopenharmony_ci		regstack[6] = b43legacy_phy_read(dev, 0x0001);
113962306a36Sopenharmony_ci		regstack[7] = b43legacy_phy_read(dev, 0x0030);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci		regstack[8] = b43legacy_radio_read16(dev, 0x0043);
114262306a36Sopenharmony_ci		regstack[9] = b43legacy_radio_read16(dev, 0x007A);
114362306a36Sopenharmony_ci		regstack[10] = b43legacy_read16(dev, 0x03EC);
114462306a36Sopenharmony_ci		regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0030, 0x00FF);
114762306a36Sopenharmony_ci		b43legacy_write16(dev, 0x03EC, 0x3F3F);
114862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
114962306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0015, 0xB000);
115262306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002B, 0x0004);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (phy->radio_ver == 0x2053) {
115562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002B, 0x0203);
115662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002A, 0x08A3);
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	phy->minlowsig[0] = 0xFFFF;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
116262306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
116362306a36Sopenharmony_ci		b43legacy_phy_lo_b_r15_loop(dev);
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
116662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
116762306a36Sopenharmony_ci		mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
116862306a36Sopenharmony_ci		if (mls < phy->minlowsig[0]) {
116962306a36Sopenharmony_ci			phy->minlowsig[0] = mls;
117062306a36Sopenharmony_ci			phy->minlowsigpos[0] = i;
117162306a36Sopenharmony_ci		}
117262306a36Sopenharmony_ci	}
117362306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0052, regstack[1]
117462306a36Sopenharmony_ci				| phy->minlowsigpos[0]);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	phy->minlowsig[1] = 0xFFFF;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	for (i = -4; i < 5; i += 2) {
117962306a36Sopenharmony_ci		for (j = -4; j < 5; j += 2) {
118062306a36Sopenharmony_ci			if (j < 0)
118162306a36Sopenharmony_ci				fval = (0x0100 * i) + j + 0x0100;
118262306a36Sopenharmony_ci			else
118362306a36Sopenharmony_ci				fval = (0x0100 * i) + j;
118462306a36Sopenharmony_ci			b43legacy_phy_write(dev, 0x002F, fval);
118562306a36Sopenharmony_ci			mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
118662306a36Sopenharmony_ci			if (mls < phy->minlowsig[1]) {
118762306a36Sopenharmony_ci				phy->minlowsig[1] = mls;
118862306a36Sopenharmony_ci				phy->minlowsigpos[1] = fval;
118962306a36Sopenharmony_ci			}
119062306a36Sopenharmony_ci		}
119162306a36Sopenharmony_ci	}
119262306a36Sopenharmony_ci	phy->minlowsigpos[1] += 0x0101;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
119562306a36Sopenharmony_ci	if (phy->radio_ver == 0x2053) {
119662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x000A, regstack[2]);
119762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002A, regstack[3]);
119862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0035, regstack[4]);
119962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0003, regstack[5]);
120062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0001, regstack[6]);
120162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0030, regstack[7]);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0043, regstack[8]);
120462306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x007A, regstack[9]);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0052,
120762306a36Sopenharmony_ci					(b43legacy_radio_read16(dev, 0x0052)
120862306a36Sopenharmony_ci					& 0x000F) | regstack[11]);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci		b43legacy_write16(dev, 0x03EC, regstack[10]);
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0015, regstack[0]);
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic inline
121662306a36Sopenharmony_ciu16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev,
121762306a36Sopenharmony_ci					u16 control)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
122062306a36Sopenharmony_ci	u16 ret;
122162306a36Sopenharmony_ci	unsigned long flags;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	local_irq_save(flags);
122462306a36Sopenharmony_ci	if (phy->gmode) {
122562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x15, 0xE300);
122662306a36Sopenharmony_ci		control <<= 8;
122762306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812, control | 0x00B0);
122862306a36Sopenharmony_ci		udelay(5);
122962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812, control | 0x00B2);
123062306a36Sopenharmony_ci		udelay(2);
123162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812, control | 0x00B3);
123262306a36Sopenharmony_ci		udelay(4);
123362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, 0xF300);
123462306a36Sopenharmony_ci		udelay(8);
123562306a36Sopenharmony_ci	} else {
123662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, control | 0xEFA0);
123762306a36Sopenharmony_ci		udelay(2);
123862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, control | 0xEFE0);
123962306a36Sopenharmony_ci		udelay(4);
124062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, control | 0xFFE0);
124162306a36Sopenharmony_ci		udelay(8);
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci	ret = b43legacy_phy_read(dev, 0x002D);
124462306a36Sopenharmony_ci	local_irq_restore(flags);
124562306a36Sopenharmony_ci	cond_resched();
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	return ret;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev,
125162306a36Sopenharmony_ci					      u16 control)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	int i;
125462306a36Sopenharmony_ci	u32 ret = 0;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
125762306a36Sopenharmony_ci		ret += b43legacy_phy_lo_g_deviation_subval(dev, control);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	return ret;
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci/* Write the LocalOscillator CONTROL */
126362306a36Sopenharmony_cistatic inline
126462306a36Sopenharmony_civoid b43legacy_lo_write(struct b43legacy_wldev *dev,
126562306a36Sopenharmony_ci			struct b43legacy_lopair *pair)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	u16 value;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	value = (u8)(pair->low);
127062306a36Sopenharmony_ci	value |= ((u8)(pair->high)) << 8;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci#ifdef CONFIG_B43LEGACY_DEBUG
127362306a36Sopenharmony_ci	/* Sanity check. */
127462306a36Sopenharmony_ci	if (pair->low < -8 || pair->low > 8 ||
127562306a36Sopenharmony_ci	    pair->high < -8 || pair->high > 8) {
127662306a36Sopenharmony_ci		b43legacydbg(dev->wl,
127762306a36Sopenharmony_ci		       "WARNING: Writing invalid LOpair "
127862306a36Sopenharmony_ci		       "(low: %d, high: %d)\n",
127962306a36Sopenharmony_ci		       pair->low, pair->high);
128062306a36Sopenharmony_ci		dump_stack();
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci#endif
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value);
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_cistatic inline
128862306a36Sopenharmony_cistruct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev,
128962306a36Sopenharmony_ci					       u16 bbatt,
129062306a36Sopenharmony_ci					       u16 rfatt,
129162306a36Sopenharmony_ci					       u16 tx)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
129462306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	if (bbatt > 6)
129762306a36Sopenharmony_ci		bbatt = 6;
129862306a36Sopenharmony_ci	B43legacy_WARN_ON(rfatt >= 10);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	if (tx == 3)
130162306a36Sopenharmony_ci		return b43legacy_get_lopair(phy, rfatt, bbatt);
130262306a36Sopenharmony_ci	return b43legacy_get_lopair(phy, dict[rfatt], bbatt);
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic inline
130662306a36Sopenharmony_cistruct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	return b43legacy_find_lopair(dev, phy->bbatt,
131162306a36Sopenharmony_ci				     phy->rfatt, phy->txctl1);
131262306a36Sopenharmony_ci}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci/* Adjust B/G LO */
131562306a36Sopenharmony_civoid b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct b43legacy_lopair *pair;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	if (fixed) {
132062306a36Sopenharmony_ci		/* Use fixed values. Only for initialization. */
132162306a36Sopenharmony_ci		pair = b43legacy_find_lopair(dev, 2, 3, 0);
132262306a36Sopenharmony_ci	} else
132362306a36Sopenharmony_ci		pair = b43legacy_current_lopair(dev);
132462306a36Sopenharmony_ci	b43legacy_lo_write(dev, pair);
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_cistatic void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
133062306a36Sopenharmony_ci	u16 txctl2 = 0;
133162306a36Sopenharmony_ci	u16 i;
133262306a36Sopenharmony_ci	u32 smallest;
133362306a36Sopenharmony_ci	u32 tmp;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0052, 0x0000);
133662306a36Sopenharmony_ci	udelay(10);
133762306a36Sopenharmony_ci	smallest = b43legacy_phy_lo_g_singledeviation(dev, 0);
133862306a36Sopenharmony_ci	for (i = 0; i < 16; i++) {
133962306a36Sopenharmony_ci		b43legacy_radio_write16(dev, 0x0052, i);
134062306a36Sopenharmony_ci		udelay(10);
134162306a36Sopenharmony_ci		tmp = b43legacy_phy_lo_g_singledeviation(dev, 0);
134262306a36Sopenharmony_ci		if (tmp < smallest) {
134362306a36Sopenharmony_ci			smallest = tmp;
134462306a36Sopenharmony_ci			txctl2 = i;
134562306a36Sopenharmony_ci		}
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci	phy->txctl2 = txctl2;
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic
135162306a36Sopenharmony_civoid b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev,
135262306a36Sopenharmony_ci			      const struct b43legacy_lopair *in_pair,
135362306a36Sopenharmony_ci			      struct b43legacy_lopair *out_pair,
135462306a36Sopenharmony_ci			      u16 r27)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	static const struct b43legacy_lopair transitions[8] = {
135762306a36Sopenharmony_ci		{ .high =  1,  .low =  1, },
135862306a36Sopenharmony_ci		{ .high =  1,  .low =  0, },
135962306a36Sopenharmony_ci		{ .high =  1,  .low = -1, },
136062306a36Sopenharmony_ci		{ .high =  0,  .low = -1, },
136162306a36Sopenharmony_ci		{ .high = -1,  .low = -1, },
136262306a36Sopenharmony_ci		{ .high = -1,  .low =  0, },
136362306a36Sopenharmony_ci		{ .high = -1,  .low =  1, },
136462306a36Sopenharmony_ci		{ .high =  0,  .low =  1, },
136562306a36Sopenharmony_ci	};
136662306a36Sopenharmony_ci	struct b43legacy_lopair lowest_transition = {
136762306a36Sopenharmony_ci		.high = in_pair->high,
136862306a36Sopenharmony_ci		.low = in_pair->low,
136962306a36Sopenharmony_ci	};
137062306a36Sopenharmony_ci	struct b43legacy_lopair tmp_pair;
137162306a36Sopenharmony_ci	struct b43legacy_lopair transition;
137262306a36Sopenharmony_ci	int i = 12;
137362306a36Sopenharmony_ci	int state = 0;
137462306a36Sopenharmony_ci	int found_lower;
137562306a36Sopenharmony_ci	int j;
137662306a36Sopenharmony_ci	int begin;
137762306a36Sopenharmony_ci	int end;
137862306a36Sopenharmony_ci	u32 lowest_deviation;
137962306a36Sopenharmony_ci	u32 tmp;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	/* Note that in_pair and out_pair can point to the same pair.
138262306a36Sopenharmony_ci	 * Be careful. */
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	b43legacy_lo_write(dev, &lowest_transition);
138562306a36Sopenharmony_ci	lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27);
138662306a36Sopenharmony_ci	do {
138762306a36Sopenharmony_ci		found_lower = 0;
138862306a36Sopenharmony_ci		B43legacy_WARN_ON(!(state >= 0 && state <= 8));
138962306a36Sopenharmony_ci		if (state == 0) {
139062306a36Sopenharmony_ci			begin = 1;
139162306a36Sopenharmony_ci			end = 8;
139262306a36Sopenharmony_ci		} else if (state % 2 == 0) {
139362306a36Sopenharmony_ci			begin = state - 1;
139462306a36Sopenharmony_ci			end = state + 1;
139562306a36Sopenharmony_ci		} else {
139662306a36Sopenharmony_ci			begin = state - 2;
139762306a36Sopenharmony_ci			end = state + 2;
139862306a36Sopenharmony_ci		}
139962306a36Sopenharmony_ci		if (begin < 1)
140062306a36Sopenharmony_ci			begin += 8;
140162306a36Sopenharmony_ci		if (end > 8)
140262306a36Sopenharmony_ci			end -= 8;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci		j = begin;
140562306a36Sopenharmony_ci		tmp_pair.high = lowest_transition.high;
140662306a36Sopenharmony_ci		tmp_pair.low = lowest_transition.low;
140762306a36Sopenharmony_ci		while (1) {
140862306a36Sopenharmony_ci			B43legacy_WARN_ON(!(j >= 1 && j <= 8));
140962306a36Sopenharmony_ci			transition.high = tmp_pair.high +
141062306a36Sopenharmony_ci					  transitions[j - 1].high;
141162306a36Sopenharmony_ci			transition.low = tmp_pair.low + transitions[j - 1].low;
141262306a36Sopenharmony_ci			if ((abs(transition.low) < 9)
141362306a36Sopenharmony_ci			     && (abs(transition.high) < 9)) {
141462306a36Sopenharmony_ci				b43legacy_lo_write(dev, &transition);
141562306a36Sopenharmony_ci				tmp = b43legacy_phy_lo_g_singledeviation(dev,
141662306a36Sopenharmony_ci								       r27);
141762306a36Sopenharmony_ci				if (tmp < lowest_deviation) {
141862306a36Sopenharmony_ci					lowest_deviation = tmp;
141962306a36Sopenharmony_ci					state = j;
142062306a36Sopenharmony_ci					found_lower = 1;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci					lowest_transition.high =
142362306a36Sopenharmony_ci								transition.high;
142462306a36Sopenharmony_ci					lowest_transition.low = transition.low;
142562306a36Sopenharmony_ci				}
142662306a36Sopenharmony_ci			}
142762306a36Sopenharmony_ci			if (j == end)
142862306a36Sopenharmony_ci				break;
142962306a36Sopenharmony_ci			if (j == 8)
143062306a36Sopenharmony_ci				j = 1;
143162306a36Sopenharmony_ci			else
143262306a36Sopenharmony_ci				j++;
143362306a36Sopenharmony_ci		}
143462306a36Sopenharmony_ci	} while (i-- && found_lower);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	out_pair->high = lowest_transition.high;
143762306a36Sopenharmony_ci	out_pair->low = lowest_transition.low;
143862306a36Sopenharmony_ci}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci/* Set the baseband attenuation value on chip. */
144162306a36Sopenharmony_civoid b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
144262306a36Sopenharmony_ci					    u16 bbatt)
144362306a36Sopenharmony_ci{
144462306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
144562306a36Sopenharmony_ci	u16 value;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	if (phy->analog == 0) {
144862306a36Sopenharmony_ci		value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0);
144962306a36Sopenharmony_ci		value |= (bbatt & 0x000F);
145062306a36Sopenharmony_ci		b43legacy_write16(dev, 0x03E6, value);
145162306a36Sopenharmony_ci		return;
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	if (phy->analog > 1) {
145562306a36Sopenharmony_ci		value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3;
145662306a36Sopenharmony_ci		value |= (bbatt << 2) & 0x003C;
145762306a36Sopenharmony_ci	} else {
145862306a36Sopenharmony_ci		value = b43legacy_phy_read(dev, 0x0060) & 0xFF87;
145962306a36Sopenharmony_ci		value |= (bbatt << 3) & 0x0078;
146062306a36Sopenharmony_ci	}
146162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0060, value);
146262306a36Sopenharmony_ci}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci/* https://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
146562306a36Sopenharmony_civoid b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev)
146662306a36Sopenharmony_ci{
146762306a36Sopenharmony_ci	static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
146862306a36Sopenharmony_ci	const int is_initializing = (b43legacy_status(dev)
146962306a36Sopenharmony_ci				     < B43legacy_STAT_STARTED);
147062306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
147162306a36Sopenharmony_ci	u16 h;
147262306a36Sopenharmony_ci	u16 i;
147362306a36Sopenharmony_ci	u16 oldi = 0;
147462306a36Sopenharmony_ci	u16 j;
147562306a36Sopenharmony_ci	struct b43legacy_lopair control;
147662306a36Sopenharmony_ci	struct b43legacy_lopair *tmp_control;
147762306a36Sopenharmony_ci	u16 tmp;
147862306a36Sopenharmony_ci	u16 regstack[16] = { 0 };
147962306a36Sopenharmony_ci	u8 oldchannel;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	/* XXX: What are these? */
148262306a36Sopenharmony_ci	u8 r27 = 0;
148362306a36Sopenharmony_ci	u16 r31;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	oldchannel = phy->channel;
148662306a36Sopenharmony_ci	/* Setup */
148762306a36Sopenharmony_ci	if (phy->gmode) {
148862306a36Sopenharmony_ci		regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS);
148962306a36Sopenharmony_ci		regstack[1] = b43legacy_phy_read(dev, 0x0802);
149062306a36Sopenharmony_ci		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
149162306a36Sopenharmony_ci				    & 0x7FFF);
149262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci	regstack[3] = b43legacy_read16(dev, 0x03E2);
149562306a36Sopenharmony_ci	b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000);
149662306a36Sopenharmony_ci	regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
149762306a36Sopenharmony_ci	regstack[5] = b43legacy_phy_read(dev, 0x15);
149862306a36Sopenharmony_ci	regstack[6] = b43legacy_phy_read(dev, 0x2A);
149962306a36Sopenharmony_ci	regstack[7] = b43legacy_phy_read(dev, 0x35);
150062306a36Sopenharmony_ci	regstack[8] = b43legacy_phy_read(dev, 0x60);
150162306a36Sopenharmony_ci	regstack[9] = b43legacy_radio_read16(dev, 0x43);
150262306a36Sopenharmony_ci	regstack[10] = b43legacy_radio_read16(dev, 0x7A);
150362306a36Sopenharmony_ci	regstack[11] = b43legacy_radio_read16(dev, 0x52);
150462306a36Sopenharmony_ci	if (phy->gmode) {
150562306a36Sopenharmony_ci		regstack[12] = b43legacy_phy_read(dev, 0x0811);
150662306a36Sopenharmony_ci		regstack[13] = b43legacy_phy_read(dev, 0x0812);
150762306a36Sopenharmony_ci		regstack[14] = b43legacy_phy_read(dev, 0x0814);
150862306a36Sopenharmony_ci		regstack[15] = b43legacy_phy_read(dev, 0x0815);
150962306a36Sopenharmony_ci	}
151062306a36Sopenharmony_ci	b43legacy_radio_selectchannel(dev, 6, 0);
151162306a36Sopenharmony_ci	if (phy->gmode) {
151262306a36Sopenharmony_ci		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
151362306a36Sopenharmony_ci				    & 0x7FFF);
151462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
151562306a36Sopenharmony_ci		b43legacy_dummy_transmission(dev);
151662306a36Sopenharmony_ci	}
151762306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0043, 0x0006);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	b43legacy_phy_set_baseband_attenuation(dev, 2);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000);
152262306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002E, 0x007F);
152362306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x080F, 0x0078);
152462306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7));
152562306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0);
152662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002B, 0x0203);
152762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002A, 0x08A3);
152862306a36Sopenharmony_ci	if (phy->gmode) {
152962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003);
153062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC);
153162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0811, 0x01B3);
153262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812, 0x00B2);
153362306a36Sopenharmony_ci	}
153462306a36Sopenharmony_ci	if (is_initializing)
153562306a36Sopenharmony_ci		b43legacy_phy_lo_g_measure_txctl2(dev);
153662306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x080F, 0x8078);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	/* Measure */
153962306a36Sopenharmony_ci	control.low = 0;
154062306a36Sopenharmony_ci	control.high = 0;
154162306a36Sopenharmony_ci	for (h = 0; h < 10; h++) {
154262306a36Sopenharmony_ci		/* Loop over each possible RadioAttenuation (0-9) */
154362306a36Sopenharmony_ci		i = pairorder[h];
154462306a36Sopenharmony_ci		if (is_initializing) {
154562306a36Sopenharmony_ci			if (i == 3) {
154662306a36Sopenharmony_ci				control.low = 0;
154762306a36Sopenharmony_ci				control.high = 0;
154862306a36Sopenharmony_ci			} else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
154962306a36Sopenharmony_ci				  ((i % 2 == 0) && (oldi % 2 == 0))) {
155062306a36Sopenharmony_ci				tmp_control = b43legacy_get_lopair(phy, oldi,
155162306a36Sopenharmony_ci								   0);
155262306a36Sopenharmony_ci				memcpy(&control, tmp_control, sizeof(control));
155362306a36Sopenharmony_ci			} else {
155462306a36Sopenharmony_ci				tmp_control = b43legacy_get_lopair(phy, 3, 0);
155562306a36Sopenharmony_ci				memcpy(&control, tmp_control, sizeof(control));
155662306a36Sopenharmony_ci			}
155762306a36Sopenharmony_ci		}
155862306a36Sopenharmony_ci		/* Loop over each possible BasebandAttenuation/2 */
155962306a36Sopenharmony_ci		for (j = 0; j < 4; j++) {
156062306a36Sopenharmony_ci			if (is_initializing) {
156162306a36Sopenharmony_ci				tmp = i * 2 + j;
156262306a36Sopenharmony_ci				r27 = 0;
156362306a36Sopenharmony_ci				r31 = 0;
156462306a36Sopenharmony_ci				if (tmp > 14) {
156562306a36Sopenharmony_ci					r31 = 1;
156662306a36Sopenharmony_ci					if (tmp > 17)
156762306a36Sopenharmony_ci						r27 = 1;
156862306a36Sopenharmony_ci					if (tmp > 19)
156962306a36Sopenharmony_ci						r27 = 2;
157062306a36Sopenharmony_ci				}
157162306a36Sopenharmony_ci			} else {
157262306a36Sopenharmony_ci				tmp_control = b43legacy_get_lopair(phy, i,
157362306a36Sopenharmony_ci								   j * 2);
157462306a36Sopenharmony_ci				if (!tmp_control->used)
157562306a36Sopenharmony_ci					continue;
157662306a36Sopenharmony_ci				memcpy(&control, tmp_control, sizeof(control));
157762306a36Sopenharmony_ci				r27 = 3;
157862306a36Sopenharmony_ci				r31 = 0;
157962306a36Sopenharmony_ci			}
158062306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x43, i);
158162306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x52, phy->txctl2);
158262306a36Sopenharmony_ci			udelay(10);
158362306a36Sopenharmony_ci			cond_resched();
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci			b43legacy_phy_set_baseband_attenuation(dev, j * 2);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci			tmp = (regstack[10] & 0xFFF0);
158862306a36Sopenharmony_ci			if (r31)
158962306a36Sopenharmony_ci				tmp |= 0x0008;
159062306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x007A, tmp);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci			tmp_control = b43legacy_get_lopair(phy, i, j * 2);
159362306a36Sopenharmony_ci			b43legacy_phy_lo_g_state(dev, &control, tmp_control,
159462306a36Sopenharmony_ci						 r27);
159562306a36Sopenharmony_ci		}
159662306a36Sopenharmony_ci		oldi = i;
159762306a36Sopenharmony_ci	}
159862306a36Sopenharmony_ci	/* Loop over each possible RadioAttenuation (10-13) */
159962306a36Sopenharmony_ci	for (i = 10; i < 14; i++) {
160062306a36Sopenharmony_ci		/* Loop over each possible BasebandAttenuation/2 */
160162306a36Sopenharmony_ci		for (j = 0; j < 4; j++) {
160262306a36Sopenharmony_ci			if (is_initializing) {
160362306a36Sopenharmony_ci				tmp_control = b43legacy_get_lopair(phy, i - 9,
160462306a36Sopenharmony_ci								 j * 2);
160562306a36Sopenharmony_ci				memcpy(&control, tmp_control, sizeof(control));
160662306a36Sopenharmony_ci				/* FIXME: The next line is wrong, as the
160762306a36Sopenharmony_ci				 * following if statement can never trigger. */
160862306a36Sopenharmony_ci				tmp = (i - 9) * 2 + j - 5;
160962306a36Sopenharmony_ci				r27 = 0;
161062306a36Sopenharmony_ci				r31 = 0;
161162306a36Sopenharmony_ci				if (tmp > 14) {
161262306a36Sopenharmony_ci					r31 = 1;
161362306a36Sopenharmony_ci					if (tmp > 17)
161462306a36Sopenharmony_ci						r27 = 1;
161562306a36Sopenharmony_ci					if (tmp > 19)
161662306a36Sopenharmony_ci						r27 = 2;
161762306a36Sopenharmony_ci				}
161862306a36Sopenharmony_ci			} else {
161962306a36Sopenharmony_ci				tmp_control = b43legacy_get_lopair(phy, i - 9,
162062306a36Sopenharmony_ci								   j * 2);
162162306a36Sopenharmony_ci				if (!tmp_control->used)
162262306a36Sopenharmony_ci					continue;
162362306a36Sopenharmony_ci				memcpy(&control, tmp_control, sizeof(control));
162462306a36Sopenharmony_ci				r27 = 3;
162562306a36Sopenharmony_ci				r31 = 0;
162662306a36Sopenharmony_ci			}
162762306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x43, i - 9);
162862306a36Sopenharmony_ci			/* FIXME: shouldn't txctl1 be zero in the next line
162962306a36Sopenharmony_ci			 * and 3 in the loop above? */
163062306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x52,
163162306a36Sopenharmony_ci					      phy->txctl2
163262306a36Sopenharmony_ci					      | (3/*txctl1*/ << 4));
163362306a36Sopenharmony_ci			udelay(10);
163462306a36Sopenharmony_ci			cond_resched();
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci			b43legacy_phy_set_baseband_attenuation(dev, j * 2);
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci			tmp = (regstack[10] & 0xFFF0);
163962306a36Sopenharmony_ci			if (r31)
164062306a36Sopenharmony_ci				tmp |= 0x0008;
164162306a36Sopenharmony_ci			b43legacy_radio_write16(dev, 0x7A, tmp);
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci			tmp_control = b43legacy_get_lopair(phy, i, j * 2);
164462306a36Sopenharmony_ci			b43legacy_phy_lo_g_state(dev, &control, tmp_control,
164562306a36Sopenharmony_ci						 r27);
164662306a36Sopenharmony_ci		}
164762306a36Sopenharmony_ci	}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	/* Restoration */
165062306a36Sopenharmony_ci	if (phy->gmode) {
165162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, 0xE300);
165262306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0);
165362306a36Sopenharmony_ci		udelay(5);
165462306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2);
165562306a36Sopenharmony_ci		udelay(2);
165662306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3);
165762306a36Sopenharmony_ci		cond_resched();
165862306a36Sopenharmony_ci	} else
165962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0);
166062306a36Sopenharmony_ci	b43legacy_phy_lo_adjust(dev, is_initializing);
166162306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002E, 0x807F);
166262306a36Sopenharmony_ci	if (phy->gmode)
166362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002F, 0x0202);
166462306a36Sopenharmony_ci	else
166562306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x002F, 0x0101);
166662306a36Sopenharmony_ci	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]);
166762306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0015, regstack[5]);
166862306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x002A, regstack[6]);
166962306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0035, regstack[7]);
167062306a36Sopenharmony_ci	b43legacy_phy_write(dev, 0x0060, regstack[8]);
167162306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x0043, regstack[9]);
167262306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x007A, regstack[10]);
167362306a36Sopenharmony_ci	regstack[11] &= 0x00F0;
167462306a36Sopenharmony_ci	regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F);
167562306a36Sopenharmony_ci	b43legacy_radio_write16(dev, 0x52, regstack[11]);
167662306a36Sopenharmony_ci	b43legacy_write16(dev, 0x03E2, regstack[3]);
167762306a36Sopenharmony_ci	if (phy->gmode) {
167862306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0811, regstack[12]);
167962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0812, regstack[13]);
168062306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0814, regstack[14]);
168162306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0815, regstack[15]);
168262306a36Sopenharmony_ci		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]);
168362306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x0802, regstack[1]);
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci	b43legacy_radio_selectchannel(dev, oldchannel, 1);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci#ifdef CONFIG_B43LEGACY_DEBUG
168862306a36Sopenharmony_ci	{
168962306a36Sopenharmony_ci		/* Sanity check for all lopairs. */
169062306a36Sopenharmony_ci		for (i = 0; i < B43legacy_LO_COUNT; i++) {
169162306a36Sopenharmony_ci			tmp_control = phy->_lo_pairs + i;
169262306a36Sopenharmony_ci			if (tmp_control->low < -8 || tmp_control->low > 8 ||
169362306a36Sopenharmony_ci			    tmp_control->high < -8 || tmp_control->high > 8)
169462306a36Sopenharmony_ci				b43legacywarn(dev->wl,
169562306a36Sopenharmony_ci				       "WARNING: Invalid LOpair (low: %d, high:"
169662306a36Sopenharmony_ci				       " %d, index: %d)\n",
169762306a36Sopenharmony_ci				       tmp_control->low, tmp_control->high, i);
169862306a36Sopenharmony_ci		}
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci#endif /* CONFIG_B43LEGACY_DEBUG */
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cistatic
170462306a36Sopenharmony_civoid b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	struct b43legacy_lopair *pair;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	pair = b43legacy_current_lopair(dev);
170962306a36Sopenharmony_ci	pair->used = 1;
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_civoid b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
171562306a36Sopenharmony_ci	struct b43legacy_lopair *pair;
171662306a36Sopenharmony_ci	int i;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	for (i = 0; i < B43legacy_LO_COUNT; i++) {
171962306a36Sopenharmony_ci		pair = phy->_lo_pairs + i;
172062306a36Sopenharmony_ci		pair->used = 0;
172162306a36Sopenharmony_ci	}
172262306a36Sopenharmony_ci}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci/* https://bcm-specs.sipsolutions.net/EstimatePowerOut
172562306a36Sopenharmony_ci * This function converts a TSSI value to dBm in Q5.2
172662306a36Sopenharmony_ci */
172762306a36Sopenharmony_cistatic s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
172862306a36Sopenharmony_ci{
172962306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
173062306a36Sopenharmony_ci	s8 dbm = 0;
173162306a36Sopenharmony_ci	s32 tmp;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	tmp = phy->idle_tssi;
173462306a36Sopenharmony_ci	tmp += tssi;
173562306a36Sopenharmony_ci	tmp -= phy->savedpctlreg;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	switch (phy->type) {
173862306a36Sopenharmony_ci	case B43legacy_PHYTYPE_B:
173962306a36Sopenharmony_ci	case B43legacy_PHYTYPE_G:
174062306a36Sopenharmony_ci		tmp = clamp_val(tmp, 0x00, 0x3F);
174162306a36Sopenharmony_ci		dbm = phy->tssi2dbm[tmp];
174262306a36Sopenharmony_ci		break;
174362306a36Sopenharmony_ci	default:
174462306a36Sopenharmony_ci		B43legacy_BUG_ON(1);
174562306a36Sopenharmony_ci	}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	return dbm;
174862306a36Sopenharmony_ci}
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci/* https://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
175162306a36Sopenharmony_civoid b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
175262306a36Sopenharmony_ci{
175362306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
175462306a36Sopenharmony_ci	u16 tmp;
175562306a36Sopenharmony_ci	u16 txpower;
175662306a36Sopenharmony_ci	s8 v0;
175762306a36Sopenharmony_ci	s8 v1;
175862306a36Sopenharmony_ci	s8 v2;
175962306a36Sopenharmony_ci	s8 v3;
176062306a36Sopenharmony_ci	s8 average;
176162306a36Sopenharmony_ci	int max_pwr;
176262306a36Sopenharmony_ci	s16 desired_pwr;
176362306a36Sopenharmony_ci	s16 estimated_pwr;
176462306a36Sopenharmony_ci	s16 pwr_adjust;
176562306a36Sopenharmony_ci	s16 radio_att_delta;
176662306a36Sopenharmony_ci	s16 baseband_att_delta;
176762306a36Sopenharmony_ci	s16 radio_attenuation;
176862306a36Sopenharmony_ci	s16 baseband_attenuation;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	if (phy->savedpctlreg == 0xFFFF)
177162306a36Sopenharmony_ci		return;
177262306a36Sopenharmony_ci	if ((dev->dev->bus->boardinfo.type == 0x0416) &&
177362306a36Sopenharmony_ci	    is_bcm_board_vendor(dev))
177462306a36Sopenharmony_ci		return;
177562306a36Sopenharmony_ci#ifdef CONFIG_B43LEGACY_DEBUG
177662306a36Sopenharmony_ci	if (phy->manual_txpower_control)
177762306a36Sopenharmony_ci		return;
177862306a36Sopenharmony_ci#endif
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
178162306a36Sopenharmony_ci			 phy->type == B43legacy_PHYTYPE_G));
178262306a36Sopenharmony_ci	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058);
178362306a36Sopenharmony_ci	v0 = (s8)(tmp & 0x00FF);
178462306a36Sopenharmony_ci	v1 = (s8)((tmp & 0xFF00) >> 8);
178562306a36Sopenharmony_ci	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A);
178662306a36Sopenharmony_ci	v2 = (s8)(tmp & 0x00FF);
178762306a36Sopenharmony_ci	v3 = (s8)((tmp & 0xFF00) >> 8);
178862306a36Sopenharmony_ci	tmp = 0;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
179162306a36Sopenharmony_ci		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
179262306a36Sopenharmony_ci					 0x0070);
179362306a36Sopenharmony_ci		v0 = (s8)(tmp & 0x00FF);
179462306a36Sopenharmony_ci		v1 = (s8)((tmp & 0xFF00) >> 8);
179562306a36Sopenharmony_ci		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
179662306a36Sopenharmony_ci					 0x0072);
179762306a36Sopenharmony_ci		v2 = (s8)(tmp & 0x00FF);
179862306a36Sopenharmony_ci		v3 = (s8)((tmp & 0xFF00) >> 8);
179962306a36Sopenharmony_ci		if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
180062306a36Sopenharmony_ci			return;
180162306a36Sopenharmony_ci		v0 = (v0 + 0x20) & 0x3F;
180262306a36Sopenharmony_ci		v1 = (v1 + 0x20) & 0x3F;
180362306a36Sopenharmony_ci		v2 = (v2 + 0x20) & 0x3F;
180462306a36Sopenharmony_ci		v3 = (v3 + 0x20) & 0x3F;
180562306a36Sopenharmony_ci		tmp = 1;
180662306a36Sopenharmony_ci	}
180762306a36Sopenharmony_ci	b43legacy_radio_clear_tssi(dev);
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	average = (v0 + v1 + v2 + v3 + 2) / 4;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E)
181262306a36Sopenharmony_ci	    & 0x8))
181362306a36Sopenharmony_ci		average -= 13;
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	estimated_pwr = b43legacy_phy_estimate_power_out(dev, average);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	max_pwr = dev->dev->bus->sprom.maxpwr_bg;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	if ((dev->dev->bus->sprom.boardflags_lo
182062306a36Sopenharmony_ci	     & B43legacy_BFL_PACTRL) &&
182162306a36Sopenharmony_ci	    (phy->type == B43legacy_PHYTYPE_G))
182262306a36Sopenharmony_ci		max_pwr -= 0x3;
182362306a36Sopenharmony_ci	if (unlikely(max_pwr <= 0)) {
182462306a36Sopenharmony_ci		b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM."
182562306a36Sopenharmony_ci			"\n");
182662306a36Sopenharmony_ci		max_pwr = 74; /* fake it */
182762306a36Sopenharmony_ci		dev->dev->bus->sprom.maxpwr_bg = max_pwr;
182862306a36Sopenharmony_ci	}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	/* Use regulatory information to get the maximum power.
183162306a36Sopenharmony_ci	 * In the absence of such data from mac80211, we will use 20 dBm, which
183262306a36Sopenharmony_ci	 * is the value for the EU, US, Canada, and most of the world.
183362306a36Sopenharmony_ci	 * The regulatory maximum is reduced by the antenna gain (from sprom)
183462306a36Sopenharmony_ci	 * and 1.5 dBm (a safety factor??). The result is in Q5.2 format
183562306a36Sopenharmony_ci	 * which accounts for the factor of 4 */
183662306a36Sopenharmony_ci#define REG_MAX_PWR 20
183762306a36Sopenharmony_ci	max_pwr = min(REG_MAX_PWR * 4
183862306a36Sopenharmony_ci		      - dev->dev->bus->sprom.antenna_gain.a0
183962306a36Sopenharmony_ci		      - 0x6, max_pwr);
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	/* find the desired power in Q5.2 - power_level is in dBm
184262306a36Sopenharmony_ci	 * and limit it - max_pwr is already in Q5.2 */
184362306a36Sopenharmony_ci	desired_pwr = clamp_val(phy->power_level << 2, 0, max_pwr);
184462306a36Sopenharmony_ci	if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
184562306a36Sopenharmony_ci		b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
184662306a36Sopenharmony_ci		       " dBm, Desired TX power output: " Q52_FMT
184762306a36Sopenharmony_ci		       " dBm\n", Q52_ARG(estimated_pwr),
184862306a36Sopenharmony_ci		       Q52_ARG(desired_pwr));
184962306a36Sopenharmony_ci	/* Check if we need to adjust the current power. The factor of 2 is
185062306a36Sopenharmony_ci	 * for damping */
185162306a36Sopenharmony_ci	pwr_adjust = (desired_pwr - estimated_pwr) / 2;
185262306a36Sopenharmony_ci	/* RF attenuation delta
185362306a36Sopenharmony_ci	 * The minus sign is because lower attenuation => more power */
185462306a36Sopenharmony_ci	radio_att_delta = -(pwr_adjust + 7) >> 3;
185562306a36Sopenharmony_ci	/* Baseband attenuation delta */
185662306a36Sopenharmony_ci	baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
185762306a36Sopenharmony_ci	/* Do we need to adjust anything? */
185862306a36Sopenharmony_ci	if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
185962306a36Sopenharmony_ci		b43legacy_phy_lo_mark_current_used(dev);
186062306a36Sopenharmony_ci		return;
186162306a36Sopenharmony_ci	}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	/* Calculate the new attenuation values. */
186462306a36Sopenharmony_ci	baseband_attenuation = phy->bbatt;
186562306a36Sopenharmony_ci	baseband_attenuation += baseband_att_delta;
186662306a36Sopenharmony_ci	radio_attenuation = phy->rfatt;
186762306a36Sopenharmony_ci	radio_attenuation += radio_att_delta;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	/* Get baseband and radio attenuation values into permitted ranges.
187062306a36Sopenharmony_ci	 * baseband 0-11, radio 0-9.
187162306a36Sopenharmony_ci	 * Radio attenuation affects power level 4 times as much as baseband.
187262306a36Sopenharmony_ci	 */
187362306a36Sopenharmony_ci	if (radio_attenuation < 0) {
187462306a36Sopenharmony_ci		baseband_attenuation -= (4 * -radio_attenuation);
187562306a36Sopenharmony_ci		radio_attenuation = 0;
187662306a36Sopenharmony_ci	} else if (radio_attenuation > 9) {
187762306a36Sopenharmony_ci		baseband_attenuation += (4 * (radio_attenuation - 9));
187862306a36Sopenharmony_ci		radio_attenuation = 9;
187962306a36Sopenharmony_ci	} else {
188062306a36Sopenharmony_ci		while (baseband_attenuation < 0 && radio_attenuation > 0) {
188162306a36Sopenharmony_ci			baseband_attenuation += 4;
188262306a36Sopenharmony_ci			radio_attenuation--;
188362306a36Sopenharmony_ci		}
188462306a36Sopenharmony_ci		while (baseband_attenuation > 11 && radio_attenuation < 9) {
188562306a36Sopenharmony_ci			baseband_attenuation -= 4;
188662306a36Sopenharmony_ci			radio_attenuation++;
188762306a36Sopenharmony_ci		}
188862306a36Sopenharmony_ci	}
188962306a36Sopenharmony_ci	baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	txpower = phy->txctl1;
189262306a36Sopenharmony_ci	if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
189362306a36Sopenharmony_ci		if (radio_attenuation <= 1) {
189462306a36Sopenharmony_ci			if (txpower == 0) {
189562306a36Sopenharmony_ci				txpower = 3;
189662306a36Sopenharmony_ci				radio_attenuation += 2;
189762306a36Sopenharmony_ci				baseband_attenuation += 2;
189862306a36Sopenharmony_ci			} else if (dev->dev->bus->sprom.boardflags_lo
189962306a36Sopenharmony_ci				   & B43legacy_BFL_PACTRL) {
190062306a36Sopenharmony_ci				baseband_attenuation += 4 *
190162306a36Sopenharmony_ci						     (radio_attenuation - 2);
190262306a36Sopenharmony_ci				radio_attenuation = 2;
190362306a36Sopenharmony_ci			}
190462306a36Sopenharmony_ci		} else if (radio_attenuation > 4 && txpower != 0) {
190562306a36Sopenharmony_ci			txpower = 0;
190662306a36Sopenharmony_ci			if (baseband_attenuation < 3) {
190762306a36Sopenharmony_ci				radio_attenuation -= 3;
190862306a36Sopenharmony_ci				baseband_attenuation += 2;
190962306a36Sopenharmony_ci			} else {
191062306a36Sopenharmony_ci				radio_attenuation -= 2;
191162306a36Sopenharmony_ci				baseband_attenuation -= 2;
191262306a36Sopenharmony_ci			}
191362306a36Sopenharmony_ci		}
191462306a36Sopenharmony_ci	}
191562306a36Sopenharmony_ci	/* Save the control values */
191662306a36Sopenharmony_ci	phy->txctl1 = txpower;
191762306a36Sopenharmony_ci	baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
191862306a36Sopenharmony_ci	radio_attenuation = clamp_val(radio_attenuation, 0, 9);
191962306a36Sopenharmony_ci	phy->rfatt = radio_attenuation;
192062306a36Sopenharmony_ci	phy->bbatt = baseband_attenuation;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	/* Adjust the hardware */
192362306a36Sopenharmony_ci	b43legacy_phy_lock(dev);
192462306a36Sopenharmony_ci	b43legacy_radio_lock(dev);
192562306a36Sopenharmony_ci	b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
192662306a36Sopenharmony_ci				       radio_attenuation, txpower);
192762306a36Sopenharmony_ci	b43legacy_phy_lo_mark_current_used(dev);
192862306a36Sopenharmony_ci	b43legacy_radio_unlock(dev);
192962306a36Sopenharmony_ci	b43legacy_phy_unlock(dev);
193062306a36Sopenharmony_ci}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_cistatic inline
193362306a36Sopenharmony_cis32 b43legacy_tssi2dbm_ad(s32 num, s32 den)
193462306a36Sopenharmony_ci{
193562306a36Sopenharmony_ci	if (num < 0)
193662306a36Sopenharmony_ci		return num/den;
193762306a36Sopenharmony_ci	else
193862306a36Sopenharmony_ci		return (num+den/2)/den;
193962306a36Sopenharmony_ci}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_cistatic inline
194262306a36Sopenharmony_cis8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
194362306a36Sopenharmony_ci{
194462306a36Sopenharmony_ci	s32 m1;
194562306a36Sopenharmony_ci	s32 m2;
194662306a36Sopenharmony_ci	s32 f = 256;
194762306a36Sopenharmony_ci	s32 q;
194862306a36Sopenharmony_ci	s32 delta;
194962306a36Sopenharmony_ci	s8 i = 0;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
195262306a36Sopenharmony_ci	m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1);
195362306a36Sopenharmony_ci	do {
195462306a36Sopenharmony_ci		if (i > 15)
195562306a36Sopenharmony_ci			return -EINVAL;
195662306a36Sopenharmony_ci		q = b43legacy_tssi2dbm_ad(f * 4096 -
195762306a36Sopenharmony_ci					  b43legacy_tssi2dbm_ad(m2 * f, 16) *
195862306a36Sopenharmony_ci					  f, 2048);
195962306a36Sopenharmony_ci		delta = abs(q - f);
196062306a36Sopenharmony_ci		f = q;
196162306a36Sopenharmony_ci		i++;
196262306a36Sopenharmony_ci	} while (delta >= 2);
196362306a36Sopenharmony_ci	entry[index] = clamp_val(b43legacy_tssi2dbm_ad(m1 * f, 8192),
196462306a36Sopenharmony_ci				   -127, 128);
196562306a36Sopenharmony_ci	return 0;
196662306a36Sopenharmony_ci}
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
196962306a36Sopenharmony_ciint b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
197062306a36Sopenharmony_ci{
197162306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
197262306a36Sopenharmony_ci	s16 pab0;
197362306a36Sopenharmony_ci	s16 pab1;
197462306a36Sopenharmony_ci	s16 pab2;
197562306a36Sopenharmony_ci	u8 idx;
197662306a36Sopenharmony_ci	s8 *dyn_tssi2dbm;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B ||
197962306a36Sopenharmony_ci			  phy->type == B43legacy_PHYTYPE_G));
198062306a36Sopenharmony_ci	pab0 = (s16)(dev->dev->bus->sprom.pa0b0);
198162306a36Sopenharmony_ci	pab1 = (s16)(dev->dev->bus->sprom.pa0b1);
198262306a36Sopenharmony_ci	pab2 = (s16)(dev->dev->bus->sprom.pa0b2);
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
198562306a36Sopenharmony_ci		phy->idle_tssi = 0x34;
198662306a36Sopenharmony_ci		phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
198762306a36Sopenharmony_ci		return 0;
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
199162306a36Sopenharmony_ci	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
199262306a36Sopenharmony_ci		/* The pabX values are set in SPROM. Use them. */
199362306a36Sopenharmony_ci		if ((s8)dev->dev->bus->sprom.itssi_bg != 0 &&
199462306a36Sopenharmony_ci		    (s8)dev->dev->bus->sprom.itssi_bg != -1)
199562306a36Sopenharmony_ci			phy->idle_tssi = (s8)(dev->dev->bus->sprom.
199662306a36Sopenharmony_ci					  itssi_bg);
199762306a36Sopenharmony_ci		else
199862306a36Sopenharmony_ci			phy->idle_tssi = 62;
199962306a36Sopenharmony_ci		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
200062306a36Sopenharmony_ci		if (dyn_tssi2dbm == NULL) {
200162306a36Sopenharmony_ci			b43legacyerr(dev->wl, "Could not allocate memory "
200262306a36Sopenharmony_ci			       "for tssi2dbm table\n");
200362306a36Sopenharmony_ci			return -ENOMEM;
200462306a36Sopenharmony_ci		}
200562306a36Sopenharmony_ci		for (idx = 0; idx < 64; idx++)
200662306a36Sopenharmony_ci			if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0,
200762306a36Sopenharmony_ci						     pab1, pab2)) {
200862306a36Sopenharmony_ci				phy->tssi2dbm = NULL;
200962306a36Sopenharmony_ci				b43legacyerr(dev->wl, "Could not generate "
201062306a36Sopenharmony_ci				       "tssi2dBm table\n");
201162306a36Sopenharmony_ci				kfree(dyn_tssi2dbm);
201262306a36Sopenharmony_ci				return -ENODEV;
201362306a36Sopenharmony_ci			}
201462306a36Sopenharmony_ci		phy->tssi2dbm = dyn_tssi2dbm;
201562306a36Sopenharmony_ci		phy->dyn_tssi_tbl = 1;
201662306a36Sopenharmony_ci	} else {
201762306a36Sopenharmony_ci		/* pabX values not set in SPROM. */
201862306a36Sopenharmony_ci		switch (phy->type) {
201962306a36Sopenharmony_ci		case B43legacy_PHYTYPE_B:
202062306a36Sopenharmony_ci			phy->idle_tssi = 0x34;
202162306a36Sopenharmony_ci			phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
202262306a36Sopenharmony_ci			break;
202362306a36Sopenharmony_ci		case B43legacy_PHYTYPE_G:
202462306a36Sopenharmony_ci			phy->idle_tssi = 0x34;
202562306a36Sopenharmony_ci			phy->tssi2dbm = b43legacy_tssi2dbm_g_table;
202662306a36Sopenharmony_ci			break;
202762306a36Sopenharmony_ci		}
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	return 0;
203162306a36Sopenharmony_ci}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ciint b43legacy_phy_init(struct b43legacy_wldev *dev)
203462306a36Sopenharmony_ci{
203562306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
203662306a36Sopenharmony_ci	int err = -ENODEV;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	switch (phy->type) {
203962306a36Sopenharmony_ci	case B43legacy_PHYTYPE_B:
204062306a36Sopenharmony_ci		switch (phy->rev) {
204162306a36Sopenharmony_ci		case 2:
204262306a36Sopenharmony_ci			b43legacy_phy_initb2(dev);
204362306a36Sopenharmony_ci			err = 0;
204462306a36Sopenharmony_ci			break;
204562306a36Sopenharmony_ci		case 4:
204662306a36Sopenharmony_ci			b43legacy_phy_initb4(dev);
204762306a36Sopenharmony_ci			err = 0;
204862306a36Sopenharmony_ci			break;
204962306a36Sopenharmony_ci		case 5:
205062306a36Sopenharmony_ci			b43legacy_phy_initb5(dev);
205162306a36Sopenharmony_ci			err = 0;
205262306a36Sopenharmony_ci			break;
205362306a36Sopenharmony_ci		case 6:
205462306a36Sopenharmony_ci			b43legacy_phy_initb6(dev);
205562306a36Sopenharmony_ci			err = 0;
205662306a36Sopenharmony_ci			break;
205762306a36Sopenharmony_ci		}
205862306a36Sopenharmony_ci		break;
205962306a36Sopenharmony_ci	case B43legacy_PHYTYPE_G:
206062306a36Sopenharmony_ci		b43legacy_phy_initg(dev);
206162306a36Sopenharmony_ci		err = 0;
206262306a36Sopenharmony_ci		break;
206362306a36Sopenharmony_ci	}
206462306a36Sopenharmony_ci	if (err)
206562306a36Sopenharmony_ci		b43legacyerr(dev->wl, "Unknown PHYTYPE found\n");
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	return err;
206862306a36Sopenharmony_ci}
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_civoid b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	struct b43legacy_phy *phy = &dev->phy;
207362306a36Sopenharmony_ci	u16 antennadiv;
207462306a36Sopenharmony_ci	u16 offset;
207562306a36Sopenharmony_ci	u16 value;
207662306a36Sopenharmony_ci	u32 ucodeflags;
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	antennadiv = phy->antenna_diversity;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	if (antennadiv == 0xFFFF)
208162306a36Sopenharmony_ci		antennadiv = 3;
208262306a36Sopenharmony_ci	B43legacy_WARN_ON(antennadiv > 3);
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
208562306a36Sopenharmony_ci					  B43legacy_UCODEFLAGS_OFFSET);
208662306a36Sopenharmony_ci	b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
208762306a36Sopenharmony_ci			      B43legacy_UCODEFLAGS_OFFSET,
208862306a36Sopenharmony_ci			      ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV);
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	switch (phy->type) {
209162306a36Sopenharmony_ci	case B43legacy_PHYTYPE_G:
209262306a36Sopenharmony_ci		offset = 0x0400;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci		if (antennadiv == 2)
209562306a36Sopenharmony_ci			value = (3/*automatic*/ << 7);
209662306a36Sopenharmony_ci		else
209762306a36Sopenharmony_ci			value = (antennadiv << 7);
209862306a36Sopenharmony_ci		b43legacy_phy_write(dev, offset + 1,
209962306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, offset + 1)
210062306a36Sopenharmony_ci				    & 0x7E7F) | value);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci		if (antennadiv >= 2) {
210362306a36Sopenharmony_ci			if (antennadiv == 2)
210462306a36Sopenharmony_ci				value = (antennadiv << 7);
210562306a36Sopenharmony_ci			else
210662306a36Sopenharmony_ci				value = (0/*force0*/ << 7);
210762306a36Sopenharmony_ci			b43legacy_phy_write(dev, offset + 0x2B,
210862306a36Sopenharmony_ci					    (b43legacy_phy_read(dev,
210962306a36Sopenharmony_ci					    offset + 0x2B)
211062306a36Sopenharmony_ci					    & 0xFEFF) | value);
211162306a36Sopenharmony_ci		}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci		if (phy->type == B43legacy_PHYTYPE_G) {
211462306a36Sopenharmony_ci			if (antennadiv >= 2)
211562306a36Sopenharmony_ci				b43legacy_phy_write(dev, 0x048C,
211662306a36Sopenharmony_ci						    b43legacy_phy_read(dev,
211762306a36Sopenharmony_ci						    0x048C) | 0x2000);
211862306a36Sopenharmony_ci			else
211962306a36Sopenharmony_ci				b43legacy_phy_write(dev, 0x048C,
212062306a36Sopenharmony_ci						    b43legacy_phy_read(dev,
212162306a36Sopenharmony_ci						    0x048C) & ~0x2000);
212262306a36Sopenharmony_ci			if (phy->rev >= 2) {
212362306a36Sopenharmony_ci				b43legacy_phy_write(dev, 0x0461,
212462306a36Sopenharmony_ci						    b43legacy_phy_read(dev,
212562306a36Sopenharmony_ci						    0x0461) | 0x0010);
212662306a36Sopenharmony_ci				b43legacy_phy_write(dev, 0x04AD,
212762306a36Sopenharmony_ci						    (b43legacy_phy_read(dev,
212862306a36Sopenharmony_ci						    0x04AD)
212962306a36Sopenharmony_ci						    & 0x00FF) | 0x0015);
213062306a36Sopenharmony_ci				if (phy->rev == 2)
213162306a36Sopenharmony_ci					b43legacy_phy_write(dev, 0x0427,
213262306a36Sopenharmony_ci							    0x0008);
213362306a36Sopenharmony_ci				else
213462306a36Sopenharmony_ci					b43legacy_phy_write(dev, 0x0427,
213562306a36Sopenharmony_ci						(b43legacy_phy_read(dev, 0x0427)
213662306a36Sopenharmony_ci						 & 0x00FF) | 0x0008);
213762306a36Sopenharmony_ci			} else if (phy->rev >= 6)
213862306a36Sopenharmony_ci				b43legacy_phy_write(dev, 0x049B, 0x00DC);
213962306a36Sopenharmony_ci		} else {
214062306a36Sopenharmony_ci			if (phy->rev < 3)
214162306a36Sopenharmony_ci				b43legacy_phy_write(dev, 0x002B,
214262306a36Sopenharmony_ci						    (b43legacy_phy_read(dev,
214362306a36Sopenharmony_ci						    0x002B) & 0x00FF)
214462306a36Sopenharmony_ci						    | 0x0024);
214562306a36Sopenharmony_ci			else {
214662306a36Sopenharmony_ci				b43legacy_phy_write(dev, 0x0061,
214762306a36Sopenharmony_ci						    b43legacy_phy_read(dev,
214862306a36Sopenharmony_ci						    0x0061) | 0x0010);
214962306a36Sopenharmony_ci				if (phy->rev == 3) {
215062306a36Sopenharmony_ci					b43legacy_phy_write(dev, 0x0093,
215162306a36Sopenharmony_ci							    0x001D);
215262306a36Sopenharmony_ci					b43legacy_phy_write(dev, 0x0027,
215362306a36Sopenharmony_ci							    0x0008);
215462306a36Sopenharmony_ci				} else {
215562306a36Sopenharmony_ci					b43legacy_phy_write(dev, 0x0093,
215662306a36Sopenharmony_ci							    0x003A);
215762306a36Sopenharmony_ci					b43legacy_phy_write(dev, 0x0027,
215862306a36Sopenharmony_ci						(b43legacy_phy_read(dev, 0x0027)
215962306a36Sopenharmony_ci						 & 0x00FF) | 0x0008);
216062306a36Sopenharmony_ci				}
216162306a36Sopenharmony_ci			}
216262306a36Sopenharmony_ci		}
216362306a36Sopenharmony_ci		break;
216462306a36Sopenharmony_ci	case B43legacy_PHYTYPE_B:
216562306a36Sopenharmony_ci		if (dev->dev->id.revision == 2)
216662306a36Sopenharmony_ci			value = (3/*automatic*/ << 7);
216762306a36Sopenharmony_ci		else
216862306a36Sopenharmony_ci			value = (antennadiv << 7);
216962306a36Sopenharmony_ci		b43legacy_phy_write(dev, 0x03E2,
217062306a36Sopenharmony_ci				    (b43legacy_phy_read(dev, 0x03E2)
217162306a36Sopenharmony_ci				    & 0xFE7F) | value);
217262306a36Sopenharmony_ci		break;
217362306a36Sopenharmony_ci	default:
217462306a36Sopenharmony_ci		B43legacy_WARN_ON(1);
217562306a36Sopenharmony_ci	}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	if (antennadiv >= 2) {
217862306a36Sopenharmony_ci		ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
217962306a36Sopenharmony_ci						  B43legacy_UCODEFLAGS_OFFSET);
218062306a36Sopenharmony_ci		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
218162306a36Sopenharmony_ci				      B43legacy_UCODEFLAGS_OFFSET,
218262306a36Sopenharmony_ci				      ucodeflags | B43legacy_UCODEFLAG_AUTODIV);
218362306a36Sopenharmony_ci	}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	phy->antenna_diversity = antennadiv;
218662306a36Sopenharmony_ci}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci/* Set the PowerSavingControlBits.
218962306a36Sopenharmony_ci * Bitvalues:
219062306a36Sopenharmony_ci *   0  => unset the bit
219162306a36Sopenharmony_ci *   1  => set the bit
219262306a36Sopenharmony_ci *   -1 => calculate the bit
219362306a36Sopenharmony_ci */
219462306a36Sopenharmony_civoid b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
219562306a36Sopenharmony_ci				     int bit25, int bit26)
219662306a36Sopenharmony_ci{
219762306a36Sopenharmony_ci	int i;
219862306a36Sopenharmony_ci	u32 status;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci/* FIXME: Force 25 to off and 26 to on for now: */
220162306a36Sopenharmony_cibit25 = 0;
220262306a36Sopenharmony_cibit26 = 1;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	if (bit25 == -1) {
220562306a36Sopenharmony_ci		/* TODO: If powersave is not off and FIXME is not set and we
220662306a36Sopenharmony_ci		 *	are not in adhoc and thus is not an AP and we arei
220762306a36Sopenharmony_ci		 *	associated, set bit 25 */
220862306a36Sopenharmony_ci	}
220962306a36Sopenharmony_ci	if (bit26 == -1) {
221062306a36Sopenharmony_ci		/* TODO: If the device is awake or this is an AP, or we are
221162306a36Sopenharmony_ci		 *	scanning, or FIXME, or we are associated, or FIXME,
221262306a36Sopenharmony_ci		 *	or the latest PS-Poll packet sent was successful,
221362306a36Sopenharmony_ci		 *	set bit26  */
221462306a36Sopenharmony_ci	}
221562306a36Sopenharmony_ci	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
221662306a36Sopenharmony_ci	if (bit25)
221762306a36Sopenharmony_ci		status |= B43legacy_MACCTL_HWPS;
221862306a36Sopenharmony_ci	else
221962306a36Sopenharmony_ci		status &= ~B43legacy_MACCTL_HWPS;
222062306a36Sopenharmony_ci	if (bit26)
222162306a36Sopenharmony_ci		status |= B43legacy_MACCTL_AWAKE;
222262306a36Sopenharmony_ci	else
222362306a36Sopenharmony_ci		status &= ~B43legacy_MACCTL_AWAKE;
222462306a36Sopenharmony_ci	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
222562306a36Sopenharmony_ci	if (bit26 && dev->dev->id.revision >= 5) {
222662306a36Sopenharmony_ci		for (i = 0; i < 100; i++) {
222762306a36Sopenharmony_ci			if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
222862306a36Sopenharmony_ci						 0x0040) != 4)
222962306a36Sopenharmony_ci				break;
223062306a36Sopenharmony_ci			udelay(10);
223162306a36Sopenharmony_ci		}
223262306a36Sopenharmony_ci	}
223362306a36Sopenharmony_ci}
2234