2015-03-10 08:31:51

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 0/7] ath9k patches

From: Sujith Manoharan <[email protected]>

This series adds initial support for AIC.

Active Interference Cancellation is a method
implemented in the HW to counter WLAN RX
sensitivity degradation when BT is transmitting
at the same time. This feature is supported by
cards like WB222 based on AR9462.

Sujith Manoharan (7):
ath9k: Add initial structures for AIC
ath9k: Register private AIC ops
ath9k: Add register definitions for AIC
ath9k: Handle MCI_STATE_AIC_CAL_SINGLE
ath9k: Finish AIC calibration
ath9k: Process the AIC calibration results
ath9k: Disable AIC by default

drivers/net/wireless/ath/ath9k/Makefile | 3 +-
drivers/net/wireless/ath/ath9k/ar9003_aic.c | 534 ++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/ar9003_aic.h | 58 +++
drivers/net/wireless/ath/ath9k/ar9003_hw.c | 1 +
drivers/net/wireless/ath/ath9k/ar9003_mci.c | 5 +
drivers/net/wireless/ath/ath9k/ar9003_phy.h | 25 --
drivers/net/wireless/ath/ath9k/btcoex.h | 12 +
drivers/net/wireless/ath/ath9k/hw-ops.h | 8 +
drivers/net/wireless/ath/ath9k/hw.h | 6 +
drivers/net/wireless/ath/ath9k/reg_aic.h | 168 +++++++++
10 files changed, 794 insertions(+), 26 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_aic.c
create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_aic.h
create mode 100644 drivers/net/wireless/ath/ath9k/reg_aic.h

--
2.3.1



2015-03-10 08:31:56

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 3/7] ath9k: Add register definitions for AIC

From: Sujith Manoharan <[email protected]>

Various registers to control and check AIC
status.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_aic.c | 1 +
drivers/net/wireless/ath/ath9k/ar9003_phy.h | 25 -----
drivers/net/wireless/ath/ath9k/reg_aic.h | 168 ++++++++++++++++++++++++++++
3 files changed, 169 insertions(+), 25 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath9k/reg_aic.h

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
index 0cd159d..cc1e97b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
@@ -18,6 +18,7 @@
#include "hw-ops.h"
#include "ar9003_mci.h"
#include "ar9003_aic.h"
+#include "reg_aic.h"

