diff options
Diffstat (limited to 'drivers/net/wireless/b43/phy_common.c')
| -rw-r--r-- | drivers/net/wireless/b43/phy_common.c | 193 | 
1 files changed, 177 insertions, 16 deletions
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index fa7f83fc8db..08244b3b327 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -5,7 +5,7 @@    Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,    Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> -  Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de> +  Copyright (c) 2005-2008 Michael Buesch <m@bues.ch>    Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>    Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -31,6 +31,8 @@  #include "phy_a.h"  #include "phy_n.h"  #include "phy_lp.h" +#include "phy_ht.h" +#include "phy_lcn.h"  #include "b43.h"  #include "main.h" @@ -50,7 +52,7 @@ int b43_phy_allocate(struct b43_wldev *dev)  		phy->ops = &b43_phyops_g;  		break;  	case B43_PHYTYPE_N: -#ifdef CONFIG_B43_NPHY +#ifdef CONFIG_B43_PHY_N  		phy->ops = &b43_phyops_n;  #endif  		break; @@ -59,6 +61,16 @@ int b43_phy_allocate(struct b43_wldev *dev)  		phy->ops = &b43_phyops_lp;  #endif  		break; +	case B43_PHYTYPE_HT: +#ifdef CONFIG_B43_PHY_HT +		phy->ops = &b43_phyops_ht; +#endif +		break; +	case B43_PHYTYPE_LCN: +#ifdef CONFIG_B43_PHY_LCN +		phy->ops = &b43_phyops_lcn; +#endif +		break;  	}  	if (B43_WARN_ON(!phy->ops))  		return -ENODEV; @@ -84,12 +96,16 @@ int b43_phy_init(struct b43_wldev *dev)  	phy->channel = ops->get_default_chan(dev); -	ops->software_rfkill(dev, false); +	phy->ops->switch_analog(dev, true); +	b43_software_rfkill(dev, false); +  	err = ops->init(dev);  	if (err) {  		b43err(dev->wl, "PHY init failed\n");  		goto err_block_rf;  	} +	phy->do_full_init = false; +  	/* Make sure to switch hardware and firmware (SHM) to  	 * the default channel. */  	err = b43_switch_channel(dev, ops->get_default_chan(dev)); @@ -101,10 +117,11 @@ int b43_phy_init(struct b43_wldev *dev)  	return 0;  err_phy_exit: +	phy->do_full_init = true;  	if (ops->exit)  		ops->exit(dev);  err_block_rf: -	ops->software_rfkill(dev, true); +	b43_software_rfkill(dev, true);  	return err;  } @@ -113,7 +130,8 @@ void b43_phy_exit(struct b43_wldev *dev)  {  	const struct b43_phy_operations *ops = dev->phy.ops; -	ops->software_rfkill(dev, true); +	b43_software_rfkill(dev, true); +	dev->phy.do_full_init = true;  	if (ops->exit)  		ops->exit(dev);  } @@ -121,9 +139,9 @@ void b43_phy_exit(struct b43_wldev *dev)  bool b43_has_hardware_pctl(struct b43_wldev *dev)  {  	if (!dev->phy.hardware_power_control) -		return 0; +		return false;  	if (!dev->phy.ops->supports_hwpctl) -		return 0; +		return false;  	return dev->phy.ops->supports_hwpctl(dev);  } @@ -133,7 +151,7 @@ void b43_radio_lock(struct b43_wldev *dev)  #if B43_DEBUG  	B43_WARN_ON(dev->phy.radio_locked); -	dev->phy.radio_locked = 1; +	dev->phy.radio_locked = true;  #endif  	macctl = b43_read32(dev, B43_MMIO_MACCTL); @@ -151,7 +169,7 @@ void b43_radio_unlock(struct b43_wldev *dev)  #if B43_DEBUG  	B43_WARN_ON(!dev->phy.radio_locked); -	dev->phy.radio_locked = 0; +	dev->phy.radio_locked = false;  #endif  	/* Commit any write */ @@ -166,9 +184,9 @@ void b43_phy_lock(struct b43_wldev *dev)  {  #if B43_DEBUG  	B43_WARN_ON(dev->phy.phy_locked); -	dev->phy.phy_locked = 1; +	dev->phy.phy_locked = true;  #endif -	B43_WARN_ON(dev->dev->id.revision < 3); +	B43_WARN_ON(dev->dev->core_rev < 3);  	if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))  		b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); @@ -178,9 +196,9 @@ void b43_phy_unlock(struct b43_wldev *dev)  {  #if B43_DEBUG  	B43_WARN_ON(!dev->phy.phy_locked); -	dev->phy.phy_locked = 0; +	dev->phy.phy_locked = false;  #endif -	B43_WARN_ON(dev->dev->id.revision < 3); +	B43_WARN_ON(dev->dev->core_rev < 3);  	if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))  		b43_power_saving_ctl_bits(dev, 0); @@ -228,9 +246,25 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)  			  (b43_radio_read16(dev, offset) & mask) | set);  } +bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask, +			  u16 value, int delay, int timeout) +{ +	u16 val; +	int i; + +	for (i = 0; i < timeout; i += delay) { +		val = b43_radio_read(dev, offset); +		if ((val & mask) == value) +			return true; +		udelay(delay); +	} +	return false; +} +  u16 b43_phy_read(struct b43_wldev *dev, u16 reg)  {  	assert_mac_suspended(dev); +	dev->phy.writes_counter = 0;  	return dev->phy.ops->phy_read(dev, reg);  } @@ -238,6 +272,10 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)  {  	assert_mac_suspended(dev);  	dev->phy.ops->phy_write(dev, reg, value); +	if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) { +		b43_read16(dev, B43_MMIO_PHY_VER); +		dev->phy.writes_counter = 0; +	}  }  void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg) @@ -280,6 +318,90 @@ void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)  	}  } +void b43_phy_put_into_reset(struct b43_wldev *dev) +{ +	u32 tmp; + +	switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA +	case B43_BUS_BCMA: +		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); +		tmp &= ~B43_BCMA_IOCTL_GMODE; +		tmp |= B43_BCMA_IOCTL_PHY_RESET; +		tmp |= BCMA_IOCTL_FGC; +		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); +		udelay(1); + +		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); +		tmp &= ~BCMA_IOCTL_FGC; +		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); +		udelay(1); +		break; +#endif +#ifdef CONFIG_B43_SSB +	case B43_BUS_SSB: +		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); +		tmp &= ~B43_TMSLOW_GMODE; +		tmp |= B43_TMSLOW_PHYRESET; +		tmp |= SSB_TMSLOW_FGC; +		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); +		usleep_range(1000, 2000); + +		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); +		tmp &= ~SSB_TMSLOW_FGC; +		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); +		usleep_range(1000, 2000); + +		break; +#endif +	} +} + +void b43_phy_take_out_of_reset(struct b43_wldev *dev) +{ +	u32 tmp; + +	switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA +	case B43_BUS_BCMA: +		/* Unset reset bit (with forcing clock) */ +		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); +		tmp &= ~B43_BCMA_IOCTL_PHY_RESET; +		tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN; +		tmp |= BCMA_IOCTL_FGC; +		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); +		udelay(1); + +		/* Do not force clock anymore */ +		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); +		tmp &= ~BCMA_IOCTL_FGC; +		tmp |= B43_BCMA_IOCTL_PHY_CLKEN; +		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); +		udelay(1); +		break; +#endif +#ifdef CONFIG_B43_SSB +	case B43_BUS_SSB: +		/* Unset reset bit (with forcing clock) */ +		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); +		tmp &= ~B43_TMSLOW_PHYRESET; +		tmp &= ~B43_TMSLOW_PHYCLKEN; +		tmp |= SSB_TMSLOW_FGC; +		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); +		ssb_read32(dev->dev->sdev, SSB_TMSLOW); /* flush */ +		usleep_range(1000, 2000); + +		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); +		tmp &= ~SSB_TMSLOW_FGC; +		tmp |= B43_TMSLOW_PHYCLKEN; +		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); +		ssb_read32(dev->dev->sdev, SSB_TMSLOW); /* flush */ +		usleep_range(1000, 2000); +		break; +#endif +	} +} +  int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)  {  	struct b43_phy *phy = &(dev->phy); @@ -363,8 +485,8 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)  	/* The next check will be needed in two seconds, or later. */  	phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2)); -	if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && -	    (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306)) +	if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) && +	    (dev->dev->board_type == SSB_BOARD_BU4306))  		return; /* No software txpower adjustment needed */  	result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI)); @@ -411,7 +533,7 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)  	average = (a + b + c + d + 2) / 4;  	if (is_ofdm) {  		/* Adjust for CCK-boost */ -		if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO) +		if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1)  		    & B43_HF_CCKBOOST)  			average = (average >= 13) ? (average - 13) : 0;  	} @@ -424,6 +546,45 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)  	b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);  } + +bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type) +{ +	return (channel_type == NL80211_CHAN_HT40MINUS || +		channel_type == NL80211_CHAN_HT40PLUS); +} + +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ +void b43_phy_force_clock(struct b43_wldev *dev, bool force) +{ +	u32 tmp; + +	WARN_ON(dev->phy.type != B43_PHYTYPE_N && +		dev->phy.type != B43_PHYTYPE_HT); + +	switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA +	case B43_BUS_BCMA: +		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); +		if (force) +			tmp |= BCMA_IOCTL_FGC; +		else +			tmp &= ~BCMA_IOCTL_FGC; +		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); +		break; +#endif +#ifdef CONFIG_B43_SSB +	case B43_BUS_SSB: +		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); +		if (force) +			tmp |= SSB_TMSLOW_FGC; +		else +			tmp &= ~SSB_TMSLOW_FGC; +		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); +		break; +#endif +	} +} +  /* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */  struct b43_c32 b43_cordic(int theta)  {  | 
