Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2015 Qualcomm Atheros Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include "hw.h"
0018 #include "hw-ops.h"
0019 #include "ar9003_mci.h"
0020 #include "ar9003_aic.h"
0021 #include "ar9003_phy.h"
0022 #include "reg_aic.h"
0023 
0024 static const u8 com_att_db_table[ATH_AIC_MAX_COM_ATT_DB_TABLE] = {
0025     0, 3, 9, 15, 21, 27
0026 };
0027 
0028 static const u16 aic_lin_table[ATH_AIC_MAX_AIC_LIN_TABLE] = {
0029     8191, 7300, 6506, 5799, 5168, 4606, 4105, 3659,
0030     3261, 2906, 2590, 2309, 2057, 1834, 1634, 1457,
0031     1298, 1157, 1031, 919,  819,  730,  651,  580,
0032     517,  461,  411,  366,  326,  291,  259,  231,
0033     206,  183,  163,  146,  130,  116,  103,  92,
0034     82,   73,   65,   58,   52,   46,   41,   37,
0035     33,   29,   26,   23,   21,   18,   16,   15,
0036     13,   12,   10,   9,    8,    7,    7,    6,
0037     5,    5,    4,    4,    3
0038 };
0039 
0040 static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
0041 {
0042     struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
0043 
0044     /*
0045      * Disable AIC for now, until we have all the
0046      * HW code and the driver-layer support ready.
0047      */
0048     return false;
0049 
0050     if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_AIC)
0051         return false;
0052 
0053     return true;
0054 }
0055 
0056 static int16_t ar9003_aic_find_valid(bool *cal_sram_valid,
0057                      bool dir, u8 index)
0058 {
0059     int16_t i;
0060 
0061     if (dir) {
0062         for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
0063             if (cal_sram_valid[i])
0064                 break;
0065         }
0066     } else {
0067         for (i = index - 1; i >= 0; i--) {
0068             if (cal_sram_valid[i])
0069                 break;
0070         }
0071     }
0072 
0073     if ((i >= ATH_AIC_MAX_BT_CHANNEL) || (i < 0))
0074         i = -1;
0075 
0076     return i;
0077 }
0078 
0079 /*
0080  * type 0: aic_lin_table, 1: com_att_db_table
0081  */
0082 static int16_t ar9003_aic_find_index(u8 type, int16_t value)
0083 {
0084     int16_t i = -1;
0085 
0086     if (type == 0) {
0087         for (i = ATH_AIC_MAX_AIC_LIN_TABLE - 1; i >= 0; i--) {
0088             if (aic_lin_table[i] >= value)
0089                 break;
0090         }
0091     } else if (type == 1) {
0092         for (i = 0; i < ATH_AIC_MAX_COM_ATT_DB_TABLE; i++) {
0093             if (com_att_db_table[i] > value) {
0094                 i--;
0095                 break;
0096             }
0097         }
0098 
0099         if (i >= ATH_AIC_MAX_COM_ATT_DB_TABLE)
0100             i = -1;
0101     }
0102 
0103     return i;
0104 }
0105 
0106 static void ar9003_aic_gain_table(struct ath_hw *ah)
0107 {
0108     u32 aic_atten_word[19], i;
0109 
0110     /* Config LNA gain difference */
0111     REG_WRITE(ah, AR_PHY_BT_COEX_4, 0x2c200a00);
0112     REG_WRITE(ah, AR_PHY_BT_COEX_5, 0x5c4e4438);
0113 
0114     /* Program gain table */
0115     aic_atten_word[0] = (0x1 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x0 & 0xf) << 5 |
0116         (0x1f & 0x1f); /* -01 dB: 4'd1, 5'd31,  00 dB: 4'd0, 5'd31 */
0117     aic_atten_word[1] = (0x3 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x2 & 0xf) << 5 |
0118         (0x1f & 0x1f); /* -03 dB: 4'd3, 5'd31, -02 dB: 4'd2, 5'd31 */
0119     aic_atten_word[2] = (0x5 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x4 & 0xf) << 5 |
0120         (0x1f & 0x1f); /* -05 dB: 4'd5, 5'd31, -04 dB: 4'd4, 5'd31 */
0121     aic_atten_word[3] = (0x1 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x0 & 0xf) << 5 |
0122         (0x1e & 0x1f); /* -07 dB: 4'd1, 5'd30, -06 dB: 4'd0, 5'd30 */
0123     aic_atten_word[4] = (0x3 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x2 & 0xf) << 5 |
0124         (0x1e & 0x1f); /* -09 dB: 4'd3, 5'd30, -08 dB: 4'd2, 5'd30 */
0125     aic_atten_word[5] = (0x5 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x4 & 0xf) << 5 |
0126         (0x1e & 0x1f); /* -11 dB: 4'd5, 5'd30, -10 dB: 4'd4, 5'd30 */
0127     aic_atten_word[6] = (0x1 & 0xf) << 14 | (0xf & 0x1f) << 9  | (0x0 & 0xf) << 5 |
0128         (0xf & 0x1f);  /* -13 dB: 4'd1, 5'd15, -12 dB: 4'd0, 5'd15 */
0129     aic_atten_word[7] = (0x3 & 0xf) << 14 | (0xf & 0x1f) << 9  | (0x2 & 0xf) << 5 |
0130         (0xf & 0x1f);  /* -15 dB: 4'd3, 5'd15, -14 dB: 4'd2, 5'd15 */
0131     aic_atten_word[8] = (0x5 & 0xf) << 14 | (0xf & 0x1f) << 9  | (0x4 & 0xf) << 5 |
0132         (0xf & 0x1f);  /* -17 dB: 4'd5, 5'd15, -16 dB: 4'd4, 5'd15 */
0133     aic_atten_word[9] = (0x1 & 0xf) << 14 | (0x7 & 0x1f) << 9  | (0x0 & 0xf) << 5 |
0134         (0x7 & 0x1f);  /* -19 dB: 4'd1, 5'd07, -18 dB: 4'd0, 5'd07 */
0135     aic_atten_word[10] = (0x3 & 0xf) << 14 | (0x7 & 0x1f) << 9  | (0x2 & 0xf) << 5 |
0136         (0x7 & 0x1f);  /* -21 dB: 4'd3, 5'd07, -20 dB: 4'd2, 5'd07 */
0137     aic_atten_word[11] = (0x5 & 0xf) << 14 | (0x7 & 0x1f) << 9  | (0x4 & 0xf) << 5 |
0138         (0x7 & 0x1f);  /* -23 dB: 4'd5, 5'd07, -22 dB: 4'd4, 5'd07 */
0139     aic_atten_word[12] = (0x7 & 0xf) << 14 | (0x7 & 0x1f) << 9  | (0x6 & 0xf) << 5 |
0140         (0x7 & 0x1f);  /* -25 dB: 4'd7, 5'd07, -24 dB: 4'd6, 5'd07 */
0141     aic_atten_word[13] = (0x3 & 0xf) << 14 | (0x3 & 0x1f) << 9  | (0x2 & 0xf) << 5 |
0142         (0x3 & 0x1f);  /* -27 dB: 4'd3, 5'd03, -26 dB: 4'd2, 5'd03 */
0143     aic_atten_word[14] = (0x5 & 0xf) << 14 | (0x3 & 0x1f) << 9  | (0x4 & 0xf) << 5 |
0144         (0x3 & 0x1f);  /* -29 dB: 4'd5, 5'd03, -28 dB: 4'd4, 5'd03 */
0145     aic_atten_word[15] = (0x1 & 0xf) << 14 | (0x1 & 0x1f) << 9  | (0x0 & 0xf) << 5 |
0146         (0x1 & 0x1f);  /* -31 dB: 4'd1, 5'd01, -30 dB: 4'd0, 5'd01 */
0147     aic_atten_word[16] = (0x3 & 0xf) << 14 | (0x1 & 0x1f) << 9  | (0x2 & 0xf) << 5 |
0148         (0x1 & 0x1f);  /* -33 dB: 4'd3, 5'd01, -32 dB: 4'd2, 5'd01 */
0149     aic_atten_word[17] = (0x5 & 0xf) << 14 | (0x1 & 0x1f) << 9  | (0x4 & 0xf) << 5 |
0150         (0x1 & 0x1f);  /* -35 dB: 4'd5, 5'd01, -34 dB: 4'd4, 5'd01 */
0151     aic_atten_word[18] = (0x7 & 0xf) << 14 | (0x1 & 0x1f) << 9  | (0x6 & 0xf) << 5 |
0152         (0x1 & 0x1f);  /* -37 dB: 4'd7, 5'd01, -36 dB: 4'd6, 5'd01 */
0153 
0154     /* Write to Gain table with auto increment enabled. */
0155     REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000),
0156           (ATH_AIC_SRAM_AUTO_INCREMENT |
0157            ATH_AIC_SRAM_GAIN_TABLE_OFFSET));
0158 
0159     for (i = 0; i < 19; i++) {
0160         REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000),
0161               aic_atten_word[i]);
0162     }
0163 }
0164 
0165 static u8 ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count)
0166 {
0167     struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
0168     int i;
0169 
0170     /* Write to Gain table with auto increment enabled. */
0171     REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000),
0172           (ATH_AIC_SRAM_AUTO_INCREMENT |
0173            ATH_AIC_SRAM_CAL_OFFSET));
0174 
0175     for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
0176         REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000), 0);
0177         aic->aic_sram[i] = 0;
0178     }
0179 
0180     REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B0,
0181           (SM(0, AR_PHY_AIC_MON_ENABLE) |
0182            SM(127, AR_PHY_AIC_CAL_MAX_HOP_COUNT) |
0183            SM(min_valid_count, AR_PHY_AIC_CAL_MIN_VALID_COUNT) |
0184            SM(37, AR_PHY_AIC_F_WLAN) |
0185            SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) |
0186            SM(0, AR_PHY_AIC_CAL_ENABLE) |
0187            SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) |
0188            SM(0, AR_PHY_AIC_ENABLE)));
0189 
0190     REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B1,
0191           (SM(0, AR_PHY_AIC_MON_ENABLE) |
0192            SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) |
0193            SM(0, AR_PHY_AIC_CAL_ENABLE) |
0194            SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) |
0195            SM(0, AR_PHY_AIC_ENABLE)));
0196 
0197     REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B0,
0198           (SM(8, AR_PHY_AIC_CAL_BT_REF_DELAY) |
0199            SM(0, AR_PHY_AIC_BT_IDLE_CFG) |
0200            SM(1, AR_PHY_AIC_STDBY_COND) |
0201            SM(37, AR_PHY_AIC_STDBY_ROT_ATT_DB) |
0202            SM(5, AR_PHY_AIC_STDBY_COM_ATT_DB) |
0203            SM(15, AR_PHY_AIC_RSSI_MAX) |
0204            SM(0, AR_PHY_AIC_RSSI_MIN)));
0205 
0206     REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B1,
0207           (SM(15, AR_PHY_AIC_RSSI_MAX) |
0208            SM(0, AR_PHY_AIC_RSSI_MIN)));
0209 
0210     REG_WRITE(ah, AR_PHY_AIC_CTRL_2_B0,
0211           (SM(44, AR_PHY_AIC_RADIO_DELAY) |
0212            SM(8, AR_PHY_AIC_CAL_STEP_SIZE_CORR) |
0213            SM(12, AR_PHY_AIC_CAL_ROT_IDX_CORR) |
0214            SM(2, AR_PHY_AIC_CAL_CONV_CHECK_FACTOR) |
0215            SM(5, AR_PHY_AIC_ROT_IDX_COUNT_MAX) |
0216            SM(0, AR_PHY_AIC_CAL_SYNTH_TOGGLE) |
0217            SM(0, AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX) |
0218            SM(200, AR_PHY_AIC_CAL_SYNTH_SETTLING)));
0219 
0220     REG_WRITE(ah, AR_PHY_AIC_CTRL_3_B0,
0221           (SM(2, AR_PHY_AIC_MON_MAX_HOP_COUNT) |
0222            SM(1, AR_PHY_AIC_MON_MIN_STALE_COUNT) |
0223            SM(1, AR_PHY_AIC_MON_PWR_EST_LONG) |
0224            SM(2, AR_PHY_AIC_MON_PD_TALLY_SCALING) |
0225            SM(10, AR_PHY_AIC_MON_PERF_THR) |
0226            SM(2, AR_PHY_AIC_CAL_TARGET_MAG_SETTING) |
0227            SM(1, AR_PHY_AIC_CAL_PERF_CHECK_FACTOR) |
0228            SM(1, AR_PHY_AIC_CAL_PWR_EST_LONG)));
0229 
0230     REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B0,
0231           (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) |
0232            SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) |
0233            SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) |
0234            SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) |
0235            SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED)));
0236 
0237     REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B1,
0238           (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) |
0239            SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) |
0240            SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) |
0241            SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) |
0242            SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED)));
0243 
0244     ar9003_aic_gain_table(ah);
0245 
0246     /* Need to enable AIC reference signal in BT modem. */
0247     REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL,
0248           (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) |
0249            ATH_AIC_BT_AIC_ENABLE));
0250 
0251     aic->aic_cal_start_time = REG_READ(ah, AR_TSF_L32);
0252 
0253     /* Start calibration */
0254     REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE);
0255     REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_CH_VALID_RESET);
0256     REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE);
0257 
0258     aic->aic_caled_chan = 0;
0259     aic->aic_cal_state = AIC_CAL_STATE_STARTED;
0260 
0261     return aic->aic_cal_state;
0262 }
0263 
0264 static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
0265 {
0266     struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
0267     bool cal_sram_valid[ATH_AIC_MAX_BT_CHANNEL];
0268     struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL];
0269     u32 dir_path_gain_idx, quad_path_gain_idx, value;
0270     u32 fixed_com_att_db;
0271     int8_t dir_path_sign, quad_path_sign;
0272     int16_t i;
0273     bool ret = true;
0274 
0275     memset(&cal_sram_valid, 0, sizeof(cal_sram_valid));
0276     memset(&aic_sram, 0, sizeof(aic_sram));
0277 
0278     for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
0279         struct ath_aic_sram_info sram;
0280         value = aic->aic_sram[i];
0281 
0282         cal_sram_valid[i] = sram.valid =
0283             MS(value, AR_PHY_AIC_SRAM_VALID);
0284         sram.rot_quad_att_db =
0285             MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB);
0286         sram.vga_quad_sign =
0287             MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN);
0288         sram.rot_dir_att_db =
0289             MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB);
0290         sram.vga_dir_sign =
0291             MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN);
0292         sram.com_att_6db =
0293             MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB);
0294 
0295         if (sram.valid) {
0296             dir_path_gain_idx = sram.rot_dir_att_db +
0297                 com_att_db_table[sram.com_att_6db];
0298             quad_path_gain_idx = sram.rot_quad_att_db +
0299                 com_att_db_table[sram.com_att_6db];
0300 
0301             dir_path_sign = (sram.vga_dir_sign) ? 1 : -1;
0302             quad_path_sign = (sram.vga_quad_sign) ? 1 : -1;
0303 
0304             aic_sram[i].dir_path_gain_lin = dir_path_sign *
0305                 aic_lin_table[dir_path_gain_idx];
0306             aic_sram[i].quad_path_gain_lin = quad_path_sign *
0307                 aic_lin_table[quad_path_gain_idx];
0308         }
0309     }
0310 
0311     for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
0312         int16_t start_idx, end_idx;
0313 
0314         if (cal_sram_valid[i])
0315             continue;
0316 
0317         start_idx = ar9003_aic_find_valid(cal_sram_valid, 0, i);
0318         end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, i);
0319 
0320         if (start_idx < 0) {
0321             /* extrapolation */
0322             start_idx = end_idx;
0323             end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, start_idx);
0324 
0325             if (end_idx < 0) {
0326                 ret = false;
0327                 break;
0328             }
0329 
0330             aic_sram[i].dir_path_gain_lin =
0331                 ((aic_sram[start_idx].dir_path_gain_lin -
0332                   aic_sram[end_idx].dir_path_gain_lin) *
0333                  (start_idx - i) + ((end_idx - i) >> 1)) /
0334                 (end_idx - i) +
0335                 aic_sram[start_idx].dir_path_gain_lin;
0336             aic_sram[i].quad_path_gain_lin =
0337                 ((aic_sram[start_idx].quad_path_gain_lin -
0338                   aic_sram[end_idx].quad_path_gain_lin) *
0339                  (start_idx - i) + ((end_idx - i) >> 1)) /
0340                 (end_idx - i) +
0341                 aic_sram[start_idx].quad_path_gain_lin;
0342         }
0343 
0344         if (end_idx < 0) {
0345             /* extrapolation */
0346             end_idx = ar9003_aic_find_valid(cal_sram_valid, 0, start_idx);
0347 
0348             if (end_idx < 0) {
0349                 ret = false;
0350                 break;
0351             }
0352 
0353             aic_sram[i].dir_path_gain_lin =
0354                 ((aic_sram[start_idx].dir_path_gain_lin -
0355                   aic_sram[end_idx].dir_path_gain_lin) *
0356                  (i - start_idx) + ((start_idx - end_idx) >> 1)) /
0357                 (start_idx - end_idx) +
0358                 aic_sram[start_idx].dir_path_gain_lin;
0359             aic_sram[i].quad_path_gain_lin =
0360                 ((aic_sram[start_idx].quad_path_gain_lin -
0361                   aic_sram[end_idx].quad_path_gain_lin) *
0362                  (i - start_idx) + ((start_idx - end_idx) >> 1)) /
0363                 (start_idx - end_idx) +
0364                 aic_sram[start_idx].quad_path_gain_lin;
0365 
0366         } else if (start_idx >= 0){
0367             /* interpolation */
0368             aic_sram[i].dir_path_gain_lin =
0369                 (((end_idx - i) * aic_sram[start_idx].dir_path_gain_lin) +
0370                  ((i - start_idx) * aic_sram[end_idx].dir_path_gain_lin) +
0371                  ((end_idx - start_idx) >> 1)) /
0372                 (end_idx - start_idx);
0373             aic_sram[i].quad_path_gain_lin =
0374                 (((end_idx - i) * aic_sram[start_idx].quad_path_gain_lin) +
0375                  ((i - start_idx) * aic_sram[end_idx].quad_path_gain_lin) +
0376                  ((end_idx - start_idx) >> 1))/
0377                 (end_idx - start_idx);
0378         }
0379     }
0380 
0381     /* From dir/quad_path_gain_lin to sram. */
0382     i = ar9003_aic_find_valid(cal_sram_valid, 1, 0);
0383     if (i < 0) {
0384         i = 0;
0385         ret = false;
0386     }
0387     fixed_com_att_db = com_att_db_table[MS(aic->aic_sram[i],
0388                         AR_PHY_AIC_SRAM_COM_ATT_6DB)];
0389 
0390     for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
0391         int16_t rot_dir_path_att_db, rot_quad_path_att_db;
0392         struct ath_aic_sram_info sram;
0393 
0394         sram.vga_dir_sign =
0395             (aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0;
0396         sram.vga_quad_sign =
0397             (aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0;
0398 
0399         rot_dir_path_att_db =
0400             ar9003_aic_find_index(0, abs(aic_sram[i].dir_path_gain_lin)) -
0401             fixed_com_att_db;
0402         rot_quad_path_att_db =
0403             ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) -
0404             fixed_com_att_db;
0405 
0406         sram.com_att_6db =
0407             ar9003_aic_find_index(1, fixed_com_att_db);
0408 
0409         sram.valid = true;
0410 
0411         sram.rot_dir_att_db =
0412             min(max(rot_dir_path_att_db,
0413                 (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB),
0414                 ATH_AIC_MAX_ROT_DIR_ATT_DB);
0415         sram.rot_quad_att_db =
0416             min(max(rot_quad_path_att_db,
0417                 (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB),
0418                 ATH_AIC_MAX_ROT_QUAD_ATT_DB);
0419 
0420         aic->aic_sram[i] = (SM(sram.vga_dir_sign,
0421                        AR_PHY_AIC_SRAM_VGA_DIR_SIGN) |
0422                     SM(sram.vga_quad_sign,
0423                        AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) |
0424                     SM(sram.com_att_6db,
0425                        AR_PHY_AIC_SRAM_COM_ATT_6DB) |
0426                     SM(sram.valid,
0427                        AR_PHY_AIC_SRAM_VALID) |
0428                     SM(sram.rot_dir_att_db,
0429                        AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) |
0430                     SM(sram.rot_quad_att_db,
0431                        AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB));
0432     }
0433 
0434     return ret;
0435 }
0436 
0437 static void ar9003_aic_cal_done(struct ath_hw *ah)
0438 {
0439     struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
0440 
0441     /* Disable AIC reference signal in BT modem. */
0442     REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL,
0443           (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) &
0444            ~ATH_AIC_BT_AIC_ENABLE));
0445 
0446     if (ar9003_aic_cal_post_process(ah))
0447         aic->aic_cal_state = AIC_CAL_STATE_DONE;
0448     else
0449         aic->aic_cal_state = AIC_CAL_STATE_ERROR;
0450 }
0451 
0452 static u8 ar9003_aic_cal_continue(struct ath_hw *ah, bool cal_once)
0453 {
0454     struct ath_common *common = ath9k_hw_common(ah);
0455     struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
0456     struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
0457     int i, num_chan;
0458 
0459     num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN);
0460 
0461     if (!num_chan) {
0462         aic->aic_cal_state = AIC_CAL_STATE_ERROR;
0463         return aic->aic_cal_state;
0464     }
0465 
0466     if (cal_once) {
0467         for (i = 0; i < 10000; i++) {
0468             if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) &
0469                  AR_PHY_AIC_CAL_ENABLE) == 0)
0470                 break;
0471 
0472             udelay(100);
0473         }
0474     }
0475 
0476     /*
0477      * Use AR_PHY_AIC_CAL_ENABLE bit instead of AR_PHY_AIC_CAL_DONE.
0478      * Sometimes CAL_DONE bit is not asserted.
0479      */
0480     if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) &
0481          AR_PHY_AIC_CAL_ENABLE) != 0) {
0482         ath_dbg(common, MCI, "AIC cal is not done after 40ms");
0483         goto exit;
0484     }
0485 
0486     REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1,
0487           (ATH_AIC_SRAM_CAL_OFFSET | ATH_AIC_SRAM_AUTO_INCREMENT));
0488 
0489     for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
0490         u32 value;
0491 
0492         value = REG_READ(ah, AR_PHY_AIC_SRAM_DATA_B1);
0493 
0494         if (value & 0x01) {
0495             if (aic->aic_sram[i] == 0)
0496                 aic->aic_caled_chan++;
0497 
0498             aic->aic_sram[i] = value;
0499 
0500             if (!cal_once)
0501                 break;
0502         }
0503     }
0504 
0505     if ((aic->aic_caled_chan >= num_chan) || cal_once) {
0506         ar9003_aic_cal_done(ah);
0507     } else {
0508         /* Start calibration */
0509         REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE);
0510         REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1,
0511                 AR_PHY_AIC_CAL_CH_VALID_RESET);
0512         REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE);
0513     }
0514 exit:
0515     return aic->aic_cal_state;
0516 
0517 }
0518 
0519 u8 ar9003_aic_calibration(struct ath_hw *ah)
0520 {
0521     struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
0522     u8 cal_ret = AIC_CAL_STATE_ERROR;
0523 
0524     switch (aic->aic_cal_state) {
0525     case AIC_CAL_STATE_IDLE:
0526         cal_ret = ar9003_aic_cal_start(ah, 1);
0527         break;
0528     case AIC_CAL_STATE_STARTED:
0529         cal_ret = ar9003_aic_cal_continue(ah, false);
0530         break;
0531     case AIC_CAL_STATE_DONE:
0532         cal_ret = AIC_CAL_STATE_DONE;
0533         break;
0534     default:
0535         break;
0536     }
0537 
0538     return cal_ret;
0539 }
0540 
0541 u8 ar9003_aic_start_normal(struct ath_hw *ah)
0542 {
0543     struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
0544     int16_t i;
0545 
0546     if (aic->aic_cal_state != AIC_CAL_STATE_DONE)
0547         return 1;
0548 
0549     ar9003_aic_gain_table(ah);
0550 
0551     REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, ATH_AIC_SRAM_AUTO_INCREMENT);
0552 
0553     for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
0554         REG_WRITE(ah, AR_PHY_AIC_SRAM_DATA_B1, aic->aic_sram[i]);
0555     }
0556 
0557     /* FIXME: Replace these with proper register names */
0558     REG_WRITE(ah, 0xa6b0, 0x80);
0559     REG_WRITE(ah, 0xa6b4, 0x5b2df0);
0560     REG_WRITE(ah, 0xa6b8, 0x10762cc8);
0561     REG_WRITE(ah, 0xa6bc, 0x1219a4b);
0562     REG_WRITE(ah, 0xa6c0, 0x1e01);
0563     REG_WRITE(ah, 0xb6b4, 0xf0);
0564     REG_WRITE(ah, 0xb6c0, 0x1e01);
0565     REG_WRITE(ah, 0xb6b0, 0x81);
0566     REG_WRITE(ah, AR_PHY_65NM_CH1_RXTX4, 0x40000000);
0567 
0568     aic->aic_enabled = true;
0569 
0570     return 0;
0571 }
0572 
0573 u8 ar9003_aic_cal_reset(struct ath_hw *ah)
0574 {
0575     struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
0576 
0577     aic->aic_cal_state = AIC_CAL_STATE_IDLE;
0578     return aic->aic_cal_state;
0579 }
0580 
0581 u8 ar9003_aic_calibration_single(struct ath_hw *ah)
0582 {
0583     struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
0584     u8 cal_ret;
0585     int num_chan;
0586 
0587     num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN);
0588 
0589     (void) ar9003_aic_cal_start(ah, num_chan);
0590     cal_ret = ar9003_aic_cal_continue(ah, true);
0591 
0592     return cal_ret;
0593 }
0594 
0595 void ar9003_hw_attach_aic_ops(struct ath_hw *ah)
0596 {
0597     struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
0598 
0599     priv_ops->is_aic_enabled = ar9003_hw_is_aic_enabled;
0600 }