ath9k_hw: Fix AR9462 power consumption on idle associated
authorRajkumar Manoharan <rmanohar@qca.qualcomm.com>
Mon, 11 Jun 2012 06:49:31 +0000 (12:19 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 13 Jun 2012 18:35:52 +0000 (14:35 -0400)
The HW statemachine is sometimes found stuck in the state
WL_LNA_CTRL_DISABLE when BT is in sleep, which will cause
TX_HOLD always asserted and resmgr stuck in PENDING_TX state

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/ar9003_mci.h
drivers/net/wireless/ath/ath9k/hw.c

index b1ced2a76da33e462dafe789c812f2692a974d55..13907f63bdc0237068c0a8e54bb01f9b42f1518b 100644 (file)
@@ -1404,3 +1404,37 @@ void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
        /* Force another 2g5g update at next scanning */
        mci->update_2g5g = true;
 }
+
+void ar9003_mci_set_power_awake(struct ath_hw *ah)
+{
+       u32 btcoex_ctrl2, diag_sw;
+       int i;
+       u8 lna_ctrl, bt_sleep;
+
+       for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+               btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2);
+               if (btcoex_ctrl2 != 0xdeadbeef)
+                       break;
+               udelay(AH_TIME_QUANTUM);
+       }
+       REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23)));
+
+       for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+               diag_sw = REG_READ(ah, AR_DIAG_SW);
+               if (diag_sw != 0xdeadbeef)
+                       break;
+               udelay(AH_TIME_QUANTUM);
+       }
+       REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18)));
+       lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3;
+       bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP;
+
+       REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2);
+       REG_WRITE(ah, AR_DIAG_SW, diag_sw);
+
+       if (bt_sleep && (lna_ctrl == 2)) {
+               REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1);
+               REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1);
+               udelay(50);
+       }
+}
index 10282e2bcdc936ae8bd65690c62a67c18a4f27ab..2a8c764281ba80602a1eb0a1ea17af59f0c97d8e 100644 (file)
@@ -265,8 +265,6 @@ void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
 void ar9003_mci_cleanup(struct ath_hw *ah);
 void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
                              u32 *rx_msg_intr);
-void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
-
 /*
  * These functions are used by ath9k_hw.
  */
@@ -285,6 +283,8 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
                      bool is_full_sleep);
 void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
+void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
+void ar9003_mci_set_power_awake(struct ath_hw *ah);
 
 #else
 
@@ -322,6 +322,12 @@ static inline void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
 static inline void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 {
 }
+static inline void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_set_power_awake(struct ath_hw *ah)
+{
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #endif
index 45e670087e1c901fc62c0fac7ccc5b9459af0f93..6d893335f42b00abd354ccccfb4fe21be9ecef51 100644 (file)
@@ -2111,6 +2111,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
                    AR_RTC_FORCE_WAKE_EN);
        udelay(50);
 
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_set_power_awake(ah);
+
        for (i = POWER_UP_TIME / 50; i > 0; i--) {
                val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
                if (val == AR_RTC_STATUS_ON)