static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
{
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index c311b2b..fc595b9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -640,16 +640,6 @@
#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE 0x0000ff00
#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE_S 8

-/* AIC Registers */
-#define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0)
-#define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4)
-#define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8)
-#define AR_PHY_AIC_CTRL_3_B0 (AR_SM_BASE + 0x4bc)
-#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + 0x4c4))
-#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + 0x4c8))
-#define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0)
-#define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc)
-
#define AR_PHY_65NM_CH0_TXRF3 0x16048
#define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G 0x0000001e
#define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G_S 1
@@ -989,21 +979,6 @@
#define AR_PHY_TX_IQCAL_STATUS_B1 (AR_SM1_BASE + 0x48c)
#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i) (AR_SM1_BASE + 0x450 + ((_i) << 2))

-/* SM 1 AIC Registers */
-
-#define AR_PHY_AIC_CTRL_0_B1 (AR_SM1_BASE + 0x4b0)
-#define AR_PHY_AIC_CTRL_1_B1 (AR_SM1_BASE + 0x4b4)
-#define AR_PHY_AIC_CTRL_2_B1 (AR_SM1_BASE + 0x4b8)
-#define AR_PHY_AIC_STAT_0_B1 (AR_SM1_BASE + (AR_SREV_9462_10(ah) ? \
- 0x4c0 : 0x4c4))
-#define AR_PHY_AIC_STAT_1_B1 (AR_SM1_BASE + (AR_SREV_9462_10(ah) ? \
- 0x4c4 : 0x4c8))
-#define AR_PHY_AIC_CTRL_4_B1 (AR_SM1_BASE + 0x4c0)
-#define AR_PHY_AIC_STAT_2_B1 (AR_SM1_BASE + 0x4cc)
-
-#define AR_PHY_AIC_SRAM_ADDR_B1 (AR_SM1_BASE + 0x5f0)
-#define AR_PHY_AIC_SRAM_DATA_B1 (AR_SM1_BASE + 0x5f4)
-
#define AR_PHY_RTT_TABLE_SW_INTF_B(i) (0x384 + ((i) ? \
AR_SM1_BASE : AR_SM_BASE))
#define AR_PHY_RTT_TABLE_SW_INTF_1_B(i) (0x388 + ((i) ? \
diff --git a/drivers/net/wireless/ath/ath9k/reg_aic.h b/drivers/net/wireless/ath/ath9k/reg_aic.h
new file mode 100644
index 0000000..955147a
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/reg_aic.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros 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.
+ */
+
+#ifndef REG_AIC_H
+#define REG_AIC_H
+
+#define AR_SM_BASE 0xa200
+#define AR_SM1_BASE 0xb200
+#define AR_AGC_BASE 0x9e00
+
+#define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0)
+#define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4)
+#define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8)
+#define AR_PHY_AIC_CTRL_3_B0 (AR_SM_BASE + 0x4bc)
+#define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0)
+
+#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + 0x4c4)
+#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + 0x4c8)
+#define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc)
+
+#define AR_PHY_AIC_CTRL_0_B1 (AR_SM1_BASE + 0x4b0)
+#define AR_PHY_AIC_CTRL_1_B1 (AR_SM1_BASE + 0x4b4)
+#define AR_PHY_AIC_CTRL_4_B1 (AR_SM1_BASE + 0x4c0)
+
+#define AR_PHY_AIC_STAT_0_B1 (AR_SM1_BASE + 0x4c4)
+#define AR_PHY_AIC_STAT_1_B1 (AR_SM1_BASE + 0x4c8)
+#define AR_PHY_AIC_STAT_2_B1 (AR_SM1_BASE + 0x4cc)
+
+#define AR_PHY_AIC_SRAM_ADDR_B0 (AR_SM_BASE + 0x5f0)
+#define AR_PHY_AIC_SRAM_DATA_B0 (AR_SM_BASE + 0x5f4)
+
+#define AR_PHY_AIC_SRAM_ADDR_B1 (AR_SM1_BASE + 0x5f0)
+#define AR_PHY_AIC_SRAM_DATA_B1 (AR_SM1_BASE + 0x5f4)
+
+#define AR_PHY_BT_COEX_4 (AR_AGC_BASE + 0x60)
+#define AR_PHY_BT_COEX_5 (AR_AGC_BASE + 0x64)
+
+/* AIC fields */
+#define AR_PHY_AIC_MON_ENABLE 0x80000000
+#define AR_PHY_AIC_MON_ENABLE_S 31
+#define AR_PHY_AIC_CAL_MAX_HOP_COUNT 0x7F000000
+#define AR_PHY_AIC_CAL_MAX_HOP_COUNT_S 24
+#define AR_PHY_AIC_CAL_MIN_VALID_COUNT 0x00FE0000
+#define AR_PHY_AIC_CAL_MIN_VALID_COUNT_S 17
+#define AR_PHY_AIC_F_WLAN 0x0001FC00
+#define AR_PHY_AIC_F_WLAN_S 10
+#define AR_PHY_AIC_CAL_CH_VALID_RESET 0x00000200
+#define AR_PHY_AIC_CAL_CH_VALID_RESET_S 9
+#define AR_PHY_AIC_CAL_ENABLE 0x00000100
+#define AR_PHY_AIC_CAL_ENABLE_S 8
+#define AR_PHY_AIC_BTTX_PWR_THR 0x000000FE
+#define AR_PHY_AIC_BTTX_PWR_THR_S 1
+#define AR_PHY_AIC_ENABLE 0x00000001
+#define AR_PHY_AIC_ENABLE_S 0
+#define AR_PHY_AIC_CAL_BT_REF_DELAY 0x00F00000
+#define AR_PHY_AIC_CAL_BT_REF_DELAY_S 20
+#define AR_PHY_AIC_BT_IDLE_CFG 0x00080000
+#define AR_PHY_AIC_BT_IDLE_CFG_S 19
+#define AR_PHY_AIC_STDBY_COND 0x00060000
+#define AR_PHY_AIC_STDBY_COND_S 17
+#define AR_PHY_AIC_STDBY_ROT_ATT_DB 0x0001F800
+#define AR_PHY_AIC_STDBY_ROT_ATT_DB_S 11
+#define AR_PHY_AIC_STDBY_COM_ATT_DB 0x00000700
+#define AR_PHY_AIC_STDBY_COM_ATT_DB_S 8
+#define AR_PHY_AIC_RSSI_MAX 0x000000F0
+#define AR_PHY_AIC_RSSI_MAX_S 4
+#define AR_PHY_AIC_RSSI_MIN 0x0000000F
+#define AR_PHY_AIC_RSSI_MIN_S 0
+#define AR_PHY_AIC_RADIO_DELAY 0x7F000000
+#define AR_PHY_AIC_RADIO_DELAY_S 24
+#define AR_PHY_AIC_CAL_STEP_SIZE_CORR 0x00F00000
+#define AR_PHY_AIC_CAL_STEP_SIZE_CORR_S 20
+#define AR_PHY_AIC_CAL_ROT_IDX_CORR 0x000F8000
+#define AR_PHY_AIC_CAL_ROT_IDX_CORR_S 15
+#define AR_PHY_AIC_CAL_CONV_CHECK_FACTOR 0x00006000
+#define AR_PHY_AIC_CAL_CONV_CHECK_FACTOR_S 13
+#define AR_PHY_AIC_ROT_IDX_COUNT_MAX 0x00001C00
+#define AR_PHY_AIC_ROT_IDX_COUNT_MAX_S 10
+#define AR_PHY_AIC_CAL_SYNTH_TOGGLE 0x00000200
+#define AR_PHY_AIC_CAL_SYNTH_TOGGLE_S 9
+#define AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX 0x00000100
+#define AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX_S 8
+#define AR_PHY_AIC_CAL_SYNTH_SETTLING 0x000000FF
+#define AR_PHY_AIC_CAL_SYNTH_SETTLING_S 0
+#define AR_PHY_AIC_MON_MAX_HOP_COUNT 0x07F00000
+#define AR_PHY_AIC_MON_MAX_HOP_COUNT_S 20
+#define AR_PHY_AIC_MON_MIN_STALE_COUNT 0x000FE000
+#define AR_PHY_AIC_MON_MIN_STALE_COUNT_S 13
+#define AR_PHY_AIC_MON_PWR_EST_LONG 0x00001000
+#define AR_PHY_AIC_MON_PWR_EST_LONG_S 12
+#define AR_PHY_AIC_MON_PD_TALLY_SCALING 0x00000C00
+#define AR_PHY_AIC_MON_PD_TALLY_SCALING_S 10
+#define AR_PHY_AIC_MON_PERF_THR 0x000003E0
+#define AR_PHY_AIC_MON_PERF_THR_S 5
+#define AR_PHY_AIC_CAL_TARGET_MAG_SETTING 0x00000018
+#define AR_PHY_AIC_CAL_TARGET_MAG_SETTING_S 3
+#define AR_PHY_AIC_CAL_PERF_CHECK_FACTOR 0x00000006
+#define AR_PHY_AIC_CAL_PERF_CHECK_FACTOR_S 1
+#define AR_PHY_AIC_CAL_PWR_EST_LONG 0x00000001
+#define AR_PHY_AIC_CAL_PWR_EST_LONG_S 0
+#define AR_PHY_AIC_MON_DONE 0x80000000
+#define AR_PHY_AIC_MON_DONE_S 31
+#define AR_PHY_AIC_MON_ACTIVE 0x40000000
+#define AR_PHY_AIC_MON_ACTIVE_S 30
+#define AR_PHY_AIC_MEAS_COUNT 0x3F000000
+#define AR_PHY_AIC_MEAS_COUNT_S 24
+#define AR_PHY_AIC_CAL_ANT_ISO_EST 0x00FC0000
+#define AR_PHY_AIC_CAL_ANT_ISO_EST_S 18
+#define AR_PHY_AIC_CAL_HOP_COUNT 0x0003F800
+#define AR_PHY_AIC_CAL_HOP_COUNT_S 11
+#define AR_PHY_AIC_CAL_VALID_COUNT 0x000007F0
+#define AR_PHY_AIC_CAL_VALID_COUNT_S 4
+#define AR_PHY_AIC_CAL_BT_TOO_WEAK_ERR 0x00000008
+#define AR_PHY_AIC_CAL_BT_TOO_WEAK_ERR_S 3
+#define AR_PHY_AIC_CAL_BT_TOO_STRONG_ERR 0x00000004
+#define AR_PHY_AIC_CAL_BT_TOO_STRONG_ERR_S 2
+#define AR_PHY_AIC_CAL_DONE 0x00000002
+#define AR_PHY_AIC_CAL_DONE_S 1
+#define AR_PHY_AIC_CAL_ACTIVE 0x00000001
+#define AR_PHY_AIC_CAL_ACTIVE_S 0
+
+#define AR_PHY_AIC_MEAS_MAG_MIN 0xFFC00000
+#define AR_PHY_AIC_MEAS_MAG_MIN_S 22
+#define AR_PHY_AIC_MON_STALE_COUNT 0x003F8000
+#define AR_PHY_AIC_MON_STALE_COUNT_S 15
+#define AR_PHY_AIC_MON_HOP_COUNT 0x00007F00
+#define AR_PHY_AIC_MON_HOP_COUNT_S 8
+#define AR_PHY_AIC_CAL_AIC_SM 0x000000F8
+#define AR_PHY_AIC_CAL_AIC_SM_S 3
+#define AR_PHY_AIC_SM 0x00000007
+#define AR_PHY_AIC_SM_S 0
+#define AR_PHY_AIC_SRAM_VALID 0x00000001
+#define AR_PHY_AIC_SRAM_VALID_S 0
+#define AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB 0x0000007E
+#define AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB_S 1
+#define AR_PHY_AIC_SRAM_VGA_QUAD_SIGN 0x00000080
+#define AR_PHY_AIC_SRAM_VGA_QUAD_SIGN_S 7
+#define AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB 0x00003F00
+#define AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB_S 8
+#define AR_PHY_AIC_SRAM_VGA_DIR_SIGN 0x00004000
+#define AR_PHY_AIC_SRAM_VGA_DIR_SIGN_S 14
+#define AR_PHY_AIC_SRAM_COM_ATT_6DB 0x00038000
+#define AR_PHY_AIC_SRAM_COM_ATT_6DB_S 15
+#define AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO 0x0000E000
+#define AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO_S 13
+#define AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO 0x00001E00
+#define AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO_S 9
+#define AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING 0x000001F8
+#define AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING_S 3
+#define AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF 0x00000006
+#define AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF_S 1
+#define AR_PHY_AIC_CAL_COM_ATT_DB_FIXED 0x00000001
+#define AR_PHY_AIC_CAL_COM_ATT_DB_FIXED_S 0
+
+#endif /* REG_AIC_H */
--
2.3.1


