10fca65c1SSujith /* 20fca65c1SSujith * Copyright (c) 2008-2009 Atheros Communications Inc. 30fca65c1SSujith * 40fca65c1SSujith * Permission to use, copy, modify, and/or distribute this software for any 50fca65c1SSujith * purpose with or without fee is hereby granted, provided that the above 60fca65c1SSujith * copyright notice and this permission notice appear in all copies. 70fca65c1SSujith * 80fca65c1SSujith * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 90fca65c1SSujith * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 100fca65c1SSujith * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 110fca65c1SSujith * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 120fca65c1SSujith * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 130fca65c1SSujith * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 140fca65c1SSujith * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 150fca65c1SSujith */ 160fca65c1SSujith 170fca65c1SSujith #include "ath9k.h" 180fca65c1SSujith 190fca65c1SSujith /********************************/ 200fca65c1SSujith /* LED functions */ 210fca65c1SSujith /********************************/ 220fca65c1SSujith 230fca65c1SSujith static void ath_led_blink_work(struct work_struct *work) 240fca65c1SSujith { 250fca65c1SSujith struct ath_softc *sc = container_of(work, struct ath_softc, 260fca65c1SSujith ath_led_blink_work.work); 270fca65c1SSujith 280fca65c1SSujith if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) 290fca65c1SSujith return; 300fca65c1SSujith 310fca65c1SSujith if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || 320fca65c1SSujith (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) 330fca65c1SSujith ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); 340fca65c1SSujith else 350fca65c1SSujith ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 360fca65c1SSujith (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); 370fca65c1SSujith 380fca65c1SSujith ieee80211_queue_delayed_work(sc->hw, 390fca65c1SSujith &sc->ath_led_blink_work, 400fca65c1SSujith (sc->sc_flags & SC_OP_LED_ON) ? 410fca65c1SSujith msecs_to_jiffies(sc->led_off_duration) : 420fca65c1SSujith msecs_to_jiffies(sc->led_on_duration)); 430fca65c1SSujith 440fca65c1SSujith sc->led_on_duration = sc->led_on_cnt ? 450fca65c1SSujith max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : 460fca65c1SSujith ATH_LED_ON_DURATION_IDLE; 470fca65c1SSujith sc->led_off_duration = sc->led_off_cnt ? 480fca65c1SSujith max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : 490fca65c1SSujith ATH_LED_OFF_DURATION_IDLE; 500fca65c1SSujith sc->led_on_cnt = sc->led_off_cnt = 0; 510fca65c1SSujith if (sc->sc_flags & SC_OP_LED_ON) 520fca65c1SSujith sc->sc_flags &= ~SC_OP_LED_ON; 530fca65c1SSujith else 540fca65c1SSujith sc->sc_flags |= SC_OP_LED_ON; 550fca65c1SSujith } 560fca65c1SSujith 570fca65c1SSujith static void ath_led_brightness(struct led_classdev *led_cdev, 580fca65c1SSujith enum led_brightness brightness) 590fca65c1SSujith { 600fca65c1SSujith struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); 610fca65c1SSujith struct ath_softc *sc = led->sc; 620fca65c1SSujith 630fca65c1SSujith switch (brightness) { 640fca65c1SSujith case LED_OFF: 650fca65c1SSujith if (led->led_type == ATH_LED_ASSOC || 660fca65c1SSujith led->led_type == ATH_LED_RADIO) { 670fca65c1SSujith ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 680fca65c1SSujith (led->led_type == ATH_LED_RADIO)); 690fca65c1SSujith sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; 700fca65c1SSujith if (led->led_type == ATH_LED_RADIO) 710fca65c1SSujith sc->sc_flags &= ~SC_OP_LED_ON; 720fca65c1SSujith } else { 730fca65c1SSujith sc->led_off_cnt++; 740fca65c1SSujith } 750fca65c1SSujith break; 760fca65c1SSujith case LED_FULL: 770fca65c1SSujith if (led->led_type == ATH_LED_ASSOC) { 780fca65c1SSujith sc->sc_flags |= SC_OP_LED_ASSOCIATED; 790fca65c1SSujith ieee80211_queue_delayed_work(sc->hw, 800fca65c1SSujith &sc->ath_led_blink_work, 0); 810fca65c1SSujith } else if (led->led_type == ATH_LED_RADIO) { 820fca65c1SSujith ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); 830fca65c1SSujith sc->sc_flags |= SC_OP_LED_ON; 840fca65c1SSujith } else { 850fca65c1SSujith sc->led_on_cnt++; 860fca65c1SSujith } 870fca65c1SSujith break; 880fca65c1SSujith default: 890fca65c1SSujith break; 900fca65c1SSujith } 910fca65c1SSujith } 920fca65c1SSujith 930fca65c1SSujith static int ath_register_led(struct ath_softc *sc, struct ath_led *led, 940fca65c1SSujith char *trigger) 950fca65c1SSujith { 960fca65c1SSujith int ret; 970fca65c1SSujith 980fca65c1SSujith led->sc = sc; 990fca65c1SSujith led->led_cdev.name = led->name; 1000fca65c1SSujith led->led_cdev.default_trigger = trigger; 1010fca65c1SSujith led->led_cdev.brightness_set = ath_led_brightness; 1020fca65c1SSujith 1030fca65c1SSujith ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); 1040fca65c1SSujith if (ret) 1050fca65c1SSujith ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, 1060fca65c1SSujith "Failed to register led:%s", led->name); 1070fca65c1SSujith else 1080fca65c1SSujith led->registered = 1; 1090fca65c1SSujith return ret; 1100fca65c1SSujith } 1110fca65c1SSujith 1120fca65c1SSujith static void ath_unregister_led(struct ath_led *led) 1130fca65c1SSujith { 1140fca65c1SSujith if (led->registered) { 1150fca65c1SSujith led_classdev_unregister(&led->led_cdev); 1160fca65c1SSujith led->registered = 0; 1170fca65c1SSujith } 1180fca65c1SSujith } 1190fca65c1SSujith 1200fca65c1SSujith void ath_deinit_leds(struct ath_softc *sc) 1210fca65c1SSujith { 1220fca65c1SSujith ath_unregister_led(&sc->assoc_led); 1230fca65c1SSujith sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; 1240fca65c1SSujith ath_unregister_led(&sc->tx_led); 1250fca65c1SSujith ath_unregister_led(&sc->rx_led); 1260fca65c1SSujith ath_unregister_led(&sc->radio_led); 1270fca65c1SSujith ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); 1280fca65c1SSujith } 1290fca65c1SSujith 1300fca65c1SSujith void ath_init_leds(struct ath_softc *sc) 1310fca65c1SSujith { 1320fca65c1SSujith char *trigger; 1330fca65c1SSujith int ret; 1340fca65c1SSujith 1350fca65c1SSujith if (AR_SREV_9287(sc->sc_ah)) 1360fca65c1SSujith sc->sc_ah->led_pin = ATH_LED_PIN_9287; 1370fca65c1SSujith else 1380fca65c1SSujith sc->sc_ah->led_pin = ATH_LED_PIN_DEF; 1390fca65c1SSujith 1400fca65c1SSujith /* Configure gpio 1 for output */ 1410fca65c1SSujith ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, 1420fca65c1SSujith AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 1430fca65c1SSujith /* LED off, active low */ 1440fca65c1SSujith ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); 1450fca65c1SSujith 1460fca65c1SSujith INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); 1470fca65c1SSujith 1480fca65c1SSujith trigger = ieee80211_get_radio_led_name(sc->hw); 1490fca65c1SSujith snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), 1500fca65c1SSujith "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); 1510fca65c1SSujith ret = ath_register_led(sc, &sc->radio_led, trigger); 1520fca65c1SSujith sc->radio_led.led_type = ATH_LED_RADIO; 1530fca65c1SSujith if (ret) 1540fca65c1SSujith goto fail; 1550fca65c1SSujith 1560fca65c1SSujith trigger = ieee80211_get_assoc_led_name(sc->hw); 1570fca65c1SSujith snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), 1580fca65c1SSujith "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); 1590fca65c1SSujith ret = ath_register_led(sc, &sc->assoc_led, trigger); 1600fca65c1SSujith sc->assoc_led.led_type = ATH_LED_ASSOC; 1610fca65c1SSujith if (ret) 1620fca65c1SSujith goto fail; 1630fca65c1SSujith 1640fca65c1SSujith trigger = ieee80211_get_tx_led_name(sc->hw); 1650fca65c1SSujith snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), 1660fca65c1SSujith "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); 1670fca65c1SSujith ret = ath_register_led(sc, &sc->tx_led, trigger); 1680fca65c1SSujith sc->tx_led.led_type = ATH_LED_TX; 1690fca65c1SSujith if (ret) 1700fca65c1SSujith goto fail; 1710fca65c1SSujith 1720fca65c1SSujith trigger = ieee80211_get_rx_led_name(sc->hw); 1730fca65c1SSujith snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), 1740fca65c1SSujith "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); 1750fca65c1SSujith ret = ath_register_led(sc, &sc->rx_led, trigger); 1760fca65c1SSujith sc->rx_led.led_type = ATH_LED_RX; 1770fca65c1SSujith if (ret) 1780fca65c1SSujith goto fail; 1790fca65c1SSujith 1800fca65c1SSujith return; 1810fca65c1SSujith 1820fca65c1SSujith fail: 1830fca65c1SSujith cancel_delayed_work_sync(&sc->ath_led_blink_work); 1840fca65c1SSujith ath_deinit_leds(sc); 1850fca65c1SSujith } 1860fca65c1SSujith 1870fca65c1SSujith /*******************/ 1880fca65c1SSujith /* Rfkill */ 1890fca65c1SSujith /*******************/ 1900fca65c1SSujith 1910fca65c1SSujith static bool ath_is_rfkill_set(struct ath_softc *sc) 1920fca65c1SSujith { 1930fca65c1SSujith struct ath_hw *ah = sc->sc_ah; 1940fca65c1SSujith 1950fca65c1SSujith return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == 1960fca65c1SSujith ah->rfkill_polarity; 1970fca65c1SSujith } 1980fca65c1SSujith 1990fca65c1SSujith void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) 2000fca65c1SSujith { 2010fca65c1SSujith struct ath_wiphy *aphy = hw->priv; 2020fca65c1SSujith struct ath_softc *sc = aphy->sc; 2030fca65c1SSujith bool blocked = !!ath_is_rfkill_set(sc); 2040fca65c1SSujith 2050fca65c1SSujith wiphy_rfkill_set_hw_state(hw->wiphy, blocked); 2060fca65c1SSujith } 2070fca65c1SSujith 2080fca65c1SSujith void ath_start_rfkill_poll(struct ath_softc *sc) 2090fca65c1SSujith { 2100fca65c1SSujith struct ath_hw *ah = sc->sc_ah; 2110fca65c1SSujith 2120fca65c1SSujith if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) 2130fca65c1SSujith wiphy_rfkill_start_polling(sc->hw->wiphy); 2140fca65c1SSujith } 2150fca65c1SSujith 2160fca65c1SSujith /******************/ 2170fca65c1SSujith /* BTCOEX */ 2180fca65c1SSujith /******************/ 2190fca65c1SSujith 2200fca65c1SSujith /* 2210fca65c1SSujith * Detects if there is any priority bt traffic 2220fca65c1SSujith */ 2230fca65c1SSujith static void ath_detect_bt_priority(struct ath_softc *sc) 2240fca65c1SSujith { 2250fca65c1SSujith struct ath_btcoex *btcoex = &sc->btcoex; 2260fca65c1SSujith struct ath_hw *ah = sc->sc_ah; 2270fca65c1SSujith 2280fca65c1SSujith if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) 2290fca65c1SSujith btcoex->bt_priority_cnt++; 2300fca65c1SSujith 2310fca65c1SSujith if (time_after(jiffies, btcoex->bt_priority_time + 2320fca65c1SSujith msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { 233*58da1318SVasanthakumar Thiagarajan sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN); 234*58da1318SVasanthakumar Thiagarajan /* Detect if colocated bt started scanning */ 235*58da1318SVasanthakumar Thiagarajan if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { 236*58da1318SVasanthakumar Thiagarajan ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, 237*58da1318SVasanthakumar Thiagarajan "BT scan detected"); 238*58da1318SVasanthakumar Thiagarajan sc->sc_flags |= (SC_OP_BT_SCAN | 239*58da1318SVasanthakumar Thiagarajan SC_OP_BT_PRIORITY_DETECTED); 240*58da1318SVasanthakumar Thiagarajan } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { 2410fca65c1SSujith ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, 2420fca65c1SSujith "BT priority traffic detected"); 2430fca65c1SSujith sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; 2440fca65c1SSujith } 2450fca65c1SSujith 2460fca65c1SSujith btcoex->bt_priority_cnt = 0; 2470fca65c1SSujith btcoex->bt_priority_time = jiffies; 2480fca65c1SSujith } 2490fca65c1SSujith } 2500fca65c1SSujith 2510fca65c1SSujith /* 2520fca65c1SSujith * Configures appropriate weight based on stomp type. 2530fca65c1SSujith */ 2540fca65c1SSujith static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, 2550fca65c1SSujith enum ath_stomp_type stomp_type) 2560fca65c1SSujith { 2570fca65c1SSujith struct ath_hw *ah = sc->sc_ah; 2580fca65c1SSujith 2590fca65c1SSujith switch (stomp_type) { 2600fca65c1SSujith case ATH_BTCOEX_STOMP_ALL: 2610fca65c1SSujith ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, 2620fca65c1SSujith AR_STOMP_ALL_WLAN_WGHT); 2630fca65c1SSujith break; 2640fca65c1SSujith case ATH_BTCOEX_STOMP_LOW: 2650fca65c1SSujith ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, 2660fca65c1SSujith AR_STOMP_LOW_WLAN_WGHT); 2670fca65c1SSujith break; 2680fca65c1SSujith case ATH_BTCOEX_STOMP_NONE: 2690fca65c1SSujith ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, 2700fca65c1SSujith AR_STOMP_NONE_WLAN_WGHT); 2710fca65c1SSujith break; 2720fca65c1SSujith default: 2730fca65c1SSujith ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, 2740fca65c1SSujith "Invalid Stomptype\n"); 2750fca65c1SSujith break; 2760fca65c1SSujith } 2770fca65c1SSujith 2780fca65c1SSujith ath9k_hw_btcoex_enable(ah); 2790fca65c1SSujith } 2800fca65c1SSujith 2810fca65c1SSujith static void ath9k_gen_timer_start(struct ath_hw *ah, 2820fca65c1SSujith struct ath_gen_timer *timer, 2830fca65c1SSujith u32 timer_next, 2840fca65c1SSujith u32 timer_period) 2850fca65c1SSujith { 2860fca65c1SSujith struct ath_common *common = ath9k_hw_common(ah); 2870fca65c1SSujith struct ath_softc *sc = (struct ath_softc *) common->priv; 2880fca65c1SSujith 2890fca65c1SSujith ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); 2900fca65c1SSujith 2910fca65c1SSujith if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { 2920fca65c1SSujith ath9k_hw_set_interrupts(ah, 0); 2930fca65c1SSujith sc->imask |= ATH9K_INT_GENTIMER; 2940fca65c1SSujith ath9k_hw_set_interrupts(ah, sc->imask); 2950fca65c1SSujith } 2960fca65c1SSujith } 2970fca65c1SSujith 2980fca65c1SSujith static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) 2990fca65c1SSujith { 3000fca65c1SSujith struct ath_common *common = ath9k_hw_common(ah); 3010fca65c1SSujith struct ath_softc *sc = (struct ath_softc *) common->priv; 3020fca65c1SSujith struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; 3030fca65c1SSujith 3040fca65c1SSujith ath9k_hw_gen_timer_stop(ah, timer); 3050fca65c1SSujith 3060fca65c1SSujith /* if no timer is enabled, turn off interrupt mask */ 3070fca65c1SSujith if (timer_table->timer_mask.val == 0) { 3080fca65c1SSujith ath9k_hw_set_interrupts(ah, 0); 3090fca65c1SSujith sc->imask &= ~ATH9K_INT_GENTIMER; 3100fca65c1SSujith ath9k_hw_set_interrupts(ah, sc->imask); 3110fca65c1SSujith } 3120fca65c1SSujith } 3130fca65c1SSujith 3140fca65c1SSujith /* 3150fca65c1SSujith * This is the master bt coex timer which runs for every 3160fca65c1SSujith * 45ms, bt traffic will be given priority during 55% of this 3170fca65c1SSujith * period while wlan gets remaining 45% 3180fca65c1SSujith */ 3190fca65c1SSujith static void ath_btcoex_period_timer(unsigned long data) 3200fca65c1SSujith { 3210fca65c1SSujith struct ath_softc *sc = (struct ath_softc *) data; 3220fca65c1SSujith struct ath_hw *ah = sc->sc_ah; 3230fca65c1SSujith struct ath_btcoex *btcoex = &sc->btcoex; 324*58da1318SVasanthakumar Thiagarajan u32 timer_period; 325*58da1318SVasanthakumar Thiagarajan bool is_btscan; 3260fca65c1SSujith 3270fca65c1SSujith ath_detect_bt_priority(sc); 3280fca65c1SSujith 329*58da1318SVasanthakumar Thiagarajan is_btscan = sc->sc_flags & SC_OP_BT_SCAN; 330*58da1318SVasanthakumar Thiagarajan 3310fca65c1SSujith spin_lock_bh(&btcoex->btcoex_lock); 3320fca65c1SSujith 333*58da1318SVasanthakumar Thiagarajan ath9k_btcoex_bt_stomp(sc, is_btscan ? ATH_BTCOEX_STOMP_ALL : 334*58da1318SVasanthakumar Thiagarajan btcoex->bt_stomp_type); 3350fca65c1SSujith 3360fca65c1SSujith spin_unlock_bh(&btcoex->btcoex_lock); 3370fca65c1SSujith 3380fca65c1SSujith if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { 3390fca65c1SSujith if (btcoex->hw_timer_enabled) 3400fca65c1SSujith ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); 3410fca65c1SSujith 342*58da1318SVasanthakumar Thiagarajan timer_period = is_btscan ? btcoex->btscan_no_stomp : 343*58da1318SVasanthakumar Thiagarajan btcoex->btcoex_no_stomp; 3440fca65c1SSujith ath9k_gen_timer_start(ah, 3450fca65c1SSujith btcoex->no_stomp_timer, 3460fca65c1SSujith (ath9k_hw_gettsf32(ah) + 347*58da1318SVasanthakumar Thiagarajan timer_period), timer_period * 10); 3480fca65c1SSujith btcoex->hw_timer_enabled = true; 3490fca65c1SSujith } 3500fca65c1SSujith 3510fca65c1SSujith mod_timer(&btcoex->period_timer, jiffies + 3520fca65c1SSujith msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); 3530fca65c1SSujith } 3540fca65c1SSujith 3550fca65c1SSujith /* 3560fca65c1SSujith * Generic tsf based hw timer which configures weight 3570fca65c1SSujith * registers to time slice between wlan and bt traffic 3580fca65c1SSujith */ 3590fca65c1SSujith static void ath_btcoex_no_stomp_timer(void *arg) 3600fca65c1SSujith { 3610fca65c1SSujith struct ath_softc *sc = (struct ath_softc *)arg; 3620fca65c1SSujith struct ath_hw *ah = sc->sc_ah; 3630fca65c1SSujith struct ath_btcoex *btcoex = &sc->btcoex; 364*58da1318SVasanthakumar Thiagarajan bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN; 3650fca65c1SSujith 3660fca65c1SSujith ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, 3670fca65c1SSujith "no stomp timer running \n"); 3680fca65c1SSujith 3690fca65c1SSujith spin_lock_bh(&btcoex->btcoex_lock); 3700fca65c1SSujith 371*58da1318SVasanthakumar Thiagarajan if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) 3720fca65c1SSujith ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); 3730fca65c1SSujith else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) 3740fca65c1SSujith ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); 3750fca65c1SSujith 3760fca65c1SSujith spin_unlock_bh(&btcoex->btcoex_lock); 3770fca65c1SSujith } 3780fca65c1SSujith 3790fca65c1SSujith int ath_init_btcoex_timer(struct ath_softc *sc) 3800fca65c1SSujith { 3810fca65c1SSujith struct ath_btcoex *btcoex = &sc->btcoex; 3820fca65c1SSujith 3830fca65c1SSujith btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; 3840fca65c1SSujith btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 3850fca65c1SSujith btcoex->btcoex_period / 100; 386*58da1318SVasanthakumar Thiagarajan btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 387*58da1318SVasanthakumar Thiagarajan btcoex->btcoex_period / 100; 3880fca65c1SSujith 3890fca65c1SSujith setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, 3900fca65c1SSujith (unsigned long) sc); 3910fca65c1SSujith 3920fca65c1SSujith spin_lock_init(&btcoex->btcoex_lock); 3930fca65c1SSujith 3940fca65c1SSujith btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, 3950fca65c1SSujith ath_btcoex_no_stomp_timer, 3960fca65c1SSujith ath_btcoex_no_stomp_timer, 3970fca65c1SSujith (void *) sc, AR_FIRST_NDP_TIMER); 3980fca65c1SSujith 3990fca65c1SSujith if (!btcoex->no_stomp_timer) 4000fca65c1SSujith return -ENOMEM; 4010fca65c1SSujith 4020fca65c1SSujith return 0; 4030fca65c1SSujith } 4040fca65c1SSujith 4050fca65c1SSujith /* 4060fca65c1SSujith * (Re)start btcoex timers 4070fca65c1SSujith */ 4080fca65c1SSujith void ath9k_btcoex_timer_resume(struct ath_softc *sc) 4090fca65c1SSujith { 4100fca65c1SSujith struct ath_btcoex *btcoex = &sc->btcoex; 4110fca65c1SSujith struct ath_hw *ah = sc->sc_ah; 4120fca65c1SSujith 4130fca65c1SSujith ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, 4140fca65c1SSujith "Starting btcoex timers"); 4150fca65c1SSujith 4160fca65c1SSujith /* make sure duty cycle timer is also stopped when resuming */ 4170fca65c1SSujith if (btcoex->hw_timer_enabled) 4180fca65c1SSujith ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); 4190fca65c1SSujith 4200fca65c1SSujith btcoex->bt_priority_cnt = 0; 4210fca65c1SSujith btcoex->bt_priority_time = jiffies; 422*58da1318SVasanthakumar Thiagarajan sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN); 4230fca65c1SSujith 4240fca65c1SSujith mod_timer(&btcoex->period_timer, jiffies); 4250fca65c1SSujith } 4260fca65c1SSujith 4270fca65c1SSujith 4280fca65c1SSujith /* 4290fca65c1SSujith * Pause btcoex timer and bt duty cycle timer 4300fca65c1SSujith */ 4310fca65c1SSujith void ath9k_btcoex_timer_pause(struct ath_softc *sc) 4320fca65c1SSujith { 4330fca65c1SSujith struct ath_btcoex *btcoex = &sc->btcoex; 4340fca65c1SSujith struct ath_hw *ah = sc->sc_ah; 4350fca65c1SSujith 4360fca65c1SSujith del_timer_sync(&btcoex->period_timer); 4370fca65c1SSujith 4380fca65c1SSujith if (btcoex->hw_timer_enabled) 4390fca65c1SSujith ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); 4400fca65c1SSujith 4410fca65c1SSujith btcoex->hw_timer_enabled = false; 4420fca65c1SSujith } 443