2008-08-27 20:53:02 +04:00
/*
Broadcom B43 wireless driver
Common PHY routines
Copyright ( c ) 2005 Martin Langer < martin - langer @ gmx . de > ,
Copyright ( c ) 2005 - 2007 Stefano Brivio < stefano . brivio @ polimi . it >
2011-07-04 22:50:05 +04:00
Copyright ( c ) 2005 - 2008 Michael Buesch < m @ bues . ch >
2008-08-27 20:53:02 +04:00
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 "phy_common.h"
# include "phy_g.h"
# include "phy_a.h"
2008-08-30 04:27:19 +04:00
# include "phy_n.h"
2008-08-30 12:55:48 +04:00
# include "phy_lp.h"
2011-06-13 18:20:06 +04:00
# include "phy_ht.h"
2011-07-07 20:58:25 +04:00
# include "phy_lcn.h"
2008-08-27 20:53:02 +04:00
# include "b43.h"
# include "main.h"
2008-09-02 15:00:34 +04:00
int b43_phy_allocate ( struct b43_wldev * dev )
2008-08-27 20:53:02 +04:00
{
struct b43_phy * phy = & ( dev - > phy ) ;
int err ;
phy - > ops = NULL ;
switch ( phy - > type ) {
case B43_PHYTYPE_G :
2014-06-20 19:22:01 +04:00
# ifdef CONFIG_B43_PHY_G
2008-08-27 20:53:02 +04:00
phy - > ops = & b43_phyops_g ;
2014-06-20 19:22:01 +04:00
# endif
2008-08-27 20:53:02 +04:00
break ;
case B43_PHYTYPE_N :
2010-12-07 23:56:00 +03:00
# ifdef CONFIG_B43_PHY_N
2008-08-27 20:53:02 +04:00
phy - > ops = & b43_phyops_n ;
# endif
break ;
case B43_PHYTYPE_LP :
2008-08-30 12:55:48 +04:00
# ifdef CONFIG_B43_PHY_LP
phy - > ops = & b43_phyops_lp ;
2011-06-13 18:20:06 +04:00
# endif
break ;
case B43_PHYTYPE_HT :
# ifdef CONFIG_B43_PHY_HT
phy - > ops = & b43_phyops_ht ;
2011-07-07 20:58:25 +04:00
# endif
break ;
case B43_PHYTYPE_LCN :
# ifdef CONFIG_B43_PHY_LCN
phy - > ops = & b43_phyops_lcn ;
2008-08-30 12:55:48 +04:00
# endif
2008-08-27 20:53:02 +04:00
break ;
}
if ( B43_WARN_ON ( ! phy - > ops ) )
return - ENODEV ;
err = phy - > ops - > allocate ( dev ) ;
if ( err )
phy - > ops = NULL ;
return err ;
}
2008-09-02 15:00:34 +04:00
void b43_phy_free ( struct b43_wldev * dev )
{
dev - > phy . ops - > free ( dev ) ;
dev - > phy . ops = NULL ;
}
2008-08-27 20:53:02 +04:00
int b43_phy_init ( struct b43_wldev * dev )
{
struct b43_phy * phy = & dev - > phy ;
const struct b43_phy_operations * ops = phy - > ops ;
int err ;
2014-05-31 22:49:38 +04:00
/* During PHY init we need to use some channel. On the first init this
* function is called * before * b43_op_config , so our pointer is NULL .
*/
if ( ! phy - > chandef ) {
phy - > chandef = & dev - > wl - > hw - > conf . chandef ;
phy - > channel = phy - > chandef - > chan - > hw_value ;
}
2008-08-27 20:53:02 +04:00
2014-05-18 01:24:56 +04:00
phy - > ops - > switch_analog ( dev , true ) ;
2014-04-22 15:54:36 +04:00
b43_software_rfkill ( dev , false ) ;
2014-05-28 00:07:31 +04:00
2008-08-27 20:53:02 +04:00
err = ops - > init ( dev ) ;
if ( err ) {
b43err ( dev - > wl , " PHY init failed \n " ) ;
goto err_block_rf ;
}
2014-05-28 00:07:31 +04:00
phy - > do_full_init = false ;
2014-05-31 22:49:36 +04:00
err = b43_switch_channel ( dev , phy - > channel ) ;
2008-08-27 20:53:02 +04:00
if ( err ) {
b43err ( dev - > wl , " PHY init: Channel switch to default failed \n " ) ;
goto err_phy_exit ;
}
return 0 ;
err_phy_exit :
2014-05-28 00:07:31 +04:00
phy - > do_full_init = true ;
2008-08-27 20:53:02 +04:00
if ( ops - > exit )
ops - > exit ( dev ) ;
err_block_rf :
2014-04-22 15:54:36 +04:00
b43_software_rfkill ( dev , true ) ;
2008-08-27 20:53:02 +04:00
return err ;
}
void b43_phy_exit ( struct b43_wldev * dev )
{
const struct b43_phy_operations * ops = dev - > phy . ops ;
2014-04-22 15:54:36 +04:00
b43_software_rfkill ( dev , true ) ;
2014-05-28 00:07:31 +04:00
dev - > phy . do_full_init = true ;
2008-08-27 20:53:02 +04:00
if ( ops - > exit )
ops - > exit ( dev ) ;
}
bool b43_has_hardware_pctl ( struct b43_wldev * dev )
{
if ( ! dev - > phy . hardware_power_control )
2014-02-16 18:31:38 +04:00
return false ;
2008-08-27 20:53:02 +04:00
if ( ! dev - > phy . ops - > supports_hwpctl )
2014-02-16 18:31:38 +04:00
return false ;
2008-08-27 20:53:02 +04:00
return dev - > phy . ops - > supports_hwpctl ( dev ) ;
}
void b43_radio_lock ( struct b43_wldev * dev )
{
u32 macctl ;
2009-03-31 14:27:32 +04:00
# if B43_DEBUG
B43_WARN_ON ( dev - > phy . radio_locked ) ;
2011-12-19 17:56:45 +04:00
dev - > phy . radio_locked = true ;
2009-03-31 14:27:32 +04:00
# endif
2008-08-27 20:53:02 +04:00
macctl = b43_read32 ( dev , B43_MMIO_MACCTL ) ;
macctl | = B43_MACCTL_RADIOLOCK ;
b43_write32 ( dev , B43_MMIO_MACCTL , macctl ) ;
2009-03-31 14:27:32 +04:00
/* Commit the write and wait for the firmware
* to finish any radio register access . */
2008-08-27 20:53:02 +04:00
b43_read32 ( dev , B43_MMIO_MACCTL ) ;
udelay ( 10 ) ;
}
void b43_radio_unlock ( struct b43_wldev * dev )
{
u32 macctl ;
2009-03-31 14:27:32 +04:00
# if B43_DEBUG
B43_WARN_ON ( ! dev - > phy . radio_locked ) ;
2011-12-19 17:56:45 +04:00
dev - > phy . radio_locked = false ;
2009-03-31 14:27:32 +04:00
# endif
2008-08-27 20:53:02 +04:00
/* Commit any write */
b43_read16 ( dev , B43_MMIO_PHY_VER ) ;
/* unlock */
macctl = b43_read32 ( dev , B43_MMIO_MACCTL ) ;
macctl & = ~ B43_MACCTL_RADIOLOCK ;
b43_write32 ( dev , B43_MMIO_MACCTL , macctl ) ;
}
void b43_phy_lock ( struct b43_wldev * dev )
{
# if B43_DEBUG
B43_WARN_ON ( dev - > phy . phy_locked ) ;
2011-12-19 17:56:45 +04:00
dev - > phy . phy_locked = true ;
2008-08-27 20:53:02 +04:00
# endif
2011-05-18 04:06:38 +04:00
B43_WARN_ON ( dev - > dev - > core_rev < 3 ) ;
2008-08-27 20:53:02 +04:00
2008-09-11 02:01:58 +04:00
if ( ! b43_is_mode ( dev - > wl , NL80211_IFTYPE_AP ) )
2008-08-27 20:53:02 +04:00
b43_power_saving_ctl_bits ( dev , B43_PS_AWAKE ) ;
}
void b43_phy_unlock ( struct b43_wldev * dev )
{
# if B43_DEBUG
B43_WARN_ON ( ! dev - > phy . phy_locked ) ;
2011-12-19 17:56:45 +04:00
dev - > phy . phy_locked = false ;
2008-08-27 20:53:02 +04:00
# endif
2011-05-18 04:06:38 +04:00
B43_WARN_ON ( dev - > dev - > core_rev < 3 ) ;
2008-08-27 20:53:02 +04:00
2008-09-11 02:01:58 +04:00
if ( ! b43_is_mode ( dev - > wl , NL80211_IFTYPE_AP ) )
2008-08-27 20:53:02 +04:00
b43_power_saving_ctl_bits ( dev , 0 ) ;
}
2008-12-19 00:13:39 +03:00
static inline void assert_mac_suspended ( struct b43_wldev * dev )
{
if ( ! B43_DEBUG )
return ;
if ( ( b43_status ( dev ) > = B43_STAT_INITIALIZED ) & &
( dev - > mac_suspended < = 0 ) ) {
b43dbg ( dev - > wl , " PHY/RADIO register access with "
" enabled MAC. \n " ) ;
dump_stack ( ) ;
}
}
2008-08-27 20:53:02 +04:00
u16 b43_radio_read ( struct b43_wldev * dev , u16 reg )
{
2008-12-19 00:13:39 +03:00
assert_mac_suspended ( dev ) ;
2014-07-31 23:59:42 +04:00
dev - > phy . writes_counter = 0 ;
2008-08-27 20:53:02 +04:00
return dev - > phy . ops - > radio_read ( dev , reg ) ;
}
void b43_radio_write ( struct b43_wldev * dev , u16 reg , u16 value )
{
2008-12-19 00:13:39 +03:00
assert_mac_suspended ( dev ) ;
2014-07-31 23:59:42 +04:00
if ( b43_bus_host_is_pci ( dev - > dev ) & &
+ + dev - > phy . writes_counter > B43_MAX_WRITES_IN_ROW ) {
b43_read32 ( dev , B43_MMIO_MACCTL ) ;
dev - > phy . writes_counter = 1 ;
}
2008-08-27 20:53:02 +04:00
dev - > phy . ops - > radio_write ( dev , reg , value ) ;
}
void b43_radio_mask ( struct b43_wldev * dev , u16 offset , u16 mask )
{
b43_radio_write16 ( dev , offset ,
b43_radio_read16 ( dev , offset ) & mask ) ;
}
void b43_radio_set ( struct b43_wldev * dev , u16 offset , u16 set )
{
b43_radio_write16 ( dev , offset ,
b43_radio_read16 ( dev , offset ) | set ) ;
}
void b43_radio_maskset ( struct b43_wldev * dev , u16 offset , u16 mask , u16 set )
{
b43_radio_write16 ( dev , offset ,
( b43_radio_read16 ( dev , offset ) & mask ) | set ) ;
}
2012-07-26 02:07:37 +04:00
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 ;
}
2008-08-27 20:53:02 +04:00
u16 b43_phy_read ( struct b43_wldev * dev , u16 reg )
{
2008-12-19 00:13:39 +03:00
assert_mac_suspended ( dev ) ;
2010-12-07 11:42:07 +03:00
dev - > phy . writes_counter = 0 ;
2014-07-31 23:59:43 +04:00
if ( dev - > phy . ops - > phy_read )
return dev - > phy . ops - > phy_read ( dev , reg ) ;
b43_write16 ( dev , B43_MMIO_PHY_CONTROL , reg ) ;
return b43_read16 ( dev , B43_MMIO_PHY_DATA ) ;
2008-08-27 20:53:02 +04:00
}
void b43_phy_write ( struct b43_wldev * dev , u16 reg , u16 value )
{
2008-12-19 00:13:39 +03:00
assert_mac_suspended ( dev ) ;
2014-07-31 23:59:42 +04:00
if ( b43_bus_host_is_pci ( dev - > dev ) & &
+ + dev - > phy . writes_counter > B43_MAX_WRITES_IN_ROW ) {
2010-12-07 11:42:07 +03:00
b43_read16 ( dev , B43_MMIO_PHY_VER ) ;
2014-07-31 23:59:42 +04:00
dev - > phy . writes_counter = 1 ;
2010-12-07 11:42:07 +03:00
}
2014-07-31 23:59:43 +04:00
if ( dev - > phy . ops - > phy_write )
return dev - > phy . ops - > phy_write ( dev , reg , value ) ;
b43_write16 ( dev , B43_MMIO_PHY_CONTROL , reg ) ;
b43_write16 ( dev , B43_MMIO_PHY_DATA , value ) ;
2008-08-27 20:53:02 +04:00
}
2009-08-03 03:28:12 +04:00
void b43_phy_copy ( struct b43_wldev * dev , u16 destreg , u16 srcreg )
{
assert_mac_suspended ( dev ) ;
dev - > phy . ops - > phy_write ( dev , destreg ,
dev - > phy . ops - > phy_read ( dev , srcreg ) ) ;
}
2008-08-27 20:53:02 +04:00
void b43_phy_mask ( struct b43_wldev * dev , u16 offset , u16 mask )
{
b43: Fix and update LP-PHY code
-Fix a few nasty typos (b43_phy_* operations instead of b43_radio_*)
in the channel tune routines.
-Fix some typos & spec errors found by MMIO tracing.
-Optimize b43_phy_write & b43_phy_mask/set/maskset to use
only the minimal number of MMIO accesses. (Write is possible
using a single 32-bit MMIO write, while set/mask/maskset can
be done in 3 16-bit MMIOs).
-Set the default channel back to 1, as the bug forcing us to use
channel 7 is now fixed.
With this, the device comes up, scans, associates, transmits,
receives, monitors and injects on all channels - in other words,
it's fully functional. Sensitivity and TX power are still sub-optimal,
due to the lack of calibration (that's next on my list).
Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-08-26 22:51:25 +04:00
if ( dev - > phy . ops - > phy_maskset ) {
assert_mac_suspended ( dev ) ;
dev - > phy . ops - > phy_maskset ( dev , offset , mask , 0 ) ;
} else {
b43_phy_write ( dev , offset ,
b43_phy_read ( dev , offset ) & mask ) ;
}
2008-08-27 20:53:02 +04:00
}
void b43_phy_set ( struct b43_wldev * dev , u16 offset , u16 set )
{
b43: Fix and update LP-PHY code
-Fix a few nasty typos (b43_phy_* operations instead of b43_radio_*)
in the channel tune routines.
-Fix some typos & spec errors found by MMIO tracing.
-Optimize b43_phy_write & b43_phy_mask/set/maskset to use
only the minimal number of MMIO accesses. (Write is possible
using a single 32-bit MMIO write, while set/mask/maskset can
be done in 3 16-bit MMIOs).
-Set the default channel back to 1, as the bug forcing us to use
channel 7 is now fixed.
With this, the device comes up, scans, associates, transmits,
receives, monitors and injects on all channels - in other words,
it's fully functional. Sensitivity and TX power are still sub-optimal,
due to the lack of calibration (that's next on my list).
Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-08-26 22:51:25 +04:00
if ( dev - > phy . ops - > phy_maskset ) {
assert_mac_suspended ( dev ) ;
dev - > phy . ops - > phy_maskset ( dev , offset , 0xFFFF , set ) ;
} else {
b43_phy_write ( dev , offset ,
b43_phy_read ( dev , offset ) | set ) ;
}
2008-08-27 20:53:02 +04:00
}
void b43_phy_maskset ( struct b43_wldev * dev , u16 offset , u16 mask , u16 set )
{
b43: Fix and update LP-PHY code
-Fix a few nasty typos (b43_phy_* operations instead of b43_radio_*)
in the channel tune routines.
-Fix some typos & spec errors found by MMIO tracing.
-Optimize b43_phy_write & b43_phy_mask/set/maskset to use
only the minimal number of MMIO accesses. (Write is possible
using a single 32-bit MMIO write, while set/mask/maskset can
be done in 3 16-bit MMIOs).
-Set the default channel back to 1, as the bug forcing us to use
channel 7 is now fixed.
With this, the device comes up, scans, associates, transmits,
receives, monitors and injects on all channels - in other words,
it's fully functional. Sensitivity and TX power are still sub-optimal,
due to the lack of calibration (that's next on my list).
Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-08-26 22:51:25 +04:00
if ( dev - > phy . ops - > phy_maskset ) {
assert_mac_suspended ( dev ) ;
dev - > phy . ops - > phy_maskset ( dev , offset , mask , set ) ;
} else {
b43_phy_write ( dev , offset ,
( b43_phy_read ( dev , offset ) & mask ) | set ) ;
}
2008-08-27 20:53:02 +04:00
}
2014-05-18 01:24:54 +04:00
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 :
2014-05-18 01:24:55 +04:00
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 ) ;
2014-05-18 01:24:54 +04:00
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 ) ;
2014-05-18 01:24:55 +04:00
usleep_range ( 1000 , 2000 ) ;
2014-05-18 01:24:54 +04:00
tmp = ssb_read32 ( dev - > dev - > sdev , SSB_TMSLOW ) ;
tmp & = ~ SSB_TMSLOW_FGC ;
ssb_write32 ( dev - > dev - > sdev , SSB_TMSLOW , tmp ) ;
2014-05-18 01:24:55 +04:00
usleep_range ( 1000 , 2000 ) ;
2014-05-18 01:24:54 +04:00
break ;
# endif
}
}
2014-05-18 01:24:55 +04:00
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
}
}
2008-08-27 20:53:02 +04:00
int b43_switch_channel ( struct b43_wldev * dev , unsigned int new_channel )
{
struct b43_phy * phy = & ( dev - > phy ) ;
u16 channelcookie , savedcookie ;
int err ;
/* First we set the channel radio code to prevent the
* firmware from sending ghost packets .
*/
channelcookie = new_channel ;
if ( b43_current_band ( dev - > wl ) = = IEEE80211_BAND_5GHZ )
2010-10-06 09:50:07 +04:00
channelcookie | = B43_SHM_SH_CHAN_5GHZ ;
/* FIXME: set 40Mhz flag if required */
if ( 0 )
channelcookie | = B43_SHM_SH_CHAN_40MHZ ;
2008-08-27 20:53:02 +04:00
savedcookie = b43_shm_read16 ( dev , B43_SHM_SHARED , B43_SHM_SH_CHAN ) ;
b43_shm_write16 ( dev , B43_SHM_SHARED , B43_SHM_SH_CHAN , channelcookie ) ;
/* Now try to switch the PHY hardware channel. */
err = phy - > ops - > switch_channel ( dev , new_channel ) ;
if ( err )
goto err_restore_cookie ;
/* Wait for the radio to tune to the channel and stabilize. */
msleep ( 8 ) ;
return 0 ;
err_restore_cookie :
b43_shm_write16 ( dev , B43_SHM_SHARED ,
B43_SHM_SH_CHAN , savedcookie ) ;
return err ;
}
2009-06-02 15:01:37 +04:00
void b43_software_rfkill ( struct b43_wldev * dev , bool blocked )
2008-08-27 20:53:02 +04:00
{
struct b43_phy * phy = & dev - > phy ;
2008-12-19 20:40:00 +03:00
b43_mac_suspend ( dev ) ;
2009-06-02 15:01:37 +04:00
phy - > ops - > software_rfkill ( dev , blocked ) ;
phy - > radio_on = ! blocked ;
2008-12-19 20:40:00 +03:00
b43_mac_enable ( dev ) ;
2008-08-27 20:53:02 +04:00
}
2008-08-28 21:33:40 +04:00
/**
* b43_phy_txpower_adjust_work - TX power workqueue .
*
* Workqueue for updating the TX power parameters in hardware .
*/
void b43_phy_txpower_adjust_work ( struct work_struct * work )
{
struct b43_wl * wl = container_of ( work , struct b43_wl ,
txpower_adjust_work ) ;
struct b43_wldev * dev ;
mutex_lock ( & wl - > mutex ) ;
dev = wl - > current_dev ;
if ( likely ( dev & & ( b43_status ( dev ) > = B43_STAT_STARTED ) ) )
dev - > phy . ops - > adjust_txpower ( dev ) ;
mutex_unlock ( & wl - > mutex ) ;
}
void b43_phy_txpower_check ( struct b43_wldev * dev , unsigned int flags )
{
struct b43_phy * phy = & dev - > phy ;
unsigned long now = jiffies ;
enum b43_txpwr_result result ;
if ( ! ( flags & B43_TXPWR_IGNORE_TIME ) ) {
/* Check if it's time for a TXpower check. */
if ( time_before ( now , phy - > next_txpwr_check_time ) )
return ; /* Not yet */
}
/* The next check will be needed in two seconds, or later. */
phy - > next_txpwr_check_time = round_jiffies ( now + ( HZ * 2 ) ) ;
2011-05-18 04:06:42 +04:00
if ( ( dev - > dev - > board_vendor = = SSB_BOARDVENDOR_BCM ) & &
( dev - > dev - > board_type = = SSB_BOARD_BU4306 ) )
2008-08-28 21:33:40 +04:00
return ; /* No software txpower adjustment needed */
result = phy - > ops - > recalc_txpower ( dev , ! ! ( flags & B43_TXPWR_IGNORE_TSSI ) ) ;
if ( result = = B43_TXPWR_RES_DONE )
return ; /* We are done. */
B43_WARN_ON ( result ! = B43_TXPWR_RES_NEED_ADJUST ) ;
B43_WARN_ON ( phy - > ops - > adjust_txpower = = NULL ) ;
/* We must adjust the transmission power in hardware.
* Schedule b43_phy_txpower_adjust_work ( ) . */
2009-07-30 04:08:07 +04:00
ieee80211_queue_work ( dev - > wl - > hw , & dev - > wl - > txpower_adjust_work ) ;
2008-08-28 21:33:40 +04:00
}
int b43_phy_shm_tssi_read ( struct b43_wldev * dev , u16 shm_offset )
{
const bool is_ofdm = ( shm_offset ! = B43_SHM_SH_TSSI_CCK ) ;
unsigned int a , b , c , d ;
unsigned int average ;
u32 tmp ;
tmp = b43_shm_read32 ( dev , B43_SHM_SHARED , shm_offset ) ;
a = tmp & 0xFF ;
b = ( tmp > > 8 ) & 0xFF ;
c = ( tmp > > 16 ) & 0xFF ;
d = ( tmp > > 24 ) & 0xFF ;
if ( a = = 0 | | a = = B43_TSSI_MAX | |
b = = 0 | | b = = B43_TSSI_MAX | |
c = = 0 | | c = = B43_TSSI_MAX | |
d = = 0 | | d = = B43_TSSI_MAX )
return - ENOENT ;
/* The values are OK. Clear them. */
tmp = B43_TSSI_MAX | ( B43_TSSI_MAX < < 8 ) |
( B43_TSSI_MAX < < 16 ) | ( B43_TSSI_MAX < < 24 ) ;
b43_shm_write32 ( dev , B43_SHM_SHARED , shm_offset , tmp ) ;
if ( is_ofdm ) {
a = ( a + 32 ) & 0x3F ;
b = ( b + 32 ) & 0x3F ;
c = ( c + 32 ) & 0x3F ;
d = ( d + 32 ) & 0x3F ;
}
/* Get the average of the values with 0.5 added to each value. */
average = ( a + b + c + d + 2 ) / 4 ;
if ( is_ofdm ) {
/* Adjust for CCK-boost */
2012-07-25 18:58:38 +04:00
if ( b43_shm_read16 ( dev , B43_SHM_SHARED , B43_SHM_SH_HOSTF1 )
2008-08-28 21:33:40 +04:00
& B43_HF_CCKBOOST )
average = ( average > = 13 ) ? ( average - 13 ) : 0 ;
}
return average ;
}
2008-09-03 14:12:20 +04:00
void b43_phyop_switch_analog_generic ( struct b43_wldev * dev , bool on )
{
b43_write16 ( dev , B43_MMIO_PHY0 , on ? 0 : 0xF4 ) ;
}
2010-01-25 20:59:59 +03:00
2010-12-07 23:55:58 +03:00
2014-05-31 22:49:40 +04:00
bool b43_is_40mhz ( struct b43_wldev * dev )
{
return dev - > phy . chandef - > width = = NL80211_CHAN_WIDTH_40 ;
}
2011-08-12 02:03:26 +04:00
/* 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
}
}
2010-01-25 21:00:00 +03:00
/* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */
2010-01-25 20:59:59 +03:00
struct b43_c32 b43_cordic ( int theta )
{
2010-11-21 05:38:56 +03:00
static const u32 arctg [ ] = {
2949120 , 1740967 , 919879 , 466945 , 234379 , 117304 ,
58666 , 29335 , 14668 , 7334 , 3667 , 1833 ,
917 , 458 , 229 , 115 , 57 , 29 ,
} ;
2010-01-25 21:00:00 +03:00
u8 i ;
s32 tmp ;
s8 signx = 1 ;
u32 angle = 0 ;
2010-01-25 20:59:59 +03:00
struct b43_c32 ret = { . i = 39797 , . q = 0 , } ;
2010-01-25 21:00:00 +03:00
while ( theta > ( 180 < < 16 ) )
theta - = ( 360 < < 16 ) ;
while ( theta < - ( 180 < < 16 ) )
theta + = ( 360 < < 16 ) ;
2010-01-25 20:59:59 +03:00
2010-01-25 21:00:00 +03:00
if ( theta > ( 90 < < 16 ) ) {
theta - = ( 180 < < 16 ) ;
2010-01-25 20:59:59 +03:00
signx = - 1 ;
2010-01-25 21:00:00 +03:00
} else if ( theta < - ( 90 < < 16 ) ) {
theta + = ( 180 < < 16 ) ;
2010-01-25 20:59:59 +03:00
signx = - 1 ;
}
for ( i = 0 ; i < = 17 ; i + + ) {
if ( theta > angle ) {
tmp = ret . i - ( ret . q > > i ) ;
ret . q + = ret . i > > i ;
ret . i = tmp ;
angle + = arctg [ i ] ;
} else {
tmp = ret . i + ( ret . q > > i ) ;
ret . q - = ret . i > > i ;
ret . i = tmp ;
angle - = arctg [ i ] ;
}
}
ret . i * = signx ;
ret . q * = signx ;
return ret ;
}