2015-03-10 08:32:02

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 7/7] ath9k: Disable AIC by default

From: Sujith Manoharan <[email protected]>

Since various MCI messages need to be
handled, along with driver-level support
in upper layers, disable AIC for now.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_aic.c | 6 ++++++
drivers/net/wireless/ath/ath9k/ar9003_mci.c | 3 ++-
2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
index 51ecc9b..7bdbc7a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
@@ -40,6 +40,12 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
{
struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;

+ /*
+ * Disable AIC for now, until we have all the
+ * HW code and the driver-layer support ready.
+ */
+ return false;
+
if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_AIC)
return false;

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index 20bb5b9..6fa98e5 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -1364,7 +1364,8 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
mci->need_flush_btinfo = false;
break;
case MCI_STATE_AIC_CAL_SINGLE:
- value = ar9003_aic_calibration_single(ah);
+ if (ath9k_hw_is_aic_enabled(ah))
+ value = ar9003_aic_calibration_single(ah);
break;
default:
break;
--
2.3.1


2015-03-10 08:32:00

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 6/7] ath9k: Process the AIC calibration results

From: Sujith Manoharan <[email protected]>

This patch adds support for post-processing
the AIC calibration results.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_aic.c | 245 ++++++++++++++++++++++++++++
1 file changed, 245 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
index 00aaf4d..51ecc9b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
@@ -20,6 +20,22 @@
#include "ar9003_aic.h"
#include "reg_aic.h"

+static const u8 com_att_db_table[ATH_AIC_MAX_COM_ATT_DB_TABLE] = {
+ 0, 3, 9, 15, 21, 27
+};
+
+static const u16 aic_lin_table[ATH_AIC_MAX_AIC_LIN_TABLE] = {
+ 8191, 7300, 6506, 5799, 5168, 4606, 4105, 3659,
+ 3261, 2906, 2590, 2309, 2057, 1834, 1634, 1457,
+ 1298, 1157, 1031, 919, 819, 730, 651, 580,
+ 517, 461, 411, 366, 326, 291, 259, 231,
+ 206, 183, 163, 146, 130, 116, 103, 92,
+ 82, 73, 65, 58, 52, 46, 41, 37,
+ 33, 29, 26, 23, 21, 18, 16, 15,
+ 13, 12, 10, 9, 8, 7, 7, 6,
+ 5, 5, 4, 4, 3
+};
+
static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
{
struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
@@ -30,6 +46,56 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
return true;
}

+static int16_t ar9003_aic_find_valid(struct ath_aic_sram_info *cal_sram,
+ bool dir, u8 index)
+{
+ int16_t i;
+
+ if (dir) {
+ for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
+ if (cal_sram[i].valid)
+ break;
+ }
+ } else {
+ for (i = index - 1; i >= 0; i--) {
+ if (cal_sram[i].valid)
+ break;
+ }
+ }
+
+ if ((i >= ATH_AIC_MAX_BT_CHANNEL) || (i < 0))
+ i = -1;
+
+ return i;
+}
+
+/*
+ * type 0: aic_lin_table, 1: com_att_db_table
+ */
+static int16_t ar9003_aic_find_index(u8 type, int16_t value)
+{
+ int16_t i = -1;
+
+ if (type == 0) {
+ for (i = ATH_AIC_MAX_AIC_LIN_TABLE - 1; i >= 0; i--) {
+ if (aic_lin_table[i] >= value)
+ break;
+ }
+ } else if (type == 1) {
+ for (i = 0; i < ATH_AIC_MAX_COM_ATT_DB_TABLE; i++) {
+ if (com_att_db_table[i] > value) {
+ i--;
+ break;
+ }
+ }
+
+ if (i >= ATH_AIC_MAX_COM_ATT_DB_TABLE)
+ i = -1;
+ }
+
+ return i;
+}
+
static void ar9003_aic_gain_table(struct ath_hw *ah)
{
u32 aic_atten_word[19], i;
@@ -186,12 +252,191 @@ static void ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count)
aic->aic_cal_state = AIC_CAL_STATE_STARTED;
}

