⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lo.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  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_LOCTLSstaticstruct 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(rfatt, bbatt, dev))		return &(lo->no_padmix[0][0]);	/* Just prevent a crash */	return &(lo->no_padmix[bbatt->att][rfatt->att]);}#endif /* !B43_CALIB_ALL_LOCTLS */struct b43_loctl *b43_get_lo_g_ctl(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(rfatt, bbatt, dev))		return &(lo->no_padmix[0][0]);	/* Just prevent a crash */	if (rfatt->with_padmix)		return &(lo->with_padmix[bbatt->att][rfatt->att]);	return &(lo->no_padmix[bbatt->att][rfatt->att]);}/* Call a function for every possible LO control value-pair. */static void b43_call_for_each_loctl(struct b43_wldev *dev,				    void (*func) (struct b43_wldev *,						  struct b43_loctl *)){	struct b43_phy *phy = &dev->phy;	struct b43_txpower_lo_control *ctl = phy->lo_control;	int i, j;	for (i = 0; i < B43_NR_BB; i++) {		for (j = 0; j < B43_NR_RF; j++)			func(dev, &(ctl->with_padmix[i][j]));	}	for (i = 0; i < B43_NR_BB; i++) {		for (j = 0; j < B43_NR_RF; j++)			func(dev, &(ctl->no_padmix[i][j]));	}}static u16 lo_b_r15_loop(struct b43_wldev *dev){	int i;	u16 ret = 0;	for (i = 0; i < 10; i++) {		b43_phy_write(dev, 0x0015, 0xAFA0);		udelay(1);		b43_phy_write(dev, 0x0015, 0xEFA0);		udelay(10);		b43_phy_write(dev, 0x0015, 0xFFA0);		udelay(40);		ret += b43_phy_read(dev, 0x002C);	}	return ret;}void b43_lo_b_measure(struct b43_wldev *dev){	struct b43_phy *phy = &dev->phy;	u16 regstack[12] = { 0 };	u16 mls;	u16 fval;	int i, j;	regstack[0] = b43_phy_read(dev, 0x0015);	regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0;	if (phy->radio_ver == 0x2053) {		regstack[2] = b43_phy_read(dev, 0x000A);		regstack[3] = b43_phy_read(dev, 0x002A);		regstack[4] = b43_phy_read(dev, 0x0035);		regstack[5] = b43_phy_read(dev, 0x0003);		regstack[6] = b43_phy_read(dev, 0x0001);		regstack[7] = b43_phy_read(dev, 0x0030);		regstack[8] = b43_radio_read16(dev, 0x0043);		regstack[9] = b43_radio_read16(dev, 0x007A);		regstack[10] = b43_read16(dev, 0x03EC);		regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0;		b43_phy_write(dev, 0x0030, 0x00FF);		b43_write16(dev, 0x03EC, 0x3F3F);		b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);		b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);	}	b43_phy_write(dev, 0x0015, 0xB000);	b43_phy_write(dev, 0x002B, 0x0004);	if (phy->radio_ver == 0x2053) {		b43_phy_write(dev, 0x002B, 0x0203);		b43_phy_write(dev, 0x002A, 0x08A3);	}	phy->minlowsig[0] = 0xFFFF;	for (i = 0; i < 4; i++) {		b43_radio_write16(dev, 0x0052, regstack[1] | i);		lo_b_r15_loop(dev);	}	for (i = 0; i < 10; i++) {		b43_radio_write16(dev, 0x0052, regstack[1] | i);		mls = lo_b_r15_loop(dev) / 10;		if (mls < phy->minlowsig[0]) {			phy->minlowsig[0] = mls;			phy->minlowsigpos[0] = i;		}	}	b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);	phy->minlowsig[1] = 0xFFFF;	for (i = -4; i < 5; i += 2) {		for (j = -4; j < 5; j += 2) {			if (j < 0)				fval = (0x0100 * i) + j + 0x0100;			else				fval = (0x0100 * i) + j;			b43_phy_write(dev, 0x002F, fval);			mls = lo_b_r15_loop(dev) / 10;			if (mls < phy->minlowsig[1]) {				phy->minlowsig[1] = mls;				phy->minlowsigpos[1] = fval;			}		}	}	phy->minlowsigpos[1] += 0x0101;	b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]);	if (phy->radio_ver == 0x2053) {		b43_phy_write(dev, 0x000A, regstack[2]);		b43_phy_write(dev, 0x002A, regstack[3]);		b43_phy_write(dev, 0x0035, regstack[4]);		b43_phy_write(dev, 0x0003, regstack[5]);		b43_phy_write(dev, 0x0001, regstack[6]);		b43_phy_write(dev, 0x0030, regstack[7]);		b43_radio_write16(dev, 0x0043, regstack[8]);		b43_radio_write16(dev, 0x007A, regstack[9]);		b43_radio_write16(dev, 0x0052,				  (b43_radio_read16(dev, 0x0052) & 0x000F)				  | regstack[11]);		b43_write16(dev, 0x03EC, regstack[10]);	}	b43_phy_write(dev, 0x0015, regstack[0]);}static u16 lo_measure_feedthrough(struct b43_wldev *dev,				  u16 lna, u16 pga, u16 trsw_rx){	struct b43_phy *phy = &dev->phy;	u16 rfover;	u16 feedthrough;	if (phy->gmode) {		lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT;		pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT;		B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA);		B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA);/*FIXME This assertion fails		B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX |				    B43_PHY_RFOVERVAL_BW));*/		trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW);		/* Construct the RF Override Value */		rfover = B43_PHY_RFOVERVAL_UNK;		rfover |= pga;		rfover |= lna;		rfover |= trsw_rx;		if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) &&		    phy->rev > 6)			rfover |= B43_PHY_RFOVERVAL_EXTLNA;		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);		udelay(10);		rfover |= B43_PHY_RFOVERVAL_BW_LBW;		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);		udelay(10);		rfover |= B43_PHY_RFOVERVAL_BW_LPF;		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);		udelay(10);		b43_phy_write(dev, B43_PHY_PGACTL, 0xF300);	} else {		pga |= B43_PHY_PGACTL_UNKNOWN;		b43_phy_write(dev, B43_PHY_PGACTL, pga);		udelay(10);		pga |= B43_PHY_PGACTL_LOWBANDW;		b43_phy_write(dev, B43_PHY_PGACTL, pga);		udelay(10);		pga |= B43_PHY_PGACTL_LPF;		b43_phy_write(dev, B43_PHY_PGACTL, pga);	}	udelay(21);	feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);	/* This is a good place to check if we need to relax a bit,	 * as this is the main function called regularly	 * in the LO calibration. */	cond_resched();	return feedthrough;}/* TXCTL Register and Value Table. * Returns the "TXCTL Register". * "value" is the "TXCTL Value". * "pad_mix_gain" is the PAD Mixer Gain. */static u16 lo_txctl_register_table(struct b43_wldev *dev,				   u16 * value, u16 * pad_mix_gain){	struct b43_phy *phy = &dev->phy;	u16 reg, v, padmix;	if (phy->type == B43_PHYTYPE_B) {		v = 0x30;		if (phy->radio_rev <= 5) {			reg = 0x43;			padmix = 0;		} else {			reg = 0x52;			padmix = 5;		}	} else {		if (phy->rev >= 2 && phy->radio_rev == 8) {			reg = 0x43;			v = 0x10;			padmix = 2;		} else {			reg = 0x52;			v = 0x30;			padmix = 5;		}	}	if (value)		*value = v;	if (pad_mix_gain)		*pad_mix_gain = padmix;	return reg;}static void lo_measure_txctl_values(struct b43_wldev *dev){	struct b43_phy *phy = &dev->phy;	struct b43_txpower_lo_control *lo = phy->lo_control;	u16 reg, mask;	u16 trsw_rx, pga;	u16 radio_pctl_reg;	static const u8 tx_bias_values[] = {		0x09, 0x08, 0x0A, 0x01, 0x00,		0x02, 0x05, 0x04, 0x06,	};	static const u8 tx_magn_values[] = {		0x70, 0x40,	};	if (!has_loopback_gain(phy)) {		radio_pctl_reg = 6;		trsw_rx = 2;		pga = 0;	} else {		int lb_gain;	/* Loopback gain (in dB) */		trsw_rx = 0;		lb_gain = phy->max_lb_gain / 2;		if (lb_gain > 10) {			radio_pctl_reg = 0;			pga = abs(10 - lb_gain) / 6;			pga = limit_value(pga, 0, 15);		} else {			int cmp_val;			int tmp;			pga = 0;			cmp_val = 0x24;			if ((phy->rev >= 2) &&			    (phy->radio_ver == 0x2050) && (phy->radio_rev == 8))				cmp_val = 0x3C;			tmp = lb_gain;			if ((10 - lb_gain) < cmp_val)				tmp = (10 - lb_gain);			if (tmp < 0)				tmp += 6;			else				tmp += 3;			cmp_val /= 4;			tmp /= 4;			if (tmp >= cmp_val)				radio_pctl_reg = cmp_val;			else				radio_pctl_reg = tmp;		}	}	b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)				      & 0xFFF0) | radio_pctl_reg);	b43_phy_set_baseband_attenuation(dev, 2);	reg = lo_txctl_register_table(dev, &mask, NULL);	mask = ~mask;	b43_radio_write16(dev, reg, b43_radio_read16(dev, reg)			  & mask);	if (has_tx_magnification(phy)) {		int i, j;		int feedthrough;		int min_feedth = 0xFFFF;		u8 tx_magn, tx_bias;		for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) {			tx_magn = tx_magn_values[i];			b43_radio_write16(dev, 0x52,					  (b43_radio_read16(dev, 0x52)					   & 0xFF0F) | tx_magn);			for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) {				tx_bias = tx_bias_values[j];				b43_radio_write16(dev, 0x52,						  (b43_radio_read16(dev, 0x52)						   & 0xFFF0) | tx_bias);				feedthrough =				    lo_measure_feedthrough(dev, 0, pga,							   trsw_rx);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -