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