+static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
+{
+ struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
+ struct ath_aic_sram_info cal_sram[ATH_AIC_MAX_BT_CHANNEL];
+ struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL];
+ u32 dir_path_gain_idx, quad_path_gain_idx, value;
+ u32 fixed_com_att_db;
+ int8_t dir_path_sign, quad_path_sign;
+ int16_t i;
+ bool ret = true;
+
+ memset(&cal_sram, 0, sizeof(cal_sram));
+ memset(&aic_sram, 0, sizeof(aic_sram));
+
+ for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
+ value = aic->aic_sram[i];
+
+ cal_sram[i].valid =
+ MS(value, AR_PHY_AIC_SRAM_VALID);
+ cal_sram[i].rot_quad_att_db =
+ MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB);
+ cal_sram[i].vga_quad_sign =
+ MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN);
+ cal_sram[i].rot_dir_att_db =
+ MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB);
+ cal_sram[i].vga_dir_sign =
+ MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN);
+ cal_sram[i].com_att_6db =
+ MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB);
+
+ if (cal_sram[i].valid) {
+ dir_path_gain_idx = cal_sram[i].rot_dir_att_db +
+ com_att_db_table[cal_sram[i].com_att_6db];
+ quad_path_gain_idx = cal_sram[i].rot_quad_att_db +
+ com_att_db_table[cal_sram[i].com_att_6db];
+
+ dir_path_sign = (cal_sram[i].vga_dir_sign) ? 1 : -1;
+ quad_path_sign = (cal_sram[i].vga_quad_sign) ? 1 : -1;
+
+ aic_sram[i].dir_path_gain_lin = dir_path_sign *
+ aic_lin_table[dir_path_gain_idx];
+ aic_sram[i].quad_path_gain_lin = quad_path_sign *
+ aic_lin_table[quad_path_gain_idx];
+ }
+ }
+
+ for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
+ int16_t start_idx, end_idx;
+
+ if (cal_sram[i].valid)
+ continue;
+
+ start_idx = ar9003_aic_find_valid(cal_sram, 0, i);
+ end_idx = ar9003_aic_find_valid(cal_sram, 1, i);
+
+ if (start_idx < 0) {
+ /* extrapolation */
+ start_idx = end_idx;
+ end_idx = ar9003_aic_find_valid(cal_sram, 1, start_idx);
+
+ if (end_idx < 0) {
+ ret = false;
+ break;
+ }
+
+ aic_sram[i].dir_path_gain_lin =
+ ((aic_sram[start_idx].dir_path_gain_lin -
+ aic_sram[end_idx].dir_path_gain_lin) *
+ (start_idx - i) + ((end_idx - i) >> 1)) /
+ (end_idx - i) +
+ aic_sram[start_idx].dir_path_gain_lin;
+ aic_sram[i].quad_path_gain_lin =
+ ((aic_sram[start_idx].quad_path_gain_lin -
+ aic_sram[end_idx].quad_path_gain_lin) *
+ (start_idx - i) + ((end_idx - i) >> 1)) /
+ (end_idx - i) +
+ aic_sram[start_idx].quad_path_gain_lin;
+ }
+
+ if (end_idx < 0) {
+ /* extrapolation */
+ end_idx = ar9003_aic_find_valid(cal_sram, 0, start_idx);
+
+ if (end_idx < 0) {
+ ret = false;
+ break;
+ }
+
+ aic_sram[i].dir_path_gain_lin =
+ ((aic_sram[start_idx].dir_path_gain_lin -
+ aic_sram[end_idx].dir_path_gain_lin) *
+ (i - start_idx) + ((start_idx - end_idx) >> 1)) /
+ (start_idx - end_idx) +
+ aic_sram[start_idx].dir_path_gain_lin;
+ aic_sram[i].quad_path_gain_lin =
+ ((aic_sram[start_idx].quad_path_gain_lin -
+ aic_sram[end_idx].quad_path_gain_lin) *
+ (i - start_idx) + ((start_idx - end_idx) >> 1)) /
+ (start_idx - end_idx) +
+ aic_sram[start_idx].quad_path_gain_lin;
+
+ } else if (start_idx >= 0){
+ /* interpolation */
+ aic_sram[i].dir_path_gain_lin =
+ (((end_idx - i) * aic_sram[start_idx].dir_path_gain_lin) +
+ ((i - start_idx) * aic_sram[end_idx].dir_path_gain_lin) +
+ ((end_idx - start_idx) >> 1)) /
+ (end_idx - start_idx);
+ aic_sram[i].quad_path_gain_lin =
+ (((end_idx - i) * aic_sram[start_idx].quad_path_gain_lin) +
+ ((i - start_idx) * aic_sram[end_idx].quad_path_gain_lin) +
+ ((end_idx - start_idx) >> 1))/
+ (end_idx - start_idx);
+ }
+ }
+
+ /* From dir/quad_path_gain_lin to sram. */
+ i = ar9003_aic_find_valid(cal_sram, 1, 0);
+ if (i < 0) {
+ i = 0;
+ ret = false;
+ }
+ fixed_com_att_db = com_att_db_table[cal_sram[i].com_att_6db];
+
+ for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
+ int16_t rot_dir_path_att_db, rot_quad_path_att_db;
+
+ aic_sram[i].sram.vga_dir_sign =
+ (aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0;
+ aic_sram[i].sram.vga_quad_sign=
+ (aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0;
+
+ rot_dir_path_att_db =
+ ar9003_aic_find_index(0, abs(aic_sram[i].dir_path_gain_lin)) -
+ fixed_com_att_db;
+ rot_quad_path_att_db =
+ ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) -
+ fixed_com_att_db;
+
+ aic_sram[i].sram.com_att_6db =
+ ar9003_aic_find_index(1, fixed_com_att_db);
+
+ aic_sram[i].sram.valid = 1;
+
+ aic_sram[i].sram.rot_dir_att_db =
+ min(max(rot_dir_path_att_db,
+ (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB),
+ ATH_AIC_MAX_ROT_DIR_ATT_DB);
+ aic_sram[i].sram.rot_quad_att_db =
+ min(max(rot_quad_path_att_db,
+ (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB),
+ ATH_AIC_MAX_ROT_QUAD_ATT_DB);
+ }
+
+ for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
+ aic->aic_sram[i] = (SM(aic_sram[i].sram.vga_dir_sign,
+ AR_PHY_AIC_SRAM_VGA_DIR_SIGN) |
+ SM(aic_sram[i].sram.vga_quad_sign,
+ AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) |
+ SM(aic_sram[i].sram.com_att_6db,
+ AR_PHY_AIC_SRAM_COM_ATT_6DB) |
+ SM(aic_sram[i].sram.valid,
+ AR_PHY_AIC_SRAM_VALID) |
+ SM(aic_sram[i].sram.rot_dir_att_db,
+ AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) |
+ SM(aic_sram[i].sram.rot_quad_att_db,
+ AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB));
+ }
+
+ return ret;
+}
+
static void ar9003_aic_cal_done(struct ath_hw *ah)
{
+ struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
+
/* Disable AIC reference signal in BT modem. */
REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL,
(REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) &
~ATH_AIC_BT_AIC_ENABLE));
+
+ if (ar9003_aic_cal_post_process(ah))
+ aic->aic_cal_state = AIC_CAL_STATE_DONE;
+ else
+ aic->aic_cal_state = AIC_CAL_STATE_ERROR;
}

