ath9k: fix power consumption on network sleep when BTCOEX is enabled
authorRajkumar Manoharan <rmanohar@qca.qualcomm.com>
Sun, 1 Jul 2012 14:23:54 +0000 (19:53 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 9 Jul 2012 20:36:20 +0000 (16:36 -0400)
The chip is waken up for every 45ms in btcoex timer cycle to
for sharing the radio between BT and WLAN. Whenever the wlan
interface is in network sleep mode, do not schedule hw timers.
This could reduce power consumption on idle associated state.

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

index fe39eb4c42a1f37b6357b7550b1dffeed572dac9..79840d6deef2feeb312a35defeb9b8e1500fcc5a 100644 (file)
@@ -481,6 +481,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc);
 void ath9k_btcoex_timer_pause(struct ath_softc *sc);
 void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status);
 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen);
+void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc);
 #else
 static inline int ath9k_init_btcoex(struct ath_softc *sc)
 {
@@ -504,6 +505,9 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc,
 {
        return 0;
 }
+static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
+{
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 /********************/
index 5eac4d168653e29818c1cdb3df5f8d7133cf3320..f23af023f3c633317cae124156549d7674aa9ea8 100644 (file)
@@ -194,6 +194,14 @@ static void ath_btcoex_period_timer(unsigned long data)
        struct ath_mci_profile *mci = &btcoex->mci;
        u32 timer_period;
        bool is_btscan;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) {
+               spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+               goto skip_hw_wakeup;
+       }
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        ath9k_ps_wakeup(sc);
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
@@ -232,6 +240,7 @@ static void ath_btcoex_period_timer(unsigned long data)
        }
 
        ath9k_ps_restore(sc);
+skip_hw_wakeup:
        timer_period = btcoex->btcoex_period;
        mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
 }
@@ -328,6 +337,13 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc)
        btcoex->hw_timer_enabled = false;
 }
 
+void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
+{
+       struct ath_btcoex *btcoex = &sc->btcoex;
+
+       ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
+}
+
 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
 {
        struct ath_btcoex *btcoex = &sc->btcoex;
index 6ce012815ba6e84f422647622c43b9409c5e6c35..06a3d1c7f2b96509dcf25c7750a565317eb6f1d1 100644 (file)
@@ -130,6 +130,8 @@ void ath9k_ps_restore(struct ath_softc *sc)
                                     PS_WAIT_FOR_PSPOLL_DATA |
                                     PS_WAIT_FOR_TX_ACK))) {
                mode = ATH9K_PM_NETWORK_SLEEP;
+               if (ath9k_hw_btcoex_is_enabled(sc->sc_ah))
+                       ath9k_btcoex_stop_gen_timer(sc);
        } else {
                goto unlock;
        }