1e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* 2e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 3e4d6b7951812d98417feb10784e400e253caf633Michael Buesch Broadcom B43 wireless driver 4e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 5e4d6b7951812d98417feb10784e400e253caf633Michael Buesch G PHY LO (LocalOscillator) Measuring and Control routines 6e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 7e4d6b7951812d98417feb10784e400e253caf633Michael Buesch Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, 81f21ad2a4f7f66855dae600ddd635ff5fb299bbdStefano Brivio Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it> 9eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch Copyright (c) 2005-2007 Michael Buesch <m@bues.ch> 10e4d6b7951812d98417feb10784e400e253caf633Michael Buesch Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> 11e4d6b7951812d98417feb10784e400e253caf633Michael Buesch Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> 12e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 13e4d6b7951812d98417feb10784e400e253caf633Michael Buesch This program is free software; you can redistribute it and/or modify 14e4d6b7951812d98417feb10784e400e253caf633Michael Buesch it under the terms of the GNU General Public License as published by 15e4d6b7951812d98417feb10784e400e253caf633Michael Buesch the Free Software Foundation; either version 2 of the License, or 16e4d6b7951812d98417feb10784e400e253caf633Michael Buesch (at your option) any later version. 17e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 18e4d6b7951812d98417feb10784e400e253caf633Michael Buesch This program is distributed in the hope that it will be useful, 19e4d6b7951812d98417feb10784e400e253caf633Michael Buesch but WITHOUT ANY WARRANTY; without even the implied warranty of 20e4d6b7951812d98417feb10784e400e253caf633Michael Buesch MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21e4d6b7951812d98417feb10784e400e253caf633Michael Buesch GNU General Public License for more details. 22e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 23e4d6b7951812d98417feb10784e400e253caf633Michael Buesch You should have received a copy of the GNU General Public License 24e4d6b7951812d98417feb10784e400e253caf633Michael Buesch along with this program; see the file COPYING. If not, write to 25e4d6b7951812d98417feb10784e400e253caf633Michael Buesch the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 26e4d6b7951812d98417feb10784e400e253caf633Michael Buesch Boston, MA 02110-1301, USA. 27e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 28e4d6b7951812d98417feb10784e400e253caf633Michael Buesch*/ 29e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 30e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include "b43.h" 31e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include "lo.h" 32ef1a628d83fc0423c36e773281162be790503168Michael Buesch#include "phy_g.h" 33e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include "main.h" 34e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 35e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include <linux/delay.h> 36e4d6b7951812d98417feb10784e400e253caf633Michael Buesch#include <linux/sched.h> 375a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 38e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 39e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 4099da185a72ba685a5aaf49dff6a5fe83885112e4John Daikerstatic struct b43_lo_calib *b43_find_lo_calib(struct b43_txpower_lo_control *lo, 4199da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker const struct b43_bbatt *bbatt, 42f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch const struct b43_rfatt *rfatt) 43f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch{ 44f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_lo_calib *c; 45f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 46f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch list_for_each_entry(c, &lo->calib_list, list) { 47f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!b43_compare_bbatt(&c->bbatt, bbatt)) 48f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch continue; 49f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!b43_compare_rfatt(&c->rfatt, rfatt)) 50f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch continue; 51f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return c; 52f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 53e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 54f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return NULL; 55f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch} 56e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 57e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* Write the LocalOscillator Control (adjust) value-pair. */ 58e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) 59e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 60e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 61e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 value; 62e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 63e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (B43_DEBUG) { 64e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { 65e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43dbg(dev->wl, "Invalid LO control pair " 66e4d6b7951812d98417feb10784e400e253caf633Michael Buesch "(I: %d, Q: %d)\n", control->i, control->q); 67e4d6b7951812d98417feb10784e400e253caf633Michael Buesch dump_stack(); 68e4d6b7951812d98417feb10784e400e253caf633Michael Buesch return; 69e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 70e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 71f4440e8a47e216adfe32d96a35bef6d13d498b58Michael Buesch B43_WARN_ON(phy->type != B43_PHYTYPE_G); 72e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 73e4d6b7951812d98417feb10784e400e253caf633Michael Buesch value = (u8) (control->q); 74e4d6b7951812d98417feb10784e400e253caf633Michael Buesch value |= ((u8) (control->i)) << 8; 75f4440e8a47e216adfe32d96a35bef6d13d498b58Michael Buesch b43_phy_write(dev, B43_PHY_LO_CTL, value); 76e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 77e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 78e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic u16 lo_measure_feedthrough(struct b43_wldev *dev, 79e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 lna, u16 pga, u16 trsw_rx) 80e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 81e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 82e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 rfover; 83e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 feedthrough; 84e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 85e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->gmode) { 86e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT; 87e4d6b7951812d98417feb10784e400e253caf633Michael Buesch pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT; 88e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 89e4d6b7951812d98417feb10784e400e253caf633Michael Buesch B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA); 90e4d6b7951812d98417feb10784e400e253caf633Michael Buesch B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA); 91e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/*FIXME This assertion fails B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX | 92e4d6b7951812d98417feb10784e400e253caf633Michael Buesch B43_PHY_RFOVERVAL_BW)); 93e4d6b7951812d98417feb10784e400e253caf633Michael Buesch*/ 94e4d6b7951812d98417feb10784e400e253caf633Michael Buesch trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW); 95e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 96e4d6b7951812d98417feb10784e400e253caf633Michael Buesch /* Construct the RF Override Value */ 97e4d6b7951812d98417feb10784e400e253caf633Michael Buesch rfover = B43_PHY_RFOVERVAL_UNK; 98e4d6b7951812d98417feb10784e400e253caf633Michael Buesch rfover |= pga; 99e4d6b7951812d98417feb10784e400e253caf633Michael Buesch rfover |= lna; 100e4d6b7951812d98417feb10784e400e253caf633Michael Buesch rfover |= trsw_rx; 1010581483afe1a6f90f828b36111b05a70c162137dRafał Miłecki if ((dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA) 10295de2841aad971867851b59c0c5253ecc2e19832Larry Finger && phy->rev > 6) 103e4d6b7951812d98417feb10784e400e253caf633Michael Buesch rfover |= B43_PHY_RFOVERVAL_EXTLNA; 104e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 105e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); 106e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); 107e4d6b7951812d98417feb10784e400e253caf633Michael Buesch udelay(10); 108e4d6b7951812d98417feb10784e400e253caf633Michael Buesch rfover |= B43_PHY_RFOVERVAL_BW_LBW; 109e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); 110e4d6b7951812d98417feb10784e400e253caf633Michael Buesch udelay(10); 111e4d6b7951812d98417feb10784e400e253caf633Michael Buesch rfover |= B43_PHY_RFOVERVAL_BW_LPF; 112e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); 113e4d6b7951812d98417feb10784e400e253caf633Michael Buesch udelay(10); 114e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_PGACTL, 0xF300); 115e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 116e4d6b7951812d98417feb10784e400e253caf633Michael Buesch pga |= B43_PHY_PGACTL_UNKNOWN; 117e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_PGACTL, pga); 118e4d6b7951812d98417feb10784e400e253caf633Michael Buesch udelay(10); 119e4d6b7951812d98417feb10784e400e253caf633Michael Buesch pga |= B43_PHY_PGACTL_LOWBANDW; 120e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_PGACTL, pga); 121e4d6b7951812d98417feb10784e400e253caf633Michael Buesch udelay(10); 122e4d6b7951812d98417feb10784e400e253caf633Michael Buesch pga |= B43_PHY_PGACTL_LPF; 123e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_PGACTL, pga); 124e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 125e4d6b7951812d98417feb10784e400e253caf633Michael Buesch udelay(21); 126e4d6b7951812d98417feb10784e400e253caf633Michael Buesch feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); 127e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 128e4d6b7951812d98417feb10784e400e253caf633Michael Buesch /* This is a good place to check if we need to relax a bit, 129e4d6b7951812d98417feb10784e400e253caf633Michael Buesch * as this is the main function called regularly 130e4d6b7951812d98417feb10784e400e253caf633Michael Buesch * in the LO calibration. */ 131e4d6b7951812d98417feb10784e400e253caf633Michael Buesch cond_resched(); 132e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 133e4d6b7951812d98417feb10784e400e253caf633Michael Buesch return feedthrough; 134e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 135e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 136e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* TXCTL Register and Value Table. 137e4d6b7951812d98417feb10784e400e253caf633Michael Buesch * Returns the "TXCTL Register". 138e4d6b7951812d98417feb10784e400e253caf633Michael Buesch * "value" is the "TXCTL Value". 139e4d6b7951812d98417feb10784e400e253caf633Michael Buesch * "pad_mix_gain" is the PAD Mixer Gain. 140e4d6b7951812d98417feb10784e400e253caf633Michael Buesch */ 141e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic u16 lo_txctl_register_table(struct b43_wldev *dev, 14299da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker u16 *value, u16 *pad_mix_gain) 143e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 144e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 145e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 reg, v, padmix; 146e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 147e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_B) { 148e4d6b7951812d98417feb10784e400e253caf633Michael Buesch v = 0x30; 149e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->radio_rev <= 5) { 150e4d6b7951812d98417feb10784e400e253caf633Michael Buesch reg = 0x43; 151e4d6b7951812d98417feb10784e400e253caf633Michael Buesch padmix = 0; 152e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 153e4d6b7951812d98417feb10784e400e253caf633Michael Buesch reg = 0x52; 154e4d6b7951812d98417feb10784e400e253caf633Michael Buesch padmix = 5; 155e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 156e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 157e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->rev >= 2 && phy->radio_rev == 8) { 158e4d6b7951812d98417feb10784e400e253caf633Michael Buesch reg = 0x43; 159e4d6b7951812d98417feb10784e400e253caf633Michael Buesch v = 0x10; 160e4d6b7951812d98417feb10784e400e253caf633Michael Buesch padmix = 2; 161e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 162e4d6b7951812d98417feb10784e400e253caf633Michael Buesch reg = 0x52; 163e4d6b7951812d98417feb10784e400e253caf633Michael Buesch v = 0x30; 164e4d6b7951812d98417feb10784e400e253caf633Michael Buesch padmix = 5; 165e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 166e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 167e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (value) 168e4d6b7951812d98417feb10784e400e253caf633Michael Buesch *value = v; 169e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (pad_mix_gain) 170e4d6b7951812d98417feb10784e400e253caf633Michael Buesch *pad_mix_gain = padmix; 171e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 172e4d6b7951812d98417feb10784e400e253caf633Michael Buesch return reg; 173e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 174e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 175e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void lo_measure_txctl_values(struct b43_wldev *dev) 176e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 177e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 178ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 179ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_txpower_lo_control *lo = gphy->lo_control; 180e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 reg, mask; 181e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 trsw_rx, pga; 182e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 radio_pctl_reg; 183e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 184e4d6b7951812d98417feb10784e400e253caf633Michael Buesch static const u8 tx_bias_values[] = { 185e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 0x09, 0x08, 0x0A, 0x01, 0x00, 186e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 0x02, 0x05, 0x04, 0x06, 187e4d6b7951812d98417feb10784e400e253caf633Michael Buesch }; 188e4d6b7951812d98417feb10784e400e253caf633Michael Buesch static const u8 tx_magn_values[] = { 189e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 0x70, 0x40, 190e4d6b7951812d98417feb10784e400e253caf633Michael Buesch }; 191e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 192e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (!has_loopback_gain(phy)) { 193e4d6b7951812d98417feb10784e400e253caf633Michael Buesch radio_pctl_reg = 6; 194e4d6b7951812d98417feb10784e400e253caf633Michael Buesch trsw_rx = 2; 195e4d6b7951812d98417feb10784e400e253caf633Michael Buesch pga = 0; 196e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 197e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int lb_gain; /* Loopback gain (in dB) */ 198e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 199e4d6b7951812d98417feb10784e400e253caf633Michael Buesch trsw_rx = 0; 200ef1a628d83fc0423c36e773281162be790503168Michael Buesch lb_gain = gphy->max_lb_gain / 2; 201e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (lb_gain > 10) { 202e4d6b7951812d98417feb10784e400e253caf633Michael Buesch radio_pctl_reg = 0; 203e4d6b7951812d98417feb10784e400e253caf633Michael Buesch pga = abs(10 - lb_gain) / 6; 204cdbf0846e2dd5f122f3910d0e2a305fab337744bHarvey Harrison pga = clamp_val(pga, 0, 15); 205e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 206e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int cmp_val; 207e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int tmp; 208e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 209e4d6b7951812d98417feb10784e400e253caf633Michael Buesch pga = 0; 210e4d6b7951812d98417feb10784e400e253caf633Michael Buesch cmp_val = 0x24; 211e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if ((phy->rev >= 2) && 212e4d6b7951812d98417feb10784e400e253caf633Michael Buesch (phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) 213e4d6b7951812d98417feb10784e400e253caf633Michael Buesch cmp_val = 0x3C; 214e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = lb_gain; 215e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if ((10 - lb_gain) < cmp_val) 216e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = (10 - lb_gain); 217e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (tmp < 0) 218e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp += 6; 219e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else 220e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp += 3; 221e4d6b7951812d98417feb10784e400e253caf633Michael Buesch cmp_val /= 4; 222e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp /= 4; 223e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (tmp >= cmp_val) 224e4d6b7951812d98417feb10784e400e253caf633Michael Buesch radio_pctl_reg = cmp_val; 225e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else 226e4d6b7951812d98417feb10784e400e253caf633Michael Buesch radio_pctl_reg = tmp; 227e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 228e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 2295f9724dd94d63e26edb02d9f6a4ce1ce35737f14Michael Buesch b43_radio_maskset(dev, 0x43, 0xFFF0, radio_pctl_reg); 230ef1a628d83fc0423c36e773281162be790503168Michael Buesch b43_gphy_set_baseband_attenuation(dev, 2); 231e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 232e4d6b7951812d98417feb10784e400e253caf633Michael Buesch reg = lo_txctl_register_table(dev, &mask, NULL); 233e4d6b7951812d98417feb10784e400e253caf633Michael Buesch mask = ~mask; 2343718582a663e035af5d2634cd537a012e20cdb3fMichael Buesch b43_radio_mask(dev, reg, mask); 235e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 236e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (has_tx_magnification(phy)) { 237e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int i, j; 238e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int feedthrough; 239e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int min_feedth = 0xFFFF; 240e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u8 tx_magn, tx_bias; 241e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 242e4d6b7951812d98417feb10784e400e253caf633Michael Buesch for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) { 243e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tx_magn = tx_magn_values[i]; 2445f9724dd94d63e26edb02d9f6a4ce1ce35737f14Michael Buesch b43_radio_maskset(dev, 0x52, 0xFF0F, tx_magn); 245e4d6b7951812d98417feb10784e400e253caf633Michael Buesch for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) { 246e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tx_bias = tx_bias_values[j]; 2475f9724dd94d63e26edb02d9f6a4ce1ce35737f14Michael Buesch b43_radio_maskset(dev, 0x52, 0xFFF0, tx_bias); 248e4d6b7951812d98417feb10784e400e253caf633Michael Buesch feedthrough = 249e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo_measure_feedthrough(dev, 0, pga, 250e4d6b7951812d98417feb10784e400e253caf633Michael Buesch trsw_rx); 251e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (feedthrough < min_feedth) { 252e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo->tx_bias = tx_bias; 253e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo->tx_magn = tx_magn; 254e4d6b7951812d98417feb10784e400e253caf633Michael Buesch min_feedth = feedthrough; 255e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 256e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (lo->tx_bias == 0) 257e4d6b7951812d98417feb10784e400e253caf633Michael Buesch break; 258e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 259e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_radio_write16(dev, 0x52, 260e4d6b7951812d98417feb10784e400e253caf633Michael Buesch (b43_radio_read16(dev, 0x52) 261e4d6b7951812d98417feb10784e400e253caf633Michael Buesch & 0xFF00) | lo->tx_bias | lo-> 262e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tx_magn); 263e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 264e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 265e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo->tx_magn = 0; 266e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo->tx_bias = 0; 2673718582a663e035af5d2634cd537a012e20cdb3fMichael Buesch b43_radio_mask(dev, 0x52, 0xFFF0); /* TX bias == 0 */ 268e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 269f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo->txctl_measured_time = jiffies; 270e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 271e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 272e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void lo_read_power_vector(struct b43_wldev *dev) 273e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 274e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 275ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 276ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_txpower_lo_control *lo = gphy->lo_control; 277f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch int i; 278e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u64 tmp; 279e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u64 power_vector = 0; 280e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 281e4d6b7951812d98417feb10784e400e253caf633Michael Buesch for (i = 0; i < 8; i += 2) { 282e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); 283e4d6b7951812d98417feb10784e400e253caf633Michael Buesch power_vector |= (tmp << (i * 8)); 284e4d6b7951812d98417feb10784e400e253caf633Michael Buesch /* Clear the vector on the device. */ 285e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); 286e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 287e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (power_vector) 288e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo->power_vector = power_vector; 289f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo->pwr_vec_read_time = jiffies; 290e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 291e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 292e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* 802.11/LO/GPHY/MeasuringGains */ 293e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void lo_measure_gain_values(struct b43_wldev *dev, 294e4d6b7951812d98417feb10784e400e253caf633Michael Buesch s16 max_rx_gain, int use_trsw_rx) 295e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 296e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 297ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 298e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 tmp; 299e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 300e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (max_rx_gain < 0) 301e4d6b7951812d98417feb10784e400e253caf633Michael Buesch max_rx_gain = 0; 302e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 303e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (has_loopback_gain(phy)) { 304e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int trsw_rx_gain; 305e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 306e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (use_trsw_rx) { 307ef1a628d83fc0423c36e773281162be790503168Michael Buesch trsw_rx_gain = gphy->trsw_rx_gain / 2; 308e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (max_rx_gain >= trsw_rx_gain) { 309e4d6b7951812d98417feb10784e400e253caf633Michael Buesch trsw_rx_gain = max_rx_gain - trsw_rx_gain; 310e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 311e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else 312e4d6b7951812d98417feb10784e400e253caf633Michael Buesch trsw_rx_gain = max_rx_gain; 313e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (trsw_rx_gain < 9) { 314ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_lod_gain = 0; 315e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 316ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_lod_gain = 1; 317e4d6b7951812d98417feb10784e400e253caf633Michael Buesch trsw_rx_gain -= 8; 318e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 319cdbf0846e2dd5f122f3910d0e2a305fab337744bHarvey Harrison trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D); 320ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain = trsw_rx_gain / 3; 321ef1a628d83fc0423c36e773281162be790503168Michael Buesch if (gphy->pga_gain >= 5) { 322ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain -= 5; 323ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_gain = 2; 324e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else 325ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_gain = 0; 326e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 327ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_gain = 0; 328ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->trsw_rx_gain = 0x20; 329e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (max_rx_gain >= 0x14) { 330ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_lod_gain = 1; 331ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain = 2; 332e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else if (max_rx_gain >= 0x12) { 333ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_lod_gain = 1; 334ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain = 1; 335e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else if (max_rx_gain >= 0xF) { 336ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_lod_gain = 1; 337ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain = 0; 338e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 339ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->lna_lod_gain = 0; 340ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain = 0; 341e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 342e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 343e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 344e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = b43_radio_read16(dev, 0x7A); 345ef1a628d83fc0423c36e773281162be790503168Michael Buesch if (gphy->lna_lod_gain == 0) 346e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp &= ~0x0008; 347e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else 348e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp |= 0x0008; 349e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_radio_write16(dev, 0x7A, tmp); 350e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 351e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 352e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstruct lo_g_saved_values { 353e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u8 old_channel; 354e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 355e4d6b7951812d98417feb10784e400e253caf633Michael Buesch /* Core registers */ 356e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 reg_3F4; 357e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 reg_3E2; 358e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 359e4d6b7951812d98417feb10784e400e253caf633Michael Buesch /* PHY registers */ 360e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_lo_mask; 361e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_extg_01; 362e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_dacctl_hwpctl; 363e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_dacctl; 3645250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch u16 phy_cck_14; 365e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_hpwr_tssictl; 366e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_analogover; 367e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_analogoverval; 368e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_rfover; 369e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_rfoverval; 370e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_classctl; 3715250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch u16 phy_cck_3E; 372e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_crs0; 373e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_pgactl; 3745250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch u16 phy_cck_2A; 375e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 phy_syncctl; 3765250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch u16 phy_cck_30; 3775250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch u16 phy_cck_06; 378e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 379e4d6b7951812d98417feb10784e400e253caf633Michael Buesch /* Radio registers */ 380e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 radio_43; 381e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 radio_7A; 382e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 radio_52; 383e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}; 384e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 385e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void lo_measure_setup(struct b43_wldev *dev, 386e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct lo_g_saved_values *sav) 387e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 3880581483afe1a6f90f828b36111b05a70c162137dRafał Miłecki struct ssb_sprom *sprom = dev->dev->bus_sprom; 389e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 390ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 391ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_txpower_lo_control *lo = gphy->lo_control; 392e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 tmp; 393e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 394ef1a628d83fc0423c36e773281162be790503168Michael Buesch if (b43_has_hardware_pctl(dev)) { 395e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); 396e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); 397e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); 3985250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14)); 399e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL); 400e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 401e59be0b5299ce327d67cfca737b839ef98e0da0eMichael Buesch b43_phy_set(dev, B43_PHY_HPWR_TSSICTL, 0x100); 402e59be0b5299ce327d67cfca737b839ef98e0da0eMichael Buesch b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x40); 403e59be0b5299ce327d67cfca737b839ef98e0da0eMichael Buesch b43_phy_set(dev, B43_PHY_DACCTL, 0x40); 404e59be0b5299ce327d67cfca737b839ef98e0da0eMichael Buesch b43_phy_set(dev, B43_PHY_CCK(0x14), 0x200); 405e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 406e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_B && 407e4d6b7951812d98417feb10784e400e253caf633Michael Buesch phy->radio_ver == 0x2050 && phy->radio_rev < 6) { 4085250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); 4095250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); 410e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 411e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->rev >= 2) { 412e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); 413e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_analogoverval = 414e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); 415e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); 416e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); 417e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); 4185250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E)); 419e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); 420e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 421ac1ea3959f4c6694e92fe18a2ec72cfbed0c71faMichael Buesch b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC); 422ac1ea3959f4c6694e92fe18a2ec72cfbed0c71faMichael Buesch b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF); 423e59be0b5299ce327d67cfca737b839ef98e0da0eMichael Buesch b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003); 424ac1ea3959f4c6694e92fe18a2ec72cfbed0c71faMichael Buesch b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC); 425e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_G) { 426e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if ((phy->rev >= 7) && 42795de2841aad971867851b59c0c5253ecc2e19832Larry Finger (sprom->boardflags_lo & B43_BFL_EXTLNA)) { 428e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVER, 0x933); 429e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 430e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVER, 0x133); 431e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 432e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 433e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVER, 0); 434e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 4355250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x3E), 0); 436e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 437e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->reg_3F4 = b43_read16(dev, 0x3F4); 438e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->reg_3E2 = b43_read16(dev, 0x3E2); 439e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->radio_43 = b43_radio_read16(dev, 0x43); 440e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->radio_7A = b43_radio_read16(dev, 0x7A); 441e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); 4425250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A)); 443e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); 444e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL); 445e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 446e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (!has_tx_magnification(phy)) { 447e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->radio_52 = b43_radio_read16(dev, 0x52); 448e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->radio_52 &= 0x00F0; 449e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 450e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_B) { 4515250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); 4525250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06)); 4535250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF); 4545250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F); 455e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 456e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) 457e4d6b7951812d98417feb10784e400e253caf633Michael Buesch | 0x8000); 458e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 459e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_write16(dev, 0x3F4, b43_read16(dev, 0x3F4) 460e4d6b7951812d98417feb10784e400e253caf633Michael Buesch & 0xF000); 461e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 462e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = 4635250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E); 464e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, tmp, 0x007F); 465e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 466e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = sav->phy_syncctl; 467e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_SYNCCTL, tmp & 0xFF7F); 468e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = sav->radio_7A; 469e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_radio_write16(dev, 0x007A, tmp & 0xFFF0); 470e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 4715250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3); 472e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_G || 473e4d6b7951812d98417feb10784e400e253caf633Michael Buesch (phy->type == B43_PHYTYPE_B && 474e4d6b7951812d98417feb10784e400e253caf633Michael Buesch phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) { 4755250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003); 476e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else 4775250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); 478e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->rev >= 2) 4792f19c287fecb958eb68b1c2199b4dd6e00ba4276Gábor Stefanik b43_dummy_transmission(dev, false, true); 480ef1a628d83fc0423c36e773281162be790503168Michael Buesch b43_gphy_channel_switch(dev, 6, 0); 481e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_radio_read16(dev, 0x51); /* dummy read */ 482e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_G) 4835250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); 484f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 485f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Re-measure the txctl values, if needed. */ 486f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (time_before(lo->txctl_measured_time, 487f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch jiffies - B43_LO_TXCTL_EXPIRE)) 488e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo_measure_txctl_values(dev); 489f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 490e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { 491e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); 492e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 493e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_B) 4945250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078); 495e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else 496e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); 497e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 498e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 499e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 500e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void lo_measure_restore(struct b43_wldev *dev, 501e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct lo_g_saved_values *sav) 502e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 503e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 504ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 505e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 tmp; 506e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 507e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->rev >= 2) { 508e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); 509ef1a628d83fc0423c36e773281162be790503168Michael Buesch tmp = (gphy->pga_gain << 8); 510e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0); 511e4d6b7951812d98417feb10784e400e253caf633Michael Buesch udelay(5); 512e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2); 513e4d6b7951812d98417feb10784e400e253caf633Michael Buesch udelay(2); 514e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3); 515e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 516ef1a628d83fc0423c36e773281162be790503168Michael Buesch tmp = (gphy->pga_gain | 0xEFA0); 517e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_PGACTL, tmp); 518e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 519e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_G) { 520e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->rev >= 3) 5215250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); 522e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else 5235250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078); 524e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->rev >= 2) 5255250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202); 526e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else 5275250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101); 528e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 529e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_write16(dev, 0x3F4, sav->reg_3F4); 530e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl); 5315250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A); 532e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl); 533e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl); 534e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_radio_write16(dev, 0x43, sav->radio_43); 535e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_radio_write16(dev, 0x7A, sav->radio_7A); 536e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (!has_tx_magnification(phy)) { 537e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = sav->radio_52; 5385f9724dd94d63e26edb02d9f6a4ce1ce35737f14Michael Buesch b43_radio_maskset(dev, 0x52, 0xFF0F, tmp); 539e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 540e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_write16(dev, 0x3E2, sav->reg_3E2); 541e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->type == B43_PHYTYPE_B && 542e4d6b7951812d98417feb10784e400e253caf633Michael Buesch phy->radio_ver == 0x2050 && phy->radio_rev <= 5) { 5435250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30); 5445250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06); 545e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 546e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (phy->rev >= 2) { 547e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover); 548e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 549e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sav->phy_analogoverval); 550e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl); 551e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover); 552e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval); 5535250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E); 554e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); 555e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 556ef1a628d83fc0423c36e773281162be790503168Michael Buesch if (b43_has_hardware_pctl(dev)) { 557e4d6b7951812d98417feb10784e400e253caf633Michael Buesch tmp = (sav->phy_lo_mask & 0xBFFF); 558e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_LO_MASK, tmp); 559e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); 560e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl); 5615250703e3144e50fbeceb4d1fc01ea2fd159fd4aMichael Buesch b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14); 562e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); 563e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 564ef1a628d83fc0423c36e773281162be790503168Michael Buesch b43_gphy_channel_switch(dev, sav->old_channel, 1); 565e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 566e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 567e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstruct b43_lo_g_statemachine { 568e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int current_state; 569e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int nr_measured; 570e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int state_val_multiplier; 571e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 lowest_feedth; 572e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_loctl min_loctl; 573e4d6b7951812d98417feb10784e400e253caf633Michael Buesch}; 574e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 575e4d6b7951812d98417feb10784e400e253caf633Michael Buesch/* Loop over each possible value in this state. */ 576e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic int lo_probe_possible_loctls(struct b43_wldev *dev, 577e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_loctl *probe_loctl, 578e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_lo_g_statemachine *d) 579e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 580e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 581ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 582e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_loctl test_loctl; 583e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_loctl orig_loctl; 584e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_loctl prev_loctl = { 585e4d6b7951812d98417feb10784e400e253caf633Michael Buesch .i = -100, 586e4d6b7951812d98417feb10784e400e253caf633Michael Buesch .q = -100, 587e4d6b7951812d98417feb10784e400e253caf633Michael Buesch }; 588e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int i; 589e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int begin, end; 590e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int found_lower = 0; 591e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 feedth; 592e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 593e4d6b7951812d98417feb10784e400e253caf633Michael Buesch static const struct b43_loctl modifiers[] = { 594e4d6b7951812d98417feb10784e400e253caf633Michael Buesch {.i = 1,.q = 1,}, 595e4d6b7951812d98417feb10784e400e253caf633Michael Buesch {.i = 1,.q = 0,}, 596e4d6b7951812d98417feb10784e400e253caf633Michael Buesch {.i = 1,.q = -1,}, 597e4d6b7951812d98417feb10784e400e253caf633Michael Buesch {.i = 0,.q = -1,}, 598e4d6b7951812d98417feb10784e400e253caf633Michael Buesch {.i = -1,.q = -1,}, 599e4d6b7951812d98417feb10784e400e253caf633Michael Buesch {.i = -1,.q = 0,}, 600e4d6b7951812d98417feb10784e400e253caf633Michael Buesch {.i = -1,.q = 1,}, 601e4d6b7951812d98417feb10784e400e253caf633Michael Buesch {.i = 0,.q = 1,}, 602e4d6b7951812d98417feb10784e400e253caf633Michael Buesch }; 603e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 604e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (d->current_state == 0) { 605e4d6b7951812d98417feb10784e400e253caf633Michael Buesch begin = 1; 606e4d6b7951812d98417feb10784e400e253caf633Michael Buesch end = 8; 607e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else if (d->current_state % 2 == 0) { 608e4d6b7951812d98417feb10784e400e253caf633Michael Buesch begin = d->current_state - 1; 609e4d6b7951812d98417feb10784e400e253caf633Michael Buesch end = d->current_state + 1; 610e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else { 611e4d6b7951812d98417feb10784e400e253caf633Michael Buesch begin = d->current_state - 2; 612e4d6b7951812d98417feb10784e400e253caf633Michael Buesch end = d->current_state + 2; 613e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 614e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (begin < 1) 615e4d6b7951812d98417feb10784e400e253caf633Michael Buesch begin += 8; 616e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (end > 8) 617e4d6b7951812d98417feb10784e400e253caf633Michael Buesch end -= 8; 618e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 619e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memcpy(&orig_loctl, probe_loctl, sizeof(struct b43_loctl)); 620e4d6b7951812d98417feb10784e400e253caf633Michael Buesch i = begin; 621e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d->current_state = i; 622e4d6b7951812d98417feb10784e400e253caf633Michael Buesch while (1) { 623e4d6b7951812d98417feb10784e400e253caf633Michael Buesch B43_WARN_ON(!(i >= 1 && i <= 8)); 624e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memcpy(&test_loctl, &orig_loctl, sizeof(struct b43_loctl)); 625e4d6b7951812d98417feb10784e400e253caf633Michael Buesch test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier; 626e4d6b7951812d98417feb10784e400e253caf633Michael Buesch test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier; 627e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if ((test_loctl.i != prev_loctl.i || 628e4d6b7951812d98417feb10784e400e253caf633Michael Buesch test_loctl.q != prev_loctl.q) && 629e4d6b7951812d98417feb10784e400e253caf633Michael Buesch (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) { 630e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_lo_write(dev, &test_loctl); 631ef1a628d83fc0423c36e773281162be790503168Michael Buesch feedth = lo_measure_feedthrough(dev, gphy->lna_gain, 632ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain, 633ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->trsw_rx_gain); 634e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (feedth < d->lowest_feedth) { 635e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memcpy(probe_loctl, &test_loctl, 636e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sizeof(struct b43_loctl)); 637e4d6b7951812d98417feb10784e400e253caf633Michael Buesch found_lower = 1; 638e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d->lowest_feedth = feedth; 639e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if ((d->nr_measured < 2) && 640f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch !has_loopback_gain(phy)) 641e4d6b7951812d98417feb10784e400e253caf633Michael Buesch break; 642e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 643e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 644e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl)); 645e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (i == end) 646e4d6b7951812d98417feb10784e400e253caf633Michael Buesch break; 647e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (i == 8) 648e4d6b7951812d98417feb10784e400e253caf633Michael Buesch i = 1; 649e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else 650e4d6b7951812d98417feb10784e400e253caf633Michael Buesch i++; 651e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d->current_state = i; 652e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 653e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 654e4d6b7951812d98417feb10784e400e253caf633Michael Buesch return found_lower; 655e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 656e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 657e4d6b7951812d98417feb10784e400e253caf633Michael Bueschstatic void lo_probe_loctls_statemachine(struct b43_wldev *dev, 658e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_loctl *loctl, 659e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int *max_rx_gain) 660e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 661e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 662ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 663e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_lo_g_statemachine d; 664e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 feedth; 665e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int found_lower; 666e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_loctl probe_loctl; 667e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int max_repeat = 1, repeat_cnt = 0; 668e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 669e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.nr_measured = 0; 670e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.state_val_multiplier = 1; 671f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (has_loopback_gain(phy)) 672e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.state_val_multiplier = 3; 673e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 674e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); 675f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (has_loopback_gain(phy)) 676e4d6b7951812d98417feb10784e400e253caf633Michael Buesch max_repeat = 4; 677e4d6b7951812d98417feb10784e400e253caf633Michael Buesch do { 678e4d6b7951812d98417feb10784e400e253caf633Michael Buesch b43_lo_write(dev, &d.min_loctl); 679ef1a628d83fc0423c36e773281162be790503168Michael Buesch feedth = lo_measure_feedthrough(dev, gphy->lna_gain, 680ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain, 681ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->trsw_rx_gain); 682f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (feedth < 0x258) { 683e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (feedth >= 0x12C) 684e4d6b7951812d98417feb10784e400e253caf633Michael Buesch *max_rx_gain += 6; 685e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else 686e4d6b7951812d98417feb10784e400e253caf633Michael Buesch *max_rx_gain += 3; 687ef1a628d83fc0423c36e773281162be790503168Michael Buesch feedth = lo_measure_feedthrough(dev, gphy->lna_gain, 688ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->pga_gain, 689ef1a628d83fc0423c36e773281162be790503168Michael Buesch gphy->trsw_rx_gain); 690e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 691e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.lowest_feedth = feedth; 692e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 693e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.current_state = 0; 694e4d6b7951812d98417feb10784e400e253caf633Michael Buesch do { 695e4d6b7951812d98417feb10784e400e253caf633Michael Buesch B43_WARN_ON(! 696e4d6b7951812d98417feb10784e400e253caf633Michael Buesch (d.current_state >= 0 697e4d6b7951812d98417feb10784e400e253caf633Michael Buesch && d.current_state <= 8)); 698e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memcpy(&probe_loctl, &d.min_loctl, 699e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sizeof(struct b43_loctl)); 700e4d6b7951812d98417feb10784e400e253caf633Michael Buesch found_lower = 701e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo_probe_possible_loctls(dev, &probe_loctl, &d); 702e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (!found_lower) 703e4d6b7951812d98417feb10784e400e253caf633Michael Buesch break; 704e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if ((probe_loctl.i == d.min_loctl.i) && 705e4d6b7951812d98417feb10784e400e253caf633Michael Buesch (probe_loctl.q == d.min_loctl.q)) 706e4d6b7951812d98417feb10784e400e253caf633Michael Buesch break; 707e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memcpy(&d.min_loctl, &probe_loctl, 708e4d6b7951812d98417feb10784e400e253caf633Michael Buesch sizeof(struct b43_loctl)); 709e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.nr_measured++; 710e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } while (d.nr_measured < 24); 711e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memcpy(loctl, &d.min_loctl, sizeof(struct b43_loctl)); 712e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 713e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (has_loopback_gain(phy)) { 714e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (d.lowest_feedth > 0x1194) 715e4d6b7951812d98417feb10784e400e253caf633Michael Buesch *max_rx_gain -= 6; 716e4d6b7951812d98417feb10784e400e253caf633Michael Buesch else if (d.lowest_feedth < 0x5DC) 717e4d6b7951812d98417feb10784e400e253caf633Michael Buesch *max_rx_gain += 3; 718e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (repeat_cnt == 0) { 719e4d6b7951812d98417feb10784e400e253caf633Michael Buesch if (d.lowest_feedth <= 0x5DC) { 720e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.state_val_multiplier = 1; 721e4d6b7951812d98417feb10784e400e253caf633Michael Buesch repeat_cnt++; 722e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else 723e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.state_val_multiplier = 2; 724e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } else if (repeat_cnt == 2) 725e4d6b7951812d98417feb10784e400e253caf633Michael Buesch d.state_val_multiplier = 1; 726e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 727e4d6b7951812d98417feb10784e400e253caf633Michael Buesch lo_measure_gain_values(dev, *max_rx_gain, 728e4d6b7951812d98417feb10784e400e253caf633Michael Buesch has_loopback_gain(phy)); 729e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } while (++repeat_cnt < max_repeat); 730e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 731e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 732f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Bueschstatic 73399da185a72ba685a5aaf49dff6a5fe83885112e4John Daikerstruct b43_lo_calib *b43_calibrate_lo_setting(struct b43_wldev *dev, 73499da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker const struct b43_bbatt *bbatt, 73599da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker const struct b43_rfatt *rfatt) 736e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 737e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 738ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 739e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_loctl loctl = { 740e4d6b7951812d98417feb10784e400e253caf633Michael Buesch .i = 0, 741e4d6b7951812d98417feb10784e400e253caf633Michael Buesch .q = 0, 742e4d6b7951812d98417feb10784e400e253caf633Michael Buesch }; 743e4d6b7951812d98417feb10784e400e253caf633Michael Buesch int max_rx_gain; 744f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_lo_calib *cal; 745f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct lo_g_saved_values uninitialized_var(saved_regs); 746e4d6b7951812d98417feb10784e400e253caf633Michael Buesch /* Values from the "TXCTL Register and Value Table" */ 747e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 txctl_reg; 748e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 txctl_value; 749e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 pad_mix_gain; 750e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 751f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch saved_regs.old_channel = phy->channel; 752f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_mac_suspend(dev); 753f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo_measure_setup(dev, &saved_regs); 754e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 755e4d6b7951812d98417feb10784e400e253caf633Michael Buesch txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); 756e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 7575f9724dd94d63e26edb02d9f6a4ce1ce35737f14Michael Buesch b43_radio_maskset(dev, 0x43, 0xFFF0, rfatt->att); 7585f9724dd94d63e26edb02d9f6a4ce1ce35737f14Michael Buesch b43_radio_maskset(dev, txctl_reg, ~txctl_value, (rfatt->with_padmix ? txctl_value :0)); 759e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 760f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch max_rx_gain = rfatt->att * 2; 761f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch max_rx_gain += bbatt->att / 2; 762f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (rfatt->with_padmix) 763f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch max_rx_gain -= pad_mix_gain; 764f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (has_loopback_gain(phy)) 765ef1a628d83fc0423c36e773281162be790503168Michael Buesch max_rx_gain += gphy->max_lb_gain; 766f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo_measure_gain_values(dev, max_rx_gain, 767f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch has_loopback_gain(phy)); 768f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 769ef1a628d83fc0423c36e773281162be790503168Michael Buesch b43_gphy_set_baseband_attenuation(dev, bbatt->att); 770f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); 771f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 772f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo_measure_restore(dev, &saved_regs); 773f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_mac_enable(dev); 774f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 775f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (b43_debug(dev, B43_DBG_LO)) { 776f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) " 777f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch "=> I=%d Q=%d\n", 778f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch bbatt->att, rfatt->att, rfatt->with_padmix, 779f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch loctl.i, loctl.q); 780e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 781e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 782f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch cal = kmalloc(sizeof(*cal), GFP_KERNEL); 783f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!cal) { 784f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43warn(dev->wl, "LO calib: out of memory\n"); 785f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return NULL; 786e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 787f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch memcpy(&cal->bbatt, bbatt, sizeof(*bbatt)); 788f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch memcpy(&cal->rfatt, rfatt, sizeof(*rfatt)); 789f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch memcpy(&cal->ctl, &loctl, sizeof(loctl)); 790f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch cal->calib_time = jiffies; 791f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch INIT_LIST_HEAD(&cal->list); 792f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 793f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return cal; 794e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 795e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 796f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch/* Get a calibrated LO setting for the given attenuation values. 797f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch * Might return a NULL pointer under OOM! */ 798f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Bueschstatic 79999da185a72ba685a5aaf49dff6a5fe83885112e4John Daikerstruct b43_lo_calib *b43_get_calib_lo_settings(struct b43_wldev *dev, 80099da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker const struct b43_bbatt *bbatt, 80199da185a72ba685a5aaf49dff6a5fe83885112e4John Daiker const struct b43_rfatt *rfatt) 802e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 803ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; 804f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_lo_calib *c; 805f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 806f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch c = b43_find_lo_calib(lo, bbatt, rfatt); 807f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (c) 808f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return c; 809f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Not in the list of calibrated LO settings. 810f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch * Calibrate it now. */ 811f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch c = b43_calibrate_lo_setting(dev, bbatt, rfatt); 812f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!c) 813f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return NULL; 814f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch list_add(&c->list, &lo->calib_list); 815f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 816f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return c; 817e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 818e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 819f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Bueschvoid b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) 820e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 821e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_phy *phy = &dev->phy; 822ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 823ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_txpower_lo_control *lo = gphy->lo_control; 824f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch int i; 825f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch int rf_offset, bb_offset; 826f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch const struct b43_rfatt *rfatt; 827f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch const struct b43_bbatt *bbatt; 828f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch u64 power_vector; 8293db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell bool table_changed = false; 830e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 831f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch BUILD_BUG_ON(B43_DC_LT_SIZE != 32); 832f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64); 833e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 834f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch power_vector = lo->power_vector; 835f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!update_all && !power_vector) 836f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return; /* Nothing to do. */ 837f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 838f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Suspend the MAC now to avoid continuous suspend/enable 839f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch * cycles in the loop. */ 840f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_mac_suspend(dev); 841f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 842f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch for (i = 0; i < B43_DC_LT_SIZE * 2; i++) { 843f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_lo_calib *cal; 844f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch int idx; 845f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch u16 val; 846f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 847f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!update_all && !(power_vector & (((u64)1ULL) << i))) 848f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch continue; 849f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Update the table entry for this power_vector bit. 850f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch * The table rows are RFatt entries and columns are BBatt. */ 851f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch bb_offset = i / lo->rfatt_list.len; 852f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch rf_offset = i % lo->rfatt_list.len; 853f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch bbatt = &(lo->bbatt_list.list[bb_offset]); 854f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch rfatt = &(lo->rfatt_list.list[rf_offset]); 855f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 856f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch cal = b43_calibrate_lo_setting(dev, bbatt, rfatt); 857f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!cal) { 858f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43warn(dev->wl, "LO: Could not " 859f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch "calibrate DC table entry\n"); 860f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch continue; 861f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 862f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /*FIXME: Is Q really in the low nibble? */ 863f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch val = (u8)(cal->ctl.q); 864f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch val |= ((u8)(cal->ctl.i)) << 4; 865f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch kfree(cal); 866f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 867f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Get the index into the hardware DC LT. */ 868f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch idx = i / 2; 869f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Change the table in memory. */ 870f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (i % 2) { 871f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Change the high byte. */ 872f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF) 873f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch | ((val & 0x00FF) << 8); 874f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } else { 875f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Change the low byte. */ 876f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00) 877f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch | (val & 0x00FF); 878f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 8793db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell table_changed = true; 880e4d6b7951812d98417feb10784e400e253caf633Michael Buesch } 881f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (table_changed) { 882f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* The table changed in memory. Update the hardware table. */ 883f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch for (i = 0; i < B43_DC_LT_SIZE; i++) 884f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]); 885f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 886f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_mac_enable(dev); 887e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 888e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 889f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch/* Fixup the RF attenuation value for the case where we are 890f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch * using the PAD mixer. */ 891f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Bueschstatic inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf) 892e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 893f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!rf->with_padmix) 894f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return; 895f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3)) 896f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch rf->att = 4; 897e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 898e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 899e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_lo_g_adjust(struct b43_wldev *dev) 900e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 901ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = dev->phy.g; 902f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_lo_calib *cal; 903e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_rfatt rf; 904e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 905ef1a628d83fc0423c36e773281162be790503168Michael Buesch memcpy(&rf, &gphy->rfatt, sizeof(rf)); 906f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_lo_fixup_rfatt(&rf); 907e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 908ef1a628d83fc0423c36e773281162be790503168Michael Buesch cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf); 909f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!cal) 910f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return; 911f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_lo_write(dev, &cal->ctl); 912e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 913e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 914e4d6b7951812d98417feb10784e400e253caf633Michael Bueschvoid b43_lo_g_adjust_to(struct b43_wldev *dev, 915e4d6b7951812d98417feb10784e400e253caf633Michael Buesch u16 rfatt, u16 bbatt, u16 tx_control) 916e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 917e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_rfatt rf; 918e4d6b7951812d98417feb10784e400e253caf633Michael Buesch struct b43_bbatt bb; 919f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_lo_calib *cal; 920e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 921e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memset(&rf, 0, sizeof(rf)); 922e4d6b7951812d98417feb10784e400e253caf633Michael Buesch memset(&bb, 0, sizeof(bb)); 923e4d6b7951812d98417feb10784e400e253caf633Michael Buesch rf.att = rfatt; 924e4d6b7951812d98417feb10784e400e253caf633Michael Buesch bb.att = bbatt; 925f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_lo_fixup_rfatt(&rf); 926f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch cal = b43_get_calib_lo_settings(dev, &bb, &rf); 927f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!cal) 928f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return; 929f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_lo_write(dev, &cal->ctl); 930e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 931e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 932f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch/* Periodic LO maintanance work */ 933f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Bueschvoid b43_lo_g_maintanance_work(struct b43_wldev *dev) 934e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 935f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_phy *phy = &dev->phy; 936ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_phy_g *gphy = phy->g; 937ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_txpower_lo_control *lo = gphy->lo_control; 938f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch unsigned long now; 939f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch unsigned long expire; 940f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_lo_calib *cal, *tmp; 9413db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell bool current_item_expired = false; 942f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch bool hwpctl; 943f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 944f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!lo) 945f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return; 946f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch now = jiffies; 947ef1a628d83fc0423c36e773281162be790503168Michael Buesch hwpctl = b43_has_hardware_pctl(dev); 948f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 949f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (hwpctl) { 950f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Read the power vector and update it, if needed. */ 951f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch expire = now - B43_LO_PWRVEC_EXPIRE; 952f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (time_before(lo->pwr_vec_read_time, expire)) { 953f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo_read_power_vector(dev); 954f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_gphy_dc_lt_init(dev, 0); 955f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 956f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch //FIXME Recalc the whole DC table from time to time? 957f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 958f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch 959f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (hwpctl) 960f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return; 961f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Search for expired LO settings. Remove them. 962f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch * Recalibrate the current setting, if expired. */ 963f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch expire = now - B43_LO_CALIB_EXPIRE; 964f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { 965f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!time_before(cal->calib_time, expire)) 966f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch continue; 967f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* This item expired. */ 968ef1a628d83fc0423c36e773281162be790503168Michael Buesch if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) && 969ef1a628d83fc0423c36e773281162be790503168Michael Buesch b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) { 970f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch B43_WARN_ON(current_item_expired); 9713db1cd5c05f35fb43eb134df6f321de4e63141f2Rusty Russell current_item_expired = true; 972f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 973f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (b43_debug(dev, B43_DBG_LO)) { 974f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), " 975f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch "I=%d, Q=%d expired\n", 976f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch cal->bbatt.att, cal->rfatt.att, 977f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch cal->rfatt.with_padmix, 978f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch cal->ctl.i, cal->ctl.q); 979f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 980f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch list_del(&cal->list); 981f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch kfree(cal); 982f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 983f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (current_item_expired || unlikely(list_empty(&lo->calib_list))) { 984f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch /* Recalibrate currently used LO setting. */ 985f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (b43_debug(dev, B43_DBG_LO)) 986f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); 987ef1a628d83fc0423c36e773281162be790503168Michael Buesch cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt); 988f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (cal) { 989f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch list_add(&cal->list, &lo->calib_list); 990f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_lo_write(dev, &cal->ctl); 991f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } else 992f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43warn(dev->wl, "Failed to recalibrate current LO setting\n"); 993f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 994e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 995e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 996f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Bueschvoid b43_lo_g_cleanup(struct b43_wldev *dev) 997e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 998ef1a628d83fc0423c36e773281162be790503168Michael Buesch struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; 999f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch struct b43_lo_calib *cal, *tmp; 1000e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 1001f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch if (!lo) 1002f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch return; 1003f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { 1004f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch list_del(&cal->list); 1005f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch kfree(cal); 1006f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 1007e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 1008e4d6b7951812d98417feb10784e400e253caf633Michael Buesch 1009f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch/* LO Initialization */ 1010f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Bueschvoid b43_lo_g_init(struct b43_wldev *dev) 1011e4d6b7951812d98417feb10784e400e253caf633Michael Buesch{ 1012ef1a628d83fc0423c36e773281162be790503168Michael Buesch if (b43_has_hardware_pctl(dev)) { 1013f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch lo_read_power_vector(dev); 1014f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch b43_gphy_dc_lt_init(dev, 1); 1015f5eda47f45e90dfa38e25d569b9ac84ba94f8301Michael Buesch } 1016e4d6b7951812d98417feb10784e400e253caf633Michael Buesch} 1017