static u8 ar9003_aic_cal_continue(struct ath_hw *ah, bool cal_once)
--
2.3.1


2015-03-10 08:31:52

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 1/7] ath9k: Add initial structures for AIC

From: Sujith Manoharan <[email protected]>

These are necessary for implementing AIC,
supported by chips like WB222.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_aic.h | 49 +++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/btcoex.h | 11 +++++++
2 files changed, 60 insertions(+)
create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_aic.h

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h
new file mode 100644
index 0000000..d1adb49
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros 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.
+ */
+
+#ifndef AR9003_AIC_H
+#define AR9003_AIC_H
+
+#define ATH_AIC_MAX_COM_ATT_DB_TABLE 6
+#define ATH_AIC_MAX_AIC_LIN_TABLE 69
+#define ATH_AIC_MIN_ROT_DIR_ATT_DB 0
+#define ATH_AIC_MIN_ROT_QUAD_ATT_DB 0
+#define ATH_AIC_MAX_ROT_DIR_ATT_DB 37
+#define ATH_AIC_MAX_ROT_QUAD_ATT_DB 37
+#define ATH_AIC_SRAM_AUTO_INCREMENT 0x80000000
+#define ATH_AIC_SRAM_GAIN_TABLE_OFFSET 0x280
+#define ATH_AIC_SRAM_CAL_OFFSET 0x140
+#define ATH_AIC_SRAM_OFFSET 0x00
+#define ATH_AIC_MEAS_MAG_THRESH 20
+#define ATH_AIC_BT_JUPITER_CTRL 0x66820
+#define ATH_AIC_BT_AIC_ENABLE 0x02
+
+struct ath_aic_sram_info {
+ bool valid;
+ u8 rot_quad_att_db;
+ bool vga_quad_sign;
+ u8 rot_dir_att_db;
+ bool vga_dir_sign;
+ u8 com_att_6db;
+};
+
+struct ath_aic_out_info {
+ int16_t dir_path_gain_lin;
+ int16_t quad_path_gain_lin;
+ struct ath_aic_sram_info sram;
+};
+
+#endif /* AR9003_AIC_H */
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 5fe62ff..b3ed738 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -44,6 +44,9 @@

#define AR9300_NUM_BT_WEIGHTS 4
#define AR9300_NUM_WLAN_WEIGHTS 4
+
+#define ATH_AIC_MAX_BT_CHANNEL 79
+
/* Defines the BT AR_BT_COEX_WGHT used */
enum ath_stomp_type {
ATH_BTCOEX_STOMP_ALL,
@@ -93,6 +96,14 @@ struct ath9k_hw_mci {
u32 last_recovery;
};

+struct ath9k_hw_aic {
+ bool aic_enabled;
+ u8 aic_cal_state;
+ u8 aic_caled_chan;
+ u32 aic_sram[ATH_AIC_MAX_BT_CHANNEL];
+ u32 aic_cal_start_time;
+};
+
struct ath_btcoex_hw {
enum ath_btcoex_scheme scheme;
struct ath9k_hw_mci mci;
--
2.3.1


2015-03-10 08:31:58

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 5/7] ath9k: Finish AIC calibration

From: Sujith Manoharan <[email protected]>

Set the appropriate bits in the HW after
AIC calibration is done.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_aic.c | 78 ++++++++++++++++++++++++++++-
1 file changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
index c2cfac3..00aaf4d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
@@ -186,15 +186,91 @@ static void ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count)
aic->aic_cal_state = AIC_CAL_STATE_STARTED;
}

