/*
Broadcom B43 wireless driver
G PHY LO (LocalOscillator) Measuring and Control routines
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "b43.h"
#include "lo.h"
#include "phy.h"
#include "main.h"
#include <linux/delay.h>
#include <linux/sched.h>
/* Define to 1 to always calibrate all possible LO control pairs.
* This is a workaround until we fix the partial LO calibration optimization. */
#define B43_CALIB_ALL_LOCTLS 1
/* Write the LocalOscillator Control (adjust) value-pair. */
static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
{
struct b43_phy *phy = &dev->phy;
u16 value;
u16 reg;
if (B43_DEBUG) {
if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) {
b43dbg(dev->wl, "Invalid LO control pair "
"(I: %d, Q: %d)\n", control->i, control->q);
dump_stack();
return;
}
}
value = (u8) (control->q);
value |= ((u8) (control->i)) << 8;
reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL;
b43_phy_write(dev, reg, value);
}
static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt,
const struct b43_bbatt *bbatt,
struct b43_wldev *dev)
{
int err = 0;
/* Check the attenuation values against the LO control array sizes. */
if (unlikely(rfatt->att >= B43_NR_RF)) {
b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att);
err = -EINVAL;
}
if (unlikely(bbatt->att >= B43_NR_BB)) {
b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att);
err = -EINVAL;
}
return err;
}
#if !B43_CALIB_ALL_LOCTLS
static
struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev,
const struct b43_rfatt *rfatt,
const struct b43_bbatt *bbatt)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
if (assert_rfatt_and_bbatt(