6479ef780d
The Linux ath9k btcoex code is based off of this code. Note this doesn't actually implement functional btcoex; there's some driver glue and a whole lot of verification that is required. On the other hand, I do have the AR9285+BT and AR9287+BT NICs which this code supports.. Obtained from: Qualcomm Atheros, Linux ath9k
136 lines
5.1 KiB
C
136 lines
5.1 KiB
C
/*
|
|
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
|
|
* Copyright (c) 2002-2005 Atheros Communications, Inc.
|
|
* Copyright (c) 2008-2010, Atheros Communications Inc.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include "opt_ah.h"
|
|
|
|
#include "ah.h"
|
|
#include "ah_internal.h"
|
|
#include "ah_devid.h"
|
|
#ifdef AH_DEBUG
|
|
#include "ah_desc.h" /* NB: for HAL_PHYERR* */
|
|
#endif
|
|
|
|
#include "ar5416/ar5416.h"
|
|
#include "ar5416/ar5416reg.h"
|
|
#include "ar5416/ar5416phy.h"
|
|
#include "ar5416/ar5416desc.h" /* AR5416_CONTTXMODE */
|
|
|
|
#include "ar9002/ar9285phy.h"
|
|
#include "ar9002/ar9285.h"
|
|
|
|
/*
|
|
* This is specific to Kite.
|
|
*
|
|
* Kiwi and others don't have antenna diversity like this.
|
|
*/
|
|
void
|
|
ar9285BTCoexAntennaDiversity(struct ath_hal *ah)
|
|
{
|
|
struct ath_hal_5416 *ahp = AH5416(ah);
|
|
u_int32_t regVal;
|
|
u_int8_t ant_div_control1, ant_div_control2;
|
|
|
|
if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ALLOW) ||
|
|
(AH5212(ah)->ah_diversity != HAL_ANT_VARIABLE)) {
|
|
if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ENABLE) &&
|
|
(AH5212(ah)->ah_diversity == HAL_ANT_VARIABLE)) {
|
|
/* Enable antenna diversity */
|
|
ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_ENABLE;
|
|
ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_ENABLE;
|
|
|
|
/* Don't disable BT ant to allow BB to control SWCOM */
|
|
ahp->ah_btCoexMode2 &= (~(AR_BT_DISABLE_BT_ANT));
|
|
OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
|
|
|
|
/* Program the correct SWCOM table */
|
|
OS_REG_WRITE(ah, AR_PHY_SWITCH_COM,
|
|
HAL_BT_COEX_ANT_DIV_SWITCH_COM);
|
|
OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
|
|
} else if (AH5212(ah)->ah_diversity == HAL_ANT_FIXED_B) {
|
|
/* Disable antenna diversity. Use antenna B(LNA2) only. */
|
|
ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_B;
|
|
ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_B;
|
|
|
|
/* Disable BT ant to allow concurrent BT and WLAN receive */
|
|
ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
|
|
OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
|
|
|
|
/* Program SWCOM talbe to make sure RF switch always parks at WLAN side */
|
|
OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, HAL_BT_COEX_ANT_DIV_SWITCH_COM);
|
|
OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0x60000000, 0xf0000000);
|
|
} else {
|
|
/* Disable antenna diversity. Use antenna A(LNA1) only */
|
|
ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_A;
|
|
ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_A;
|
|
|
|
/* Disable BT ant to allow concurrent BT and WLAN receive */
|
|
ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
|
|
OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
|
|
|
|
/* Program SWCOM talbe to make sure RF switch always parks at BT side */
|
|
OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, 0);
|
|
OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
|
|
}
|
|
|
|
regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
|
|
regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
|
|
/* Clear ant_fast_div_bias [14:9] since for Janus the main LNA is always LNA1. */
|
|
regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS));
|
|
|
|
regVal |= SM(ant_div_control1, AR_PHY_9285_ANT_DIV_CTL);
|
|
regVal |= SM(ant_div_control2, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
|
|
regVal |= SM((ant_div_control2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
|
|
regVal |= SM((ant_div_control1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB);
|
|
regVal |= SM((ant_div_control1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
|
|
OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
|
|
|
|
regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
|
|
regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
|
|
regVal |= SM((ant_div_control1 >> 3), AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
|
|
OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
|
|
}
|
|
}
|
|
|
|
void
|
|
ar9285BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value)
|
|
{
|
|
struct ath_hal_5416 *ahp = AH5416(ah);
|
|
|
|
switch (type) {
|
|
case HAL_BT_COEX_ANTENNA_DIVERSITY:
|
|
if (AR_SREV_KITE(ah)) {
|
|
ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_ANT_DIV_ALLOW;
|
|
if (value)
|
|
ahp->ah_btCoexFlag |=
|
|
HAL_BT_COEX_FLAG_ANT_DIV_ENABLE;
|
|
else
|
|
ahp->ah_btCoexFlag &=
|
|
~HAL_BT_COEX_FLAG_ANT_DIV_ENABLE;
|
|
ar9285BTCoexAntennaDiversity(ah);
|
|
}
|
|
break;
|
|
default:
|
|
ar5416BTCoexSetParameter(ah, type, value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|