+static void ar9003_aic_cal_done(struct ath_hw *ah)
+{
+ /* Disable AIC reference signal in BT modem. */
+ REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL,
+ (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) &
+ ~ATH_AIC_BT_AIC_ENABLE));
+}
+
+static u8 ar9003_aic_cal_continue(struct ath_hw *ah, bool cal_once)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+ struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
+ int i, num_chan;
+
+ num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN);
+
+ if (!num_chan) {
+ aic->aic_cal_state = AIC_CAL_STATE_ERROR;
+ return aic->aic_cal_state;
+ }
+
+ if (cal_once) {
+ for (i = 0; i < 10000; i++) {
+ if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) &
+ AR_PHY_AIC_CAL_ENABLE) == 0)
+ break;
+
+ udelay(100);
+ }
+ }
+
+ /*
+ * Use AR_PHY_AIC_CAL_ENABLE bit instead of AR_PHY_AIC_CAL_DONE.
+ * Sometimes CAL_DONE bit is not asserted.
+ */
+ if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) &
+ AR_PHY_AIC_CAL_ENABLE) != 0) {
+ ath_dbg(common, MCI, "AIC cal is not done after 40ms");
+ goto exit;
+ }
+
+ REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1,
+ (ATH_AIC_SRAM_CAL_OFFSET | ATH_AIC_SRAM_AUTO_INCREMENT));
+
+ for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
+ u32 value;
+
+ value = REG_READ(ah, AR_PHY_AIC_SRAM_DATA_B1);
+
+ if (value & 0x01) {
+ if (aic->aic_sram[i] == 0)
+ aic->aic_caled_chan++;
+
+ aic->aic_sram[i] = value;
+
+ if (!cal_once)
+ break;
+ }
+ }
+
+ if ((aic->aic_caled_chan >= num_chan) || cal_once) {
+ ar9003_aic_cal_done(ah);
+ } else {
+ /* Start calibration */
+ REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE);
+ REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1,
+ AR_PHY_AIC_CAL_CH_VALID_RESET);
+ REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE);
+ }
+exit:
+ return aic->aic_cal_state;
+
+}
+
u8 ar9003_aic_calibration_single(struct ath_hw *ah)
{
struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
- u8 cal_ret = 0;
+ u8 cal_ret;
int num_chan;

num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN);

ar9003_aic_cal_start(ah, num_chan);
+ cal_ret = ar9003_aic_cal_continue(ah, true);

return cal_ret;
}
--
2.3.1


2015-03-10 08:31:57

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 4/7] ath9k: Handle MCI_STATE_AIC_CAL_SINGLE

From: Sujith Manoharan <[email protected]>

This patch adds routines to handle the MCI
message AIC_CAL_SINGLE, starting the required
HW calibration.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_aic.c | 169 ++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/ar9003_aic.h | 9 ++
drivers/net/wireless/ath/ath9k/ar9003_mci.c | 4 +
drivers/net/wireless/ath/ath9k/btcoex.h | 1 +
4 files changed, 183 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
index cc1e97b..c2cfac3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
@@ -30,6 +30,175 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
return true;
}

