2 * Copyright (c) 2008-2009 Atheros Communications Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 /********************************/
21 /********************************/
23 #ifdef CONFIG_MAC80211_LEDS
24 static void ath_led_brightness(struct led_classdev
*led_cdev
,
25 enum led_brightness brightness
)
27 struct ath_softc
*sc
= container_of(led_cdev
, struct ath_softc
, led_cdev
);
28 ath9k_hw_set_gpio(sc
->sc_ah
, sc
->sc_ah
->led_pin
, (brightness
== LED_OFF
));
31 void ath_deinit_leds(struct ath_softc
*sc
)
33 if (!sc
->led_registered
)
36 ath_led_brightness(&sc
->led_cdev
, LED_OFF
);
37 led_classdev_unregister(&sc
->led_cdev
);
40 void ath_init_leds(struct ath_softc
*sc
)
44 if (AR_SREV_9287(sc
->sc_ah
))
45 sc
->sc_ah
->led_pin
= ATH_LED_PIN_9287
;
46 else if (AR_SREV_9485(sc
->sc_ah
))
47 sc
->sc_ah
->led_pin
= ATH_LED_PIN_9485
;
49 sc
->sc_ah
->led_pin
= ATH_LED_PIN_DEF
;
51 /* Configure gpio 1 for output */
52 ath9k_hw_cfg_output(sc
->sc_ah
, sc
->sc_ah
->led_pin
,
53 AR_GPIO_OUTPUT_MUX_AS_OUTPUT
);
54 /* LED off, active low */
55 ath9k_hw_set_gpio(sc
->sc_ah
, sc
->sc_ah
->led_pin
, 1);
58 sc
->led_cdev
.default_trigger
=
59 ieee80211_get_radio_led_name(sc
->hw
);
61 snprintf(sc
->led_name
, sizeof(sc
->led_name
),
62 "ath9k-%s", wiphy_name(sc
->hw
->wiphy
));
63 sc
->led_cdev
.name
= sc
->led_name
;
64 sc
->led_cdev
.brightness_set
= ath_led_brightness
;
66 ret
= led_classdev_register(wiphy_dev(sc
->hw
->wiphy
), &sc
->led_cdev
);
70 sc
->led_registered
= true;
78 static bool ath_is_rfkill_set(struct ath_softc
*sc
)
80 struct ath_hw
*ah
= sc
->sc_ah
;
82 return ath9k_hw_gpio_get(ah
, ah
->rfkill_gpio
) ==
86 void ath9k_rfkill_poll_state(struct ieee80211_hw
*hw
)
88 struct ath_softc
*sc
= hw
->priv
;
89 bool blocked
= !!ath_is_rfkill_set(sc
);
91 wiphy_rfkill_set_hw_state(hw
->wiphy
, blocked
);
94 void ath_start_rfkill_poll(struct ath_softc
*sc
)
96 struct ath_hw
*ah
= sc
->sc_ah
;
98 if (ah
->caps
.hw_caps
& ATH9K_HW_CAP_RFSILENT
)
99 wiphy_rfkill_start_polling(sc
->hw
->wiphy
);
107 * Detects if there is any priority bt traffic
109 static void ath_detect_bt_priority(struct ath_softc
*sc
)
111 struct ath_btcoex
*btcoex
= &sc
->btcoex
;
112 struct ath_hw
*ah
= sc
->sc_ah
;
114 if (ath9k_hw_gpio_get(sc
->sc_ah
, ah
->btcoex_hw
.btpriority_gpio
))
115 btcoex
->bt_priority_cnt
++;
117 if (time_after(jiffies
, btcoex
->bt_priority_time
+
118 msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD
))) {
119 sc
->sc_flags
&= ~(SC_OP_BT_PRIORITY_DETECTED
| SC_OP_BT_SCAN
);
120 /* Detect if colocated bt started scanning */
121 if (btcoex
->bt_priority_cnt
>= ATH_BT_CNT_SCAN_THRESHOLD
) {
122 ath_dbg(ath9k_hw_common(sc
->sc_ah
), ATH_DBG_BTCOEX
,
123 "BT scan detected\n");
124 sc
->sc_flags
|= (SC_OP_BT_SCAN
|
125 SC_OP_BT_PRIORITY_DETECTED
);
126 } else if (btcoex
->bt_priority_cnt
>= ATH_BT_CNT_THRESHOLD
) {
127 ath_dbg(ath9k_hw_common(sc
->sc_ah
), ATH_DBG_BTCOEX
,
128 "BT priority traffic detected\n");
129 sc
->sc_flags
|= SC_OP_BT_PRIORITY_DETECTED
;
132 btcoex
->bt_priority_cnt
= 0;
133 btcoex
->bt_priority_time
= jiffies
;
137 static void ath9k_gen_timer_start(struct ath_hw
*ah
,
138 struct ath_gen_timer
*timer
,
142 ath9k_hw_gen_timer_start(ah
, timer
, timer_next
, timer_period
);
144 if ((ah
->imask
& ATH9K_INT_GENTIMER
) == 0) {
145 ath9k_hw_disable_interrupts(ah
);
146 ah
->imask
|= ATH9K_INT_GENTIMER
;
147 ath9k_hw_set_interrupts(ah
, ah
->imask
);
151 static void ath9k_gen_timer_stop(struct ath_hw
*ah
, struct ath_gen_timer
*timer
)
153 struct ath_gen_timer_table
*timer_table
= &ah
->hw_gen_timers
;
155 ath9k_hw_gen_timer_stop(ah
, timer
);
157 /* if no timer is enabled, turn off interrupt mask */
158 if (timer_table
->timer_mask
.val
== 0) {
159 ath9k_hw_disable_interrupts(ah
);
160 ah
->imask
&= ~ATH9K_INT_GENTIMER
;
161 ath9k_hw_set_interrupts(ah
, ah
->imask
);
166 * This is the master bt coex timer which runs for every
167 * 45ms, bt traffic will be given priority during 55% of this
168 * period while wlan gets remaining 45%
170 static void ath_btcoex_period_timer(unsigned long data
)
172 struct ath_softc
*sc
= (struct ath_softc
*) data
;
173 struct ath_hw
*ah
= sc
->sc_ah
;
174 struct ath_btcoex
*btcoex
= &sc
->btcoex
;
175 struct ath_common
*common
= ath9k_hw_common(ah
);
179 ath_detect_bt_priority(sc
);
181 is_btscan
= sc
->sc_flags
& SC_OP_BT_SCAN
;
183 spin_lock_bh(&btcoex
->btcoex_lock
);
185 ath9k_cmn_btcoex_bt_stomp(common
, is_btscan
? ATH_BTCOEX_STOMP_ALL
:
186 btcoex
->bt_stomp_type
);
188 spin_unlock_bh(&btcoex
->btcoex_lock
);
190 if (btcoex
->btcoex_period
!= btcoex
->btcoex_no_stomp
) {
191 if (btcoex
->hw_timer_enabled
)
192 ath9k_gen_timer_stop(ah
, btcoex
->no_stomp_timer
);
194 timer_period
= is_btscan
? btcoex
->btscan_no_stomp
:
195 btcoex
->btcoex_no_stomp
;
196 ath9k_gen_timer_start(ah
, btcoex
->no_stomp_timer
, 0,
198 btcoex
->hw_timer_enabled
= true;
201 mod_timer(&btcoex
->period_timer
, jiffies
+
202 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD
));
206 * Generic tsf based hw timer which configures weight
207 * registers to time slice between wlan and bt traffic
209 static void ath_btcoex_no_stomp_timer(void *arg
)
211 struct ath_softc
*sc
= (struct ath_softc
*)arg
;
212 struct ath_hw
*ah
= sc
->sc_ah
;
213 struct ath_btcoex
*btcoex
= &sc
->btcoex
;
214 struct ath_common
*common
= ath9k_hw_common(ah
);
215 bool is_btscan
= sc
->sc_flags
& SC_OP_BT_SCAN
;
217 ath_dbg(common
, ATH_DBG_BTCOEX
,
218 "no stomp timer running\n");
220 spin_lock_bh(&btcoex
->btcoex_lock
);
222 if (btcoex
->bt_stomp_type
== ATH_BTCOEX_STOMP_LOW
|| is_btscan
)
223 ath9k_cmn_btcoex_bt_stomp(common
, ATH_BTCOEX_STOMP_NONE
);
224 else if (btcoex
->bt_stomp_type
== ATH_BTCOEX_STOMP_ALL
)
225 ath9k_cmn_btcoex_bt_stomp(common
, ATH_BTCOEX_STOMP_LOW
);
227 spin_unlock_bh(&btcoex
->btcoex_lock
);
230 int ath_init_btcoex_timer(struct ath_softc
*sc
)
232 struct ath_btcoex
*btcoex
= &sc
->btcoex
;
234 btcoex
->btcoex_period
= ATH_BTCOEX_DEF_BT_PERIOD
* 1000;
235 btcoex
->btcoex_no_stomp
= (100 - ATH_BTCOEX_DEF_DUTY_CYCLE
) *
236 btcoex
->btcoex_period
/ 100;
237 btcoex
->btscan_no_stomp
= (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE
) *
238 btcoex
->btcoex_period
/ 100;
240 setup_timer(&btcoex
->period_timer
, ath_btcoex_period_timer
,
243 spin_lock_init(&btcoex
->btcoex_lock
);
245 btcoex
->no_stomp_timer
= ath_gen_timer_alloc(sc
->sc_ah
,
246 ath_btcoex_no_stomp_timer
,
247 ath_btcoex_no_stomp_timer
,
248 (void *) sc
, AR_FIRST_NDP_TIMER
);
250 if (!btcoex
->no_stomp_timer
)
257 * (Re)start btcoex timers
259 void ath9k_btcoex_timer_resume(struct ath_softc
*sc
)
261 struct ath_btcoex
*btcoex
= &sc
->btcoex
;
262 struct ath_hw
*ah
= sc
->sc_ah
;
264 ath_dbg(ath9k_hw_common(ah
), ATH_DBG_BTCOEX
,
265 "Starting btcoex timers\n");
267 /* make sure duty cycle timer is also stopped when resuming */
268 if (btcoex
->hw_timer_enabled
)
269 ath9k_gen_timer_stop(sc
->sc_ah
, btcoex
->no_stomp_timer
);
271 btcoex
->bt_priority_cnt
= 0;
272 btcoex
->bt_priority_time
= jiffies
;
273 sc
->sc_flags
&= ~(SC_OP_BT_PRIORITY_DETECTED
| SC_OP_BT_SCAN
);
275 mod_timer(&btcoex
->period_timer
, jiffies
);
280 * Pause btcoex timer and bt duty cycle timer
282 void ath9k_btcoex_timer_pause(struct ath_softc
*sc
)
284 struct ath_btcoex
*btcoex
= &sc
->btcoex
;
285 struct ath_hw
*ah
= sc
->sc_ah
;
287 del_timer_sync(&btcoex
->period_timer
);
289 if (btcoex
->hw_timer_enabled
)
290 ath9k_gen_timer_stop(ah
, btcoex
->no_stomp_timer
);
292 btcoex
->hw_timer_enabled
= false;