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