+static void ar9003_aic_gain_table(struct ath_hw *ah)
+{
+ u32 aic_atten_word[19], i;
+
+ /* Config LNA gain difference */
+ REG_WRITE(ah, AR_PHY_BT_COEX_4, 0x2c200a00);
+ REG_WRITE(ah, AR_PHY_BT_COEX_5, 0x5c4e4438);
+
+ /* Program gain table */
+ aic_atten_word[0] = (0x1 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x0 & 0xf) << 5 |
+ (0x1f & 0x1f); /* -01 dB: 4'd1, 5'd31, 00 dB: 4'd0, 5'd31 */
+ aic_atten_word[1] = (0x3 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x2 & 0xf) << 5 |
+ (0x1f & 0x1f); /* -03 dB: 4'd3, 5'd31, -02 dB: 4'd2, 5'd31 */
+ aic_atten_word[2] = (0x5 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x4 & 0xf) << 5 |
+ (0x1f & 0x1f); /* -05 dB: 4'd5, 5'd31, -04 dB: 4'd4, 5'd31 */
+ aic_atten_word[3] = (0x1 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x0 & 0xf) << 5 |
+ (0x1e & 0x1f); /* -07 dB: 4'd1, 5'd30, -06 dB: 4'd0, 5'd30 */
+ aic_atten_word[4] = (0x3 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x2 & 0xf) << 5 |
+ (0x1e & 0x1f); /* -09 dB: 4'd3, 5'd30, -08 dB: 4'd2, 5'd30 */
+ aic_atten_word[5] = (0x5 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x4 & 0xf) << 5 |
+ (0x1e & 0x1f); /* -11 dB: 4'd5, 5'd30, -10 dB: 4'd4, 5'd30 */
+ aic_atten_word[6] = (0x1 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x0 & 0xf) << 5 |
+ (0xf & 0x1f); /* -13 dB: 4'd1, 5'd15, -12 dB: 4'd0, 5'd15 */
+ aic_atten_word[7] = (0x3 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x2 & 0xf) << 5 |
+ (0xf & 0x1f); /* -15 dB: 4'd3, 5'd15, -14 dB: 4'd2, 5'd15 */
+ aic_atten_word[8] = (0x5 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x4 & 0xf) << 5 |
+ (0xf & 0x1f); /* -17 dB: 4'd5, 5'd15, -16 dB: 4'd4, 5'd15 */
+ aic_atten_word[9] = (0x1 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x0 & 0xf) << 5 |
+ (0x7 & 0x1f); /* -19 dB: 4'd1, 5'd07, -18 dB: 4'd0, 5'd07 */
+ aic_atten_word[10] = (0x3 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x2 & 0xf) << 5 |
+ (0x7 & 0x1f); /* -21 dB: 4'd3, 5'd07, -20 dB: 4'd2, 5'd07 */
+ aic_atten_word[11] = (0x5 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x4 & 0xf) << 5 |
+ (0x7 & 0x1f); /* -23 dB: 4'd5, 5'd07, -22 dB: 4'd4, 5'd07 */
+ aic_atten_word[12] = (0x7 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x6 & 0xf) << 5 |
+ (0x7 & 0x1f); /* -25 dB: 4'd7, 5'd07, -24 dB: 4'd6, 5'd07 */
+ aic_atten_word[13] = (0x3 & 0xf) << 14 | (0x3 & 0x1f) << 9 | (0x2 & 0xf) << 5 |
+ (0x3 & 0x1f); /* -27 dB: 4'd3, 5'd03, -26 dB: 4'd2, 5'd03 */
+ aic_atten_word[14] = (0x5 & 0xf) << 14 | (0x3 & 0x1f) << 9 | (0x4 & 0xf) << 5 |
+ (0x3 & 0x1f); /* -29 dB: 4'd5, 5'd03, -28 dB: 4'd4, 5'd03 */
+ aic_atten_word[15] = (0x1 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x0 & 0xf) << 5 |
+ (0x1 & 0x1f); /* -31 dB: 4'd1, 5'd01, -30 dB: 4'd0, 5'd01 */
+ aic_atten_word[16] = (0x3 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x2 & 0xf) << 5 |
+ (0x1 & 0x1f); /* -33 dB: 4'd3, 5'd01, -32 dB: 4'd2, 5'd01 */
+ aic_atten_word[17] = (0x5 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x4 & 0xf) << 5 |
+ (0x1 & 0x1f); /* -35 dB: 4'd5, 5'd01, -34 dB: 4'd4, 5'd01 */
+ aic_atten_word[18] = (0x7 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x6 & 0xf) << 5 |
+ (0x1 & 0x1f); /* -37 dB: 4'd7, 5'd01, -36 dB: 4'd6, 5'd01 */
+
+ /* Write to Gain table with auto increment enabled. */
+ REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000),
+ (ATH_AIC_SRAM_AUTO_INCREMENT |
+ ATH_AIC_SRAM_GAIN_TABLE_OFFSET));
+
+ for (i = 0; i < 19; i++) {
+ REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000),
+ aic_atten_word[i]);
+ }
+}
+
+static void ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count)
+{
+ struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
+ int i;
+
+ /* Write to Gain table with auto increment enabled. */
+ REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000),
+ (ATH_AIC_SRAM_AUTO_INCREMENT |
+ ATH_AIC_SRAM_CAL_OFFSET));
+
+ for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
+ REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000), 0);
+ aic->aic_sram[i] = 0;
+ }
+
+ REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B0,
+ (SM(0, AR_PHY_AIC_MON_ENABLE) |
+ SM(127, AR_PHY_AIC_CAL_MAX_HOP_COUNT) |
+ SM(min_valid_count, AR_PHY_AIC_CAL_MIN_VALID_COUNT) |
+ SM(37, AR_PHY_AIC_F_WLAN) |
+ SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) |
+ SM(0, AR_PHY_AIC_CAL_ENABLE) |
+ SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) |
+ SM(0, AR_PHY_AIC_ENABLE)));
+
+ REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B1,
+ (SM(0, AR_PHY_AIC_MON_ENABLE) |
+ SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) |
+ SM(0, AR_PHY_AIC_CAL_ENABLE) |
+ SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) |
+ SM(0, AR_PHY_AIC_ENABLE)));
+
+ REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B0,
+ (SM(8, AR_PHY_AIC_CAL_BT_REF_DELAY) |
+ SM(0, AR_PHY_AIC_BT_IDLE_CFG) |
+ SM(1, AR_PHY_AIC_STDBY_COND) |
+ SM(37, AR_PHY_AIC_STDBY_ROT_ATT_DB) |
+ SM(5, AR_PHY_AIC_STDBY_COM_ATT_DB) |
+ SM(15, AR_PHY_AIC_RSSI_MAX) |
+ SM(0, AR_PHY_AIC_RSSI_MIN)));
+
+ REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B1,
+ (SM(15, AR_PHY_AIC_RSSI_MAX) |
+ SM(0, AR_PHY_AIC_RSSI_MIN)));
+
+ REG_WRITE(ah, AR_PHY_AIC_CTRL_2_B0,
+ (SM(44, AR_PHY_AIC_RADIO_DELAY) |
+ SM(8, AR_PHY_AIC_CAL_STEP_SIZE_CORR) |
+ SM(12, AR_PHY_AIC_CAL_ROT_IDX_CORR) |
+ SM(2, AR_PHY_AIC_CAL_CONV_CHECK_FACTOR) |
+ SM(5, AR_PHY_AIC_ROT_IDX_COUNT_MAX) |
+ SM(0, AR_PHY_AIC_CAL_SYNTH_TOGGLE) |
+ SM(0, AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX) |
+ SM(200, AR_PHY_AIC_CAL_SYNTH_SETTLING)));
+
+ REG_WRITE(ah, AR_PHY_AIC_CTRL_3_B0,
+ (SM(2, AR_PHY_AIC_MON_MAX_HOP_COUNT) |
+ SM(1, AR_PHY_AIC_MON_MIN_STALE_COUNT) |
+ SM(1, AR_PHY_AIC_MON_PWR_EST_LONG) |
+ SM(2, AR_PHY_AIC_MON_PD_TALLY_SCALING) |
+ SM(10, AR_PHY_AIC_MON_PERF_THR) |
+ SM(2, AR_PHY_AIC_CAL_TARGET_MAG_SETTING) |
+ SM(1, AR_PHY_AIC_CAL_PERF_CHECK_FACTOR) |
+ SM(1, AR_PHY_AIC_CAL_PWR_EST_LONG)));
+
+ REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B0,
+ (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) |
+ SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) |
+ SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) |
+ SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) |
+ SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED)));
+
+ REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B1,
+ (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) |
+ SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) |
+ SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) |
+ SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) |
+ SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED)));
+
+ ar9003_aic_gain_table(ah);
+
+ /* Need to enable AIC reference signal in BT modem. */
+ REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL,
+ (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) |
+ ATH_AIC_BT_AIC_ENABLE));
+
+ aic->aic_cal_start_time = REG_READ(ah, AR_TSF_L32);
+
+ /* Start calibration */
+ REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE);
+ REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_CH_VALID_RESET);
+ REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE);
+
+ aic->aic_caled_chan = 0;
+ aic->aic_cal_state = AIC_CAL_STATE_STARTED;
+}
+
+u8 ar9003_aic_calibration_single(struct ath_hw *ah)
+{
+ struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+ u8 cal_ret = 0;
+ int num_chan;
+
+ num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN);
+
+ ar9003_aic_cal_start(ah, num_chan);
+
+ return cal_ret;
+}
+
void ar9003_hw_attach_aic_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h
index d1adb49..9651bcd 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_aic.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h
@@ -31,6 +31,13 @@
#define ATH_AIC_BT_JUPITER_CTRL 0x66820
#define ATH_AIC_BT_AIC_ENABLE 0x02

+enum aic_cal_state {
+ AIC_CAL_STATE_IDLE = 0,
+ AIC_CAL_STATE_STARTED,
+ AIC_CAL_STATE_DONE,
+ AIC_CAL_STATE_ERROR
+};
+
struct ath_aic_sram_info {
bool valid;
u8 rot_quad_att_db;
@@ -46,4 +53,6 @@ struct ath_aic_out_info {
struct ath_aic_sram_info sram;
};

+u8 ar9003_aic_calibration_single(struct ath_hw *ah);
+
#endif /* AR9003_AIC_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index bd169fa..20bb5b9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -19,6 +19,7 @@
#include "hw-ops.h"
#include "ar9003_phy.h"
#include "ar9003_mci.h"
+#include "ar9003_aic.h"

static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah)
{
@@ -1362,6 +1363,9 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0;
mci->need_flush_btinfo = false;
break;
+ case MCI_STATE_AIC_CAL_SINGLE:
+ value = ar9003_aic_calibration_single(ah);
+ break;
default:
break;
}
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index b3ed738..cd2f0a2 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -107,6 +107,7 @@ struct ath9k_hw_aic {
struct ath_btcoex_hw {
enum ath_btcoex_scheme scheme;
struct ath9k_hw_mci mci;
+ struct ath9k_hw_aic aic;
bool enabled;
u8 wlanactive_gpio;
u8 btactive_gpio;
--
2.3.1


2015-03-10 08:31:54

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 2/7] ath9k: Register private AIC ops

From: Sujith Manoharan <[email protected]>

AIC can be disabled or enabled on a per-card
basis using MCI configuration, so register a function
to check its status.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/Makefile | 3 ++-
drivers/net/wireless/ath/ath9k/ar9003_aic.c | 37 +++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/ar9003_hw.c | 1 +
drivers/net/wireless/ath/ath9k/hw-ops.h | 8 +++++++
drivers/net/wireless/ath/ath9k/hw.h | 6 +++++
5 files changed, 54 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_aic.c

diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 4739722..ecda613 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -46,7 +46,8 @@ ath9k_hw-y:= \
ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o

ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
- ar9003_mci.o
+ ar9003_mci.o \
+ ar9003_aic.o

ath9k_hw-$(CONFIG_ATH9K_PCOEM) += ar9003_rtt.o

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
new file mode 100644
index 0000000..0cd159d
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros 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.
+ */
+
+#include "hw.h"
+#include "hw-ops.h"
+#include "ar9003_mci.h"
+#include "ar9003_aic.h"
+
+static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
+{
+ struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
+
+ if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_AIC)
+ return false;
+
+ return true;
+}
+
+void ar9003_hw_attach_aic_ops(struct ath_hw *ah)
+{
+ struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+
+ priv_ops->is_aic_enabled = ar9003_hw_is_aic_enabled;
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index df176e6..79fd3b2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -1180,4 +1180,5 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
ar9003_hw_attach_phy_ops(ah);
ar9003_hw_attach_calib_ops(ah);
ar9003_hw_attach_mac_ops(ah);
+ ar9003_hw_attach_aic_ops(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 88769b6..232339b 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -108,6 +108,14 @@ static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
ath9k_hw_ops(ah)->set_bt_ant_diversity(ah, enable);
}

+static inline bool ath9k_hw_is_aic_enabled(struct ath_hw *ah)
+{
+ if (ath9k_hw_private_ops(ah)->is_aic_enabled)
+ return ath9k_hw_private_ops(ah)->is_aic_enabled(ah);
+
+ return false;
+}
+
#endif

/* Private hardware call ops */
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 2067cb5..c22edd3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -653,6 +653,10 @@ struct ath_hw_private_ops {

/* ANI */
void (*ani_cache_ini_regs)(struct ath_hw *ah);
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+ bool (*is_aic_enabled)(struct ath_hw *ah);
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
};

/**
@@ -1113,6 +1117,8 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
int ar9002_hw_attach_ops(struct ath_hw *ah);
void ar9003_hw_attach_ops(struct ath_hw *ah);

+void ar9003_hw_attach_aic_ops(struct ath_hw *ah);
+
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);

void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
--
2.3.1


2015-03-10 08:43:40

by Sujith Manoharan

[permalink] [raw]
Subject: Re: [PATCH 0/7] ath9k patches

Hi Kalle,

Sorry, I forgot to mention that this is intended for -next.

Sujith

Sujith Manoharan wrote:
> From: Sujith Manoharan <[email protected]>
>
> This series adds initial support for AIC.
>
> Active Interference Cancellation is a method
> implemented in the HW to counter WLAN RX
> sensitivity degradation when BT is transmitting
> at the same time. This feature is supported by
> cards like WB222 based on AR9462.
>
> Sujith Manoharan (7):
> ath9k: Add initial structures for AIC
> ath9k: Register private AIC ops
> ath9k: Add register definitions for AIC
> ath9k: Handle MCI_STATE_AIC_CAL_SINGLE
> ath9k: Finish AIC calibration
> ath9k: Process the AIC calibration results
> ath9k: Disable AIC by default
>
> drivers/net/wireless/ath/ath9k/Makefile | 3 +-
> drivers/net/wireless/ath/ath9k/ar9003_aic.c | 534 ++++++++++++++++++++++++++++
> drivers/net/wireless/ath/ath9k/ar9003_aic.h | 58 +++
> drivers/net/wireless/ath/ath9k/ar9003_hw.c | 1 +
> drivers/net/wireless/ath/ath9k/ar9003_mci.c | 5 +
> drivers/net/wireless/ath/ath9k/ar9003_phy.h | 25 --
> drivers/net/wireless/ath/ath9k/btcoex.h | 12 +
> drivers/net/wireless/ath/ath9k/hw-ops.h | 8 +
> drivers/net/wireless/ath/ath9k/hw.h | 6 +
> drivers/net/wireless/ath/ath9k/reg_aic.h | 168 +++++++++
> 10 files changed, 794 insertions(+), 26 deletions(-)
> create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_aic.c
> create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_aic.h
> create mode 100644 drivers/net/wireless/ath/ath9k/reg_aic.h
>
> --
> 2.3.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html