2
* Copyright (c) 2010 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.
24
* Detects if there is any priority bt traffic
26
static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
28
struct ath_btcoex *btcoex = &priv->btcoex;
29
struct ath_hw *ah = priv->ah;
31
if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio))
32
btcoex->bt_priority_cnt++;
34
if (time_after(jiffies, btcoex->bt_priority_time +
35
msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
36
priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
37
/* Detect if colocated bt started scanning */
38
if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
39
ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
40
"BT scan detected\n");
41
priv->op_flags |= (OP_BT_SCAN |
42
OP_BT_PRIORITY_DETECTED);
43
} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
44
ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
45
"BT priority traffic detected\n");
46
priv->op_flags |= OP_BT_PRIORITY_DETECTED;
49
btcoex->bt_priority_cnt = 0;
50
btcoex->bt_priority_time = jiffies;
55
* This is the master bt coex work which runs for every
56
* 45ms, bt traffic will be given priority during 55% of this
57
* period while wlan gets remaining 45%
59
static void ath_btcoex_period_work(struct work_struct *work)
61
struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
62
coex_period_work.work);
63
struct ath_btcoex *btcoex = &priv->btcoex;
64
struct ath_common *common = ath9k_hw_common(priv->ah);
70
ath_detect_bt_priority(priv);
72
is_btscan = !!(priv->op_flags & OP_BT_SCAN);
74
aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
76
WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
78
ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
79
btcoex->bt_stomp_type);
81
timer_period = is_btscan ? btcoex->btscan_no_stomp :
82
btcoex->btcoex_no_stomp;
83
ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
84
msecs_to_jiffies(timer_period));
85
ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
86
msecs_to_jiffies(btcoex->btcoex_period));
90
* Work to time slice between wlan and bt traffic and
91
* configure weight registers
93
static void ath_btcoex_duty_cycle_work(struct work_struct *work)
95
struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
96
duty_cycle_work.work);
97
struct ath_hw *ah = priv->ah;
98
struct ath_btcoex *btcoex = &priv->btcoex;
99
struct ath_common *common = ath9k_hw_common(ah);
100
bool is_btscan = priv->op_flags & OP_BT_SCAN;
102
ath_dbg(common, ATH_DBG_BTCOEX,
103
"time slice work for bt and wlan\n");
105
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
106
ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
107
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
108
ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
111
void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
113
struct ath_btcoex *btcoex = &priv->btcoex;
115
btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
116
btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
117
btcoex->btcoex_period / 100;
118
btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
119
btcoex->btcoex_period / 100;
120
INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work);
121
INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work);
125
* (Re)start btcoex work
128
void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
130
struct ath_btcoex *btcoex = &priv->btcoex;
131
struct ath_hw *ah = priv->ah;
133
ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Starting btcoex work\n");
135
btcoex->bt_priority_cnt = 0;
136
btcoex->bt_priority_time = jiffies;
137
priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
138
ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
143
* Cancel btcoex and bt duty cycle work.
145
void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
147
cancel_delayed_work_sync(&priv->coex_period_work);
148
cancel_delayed_work_sync(&priv->duty_cycle_work);
155
static void ath9k_led_blink_work(struct work_struct *work)
157
struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
158
ath9k_led_blink_work.work);
160
if (!(priv->op_flags & OP_LED_ASSOCIATED))
163
if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
164
(priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
165
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
167
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
168
(priv->op_flags & OP_LED_ON) ? 1 : 0);
170
ieee80211_queue_delayed_work(priv->hw,
171
&priv->ath9k_led_blink_work,
172
(priv->op_flags & OP_LED_ON) ?
173
msecs_to_jiffies(priv->led_off_duration) :
174
msecs_to_jiffies(priv->led_on_duration));
176
priv->led_on_duration = priv->led_on_cnt ?
177
max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
178
ATH_LED_ON_DURATION_IDLE;
179
priv->led_off_duration = priv->led_off_cnt ?
180
max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
181
ATH_LED_OFF_DURATION_IDLE;
182
priv->led_on_cnt = priv->led_off_cnt = 0;
184
if (priv->op_flags & OP_LED_ON)
185
priv->op_flags &= ~OP_LED_ON;
187
priv->op_flags |= OP_LED_ON;
190
static void ath9k_led_brightness_work(struct work_struct *work)
192
struct ath_led *led = container_of(work, struct ath_led,
193
brightness_work.work);
194
struct ath9k_htc_priv *priv = led->priv;
196
switch (led->brightness) {
198
if (led->led_type == ATH_LED_ASSOC ||
199
led->led_type == ATH_LED_RADIO) {
200
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
201
(led->led_type == ATH_LED_RADIO));
202
priv->op_flags &= ~OP_LED_ASSOCIATED;
203
if (led->led_type == ATH_LED_RADIO)
204
priv->op_flags &= ~OP_LED_ON;
210
if (led->led_type == ATH_LED_ASSOC) {
211
priv->op_flags |= OP_LED_ASSOCIATED;
212
ieee80211_queue_delayed_work(priv->hw,
213
&priv->ath9k_led_blink_work, 0);
214
} else if (led->led_type == ATH_LED_RADIO) {
215
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
216
priv->op_flags |= OP_LED_ON;
226
static void ath9k_led_brightness(struct led_classdev *led_cdev,
227
enum led_brightness brightness)
229
struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
230
struct ath9k_htc_priv *priv = led->priv;
232
led->brightness = brightness;
233
if (!(priv->op_flags & OP_LED_DEINIT))
234
ieee80211_queue_delayed_work(priv->hw,
235
&led->brightness_work, 0);
238
void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
240
cancel_delayed_work_sync(&priv->radio_led.brightness_work);
241
cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
242
cancel_delayed_work_sync(&priv->tx_led.brightness_work);
243
cancel_delayed_work_sync(&priv->rx_led.brightness_work);
246
static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
252
led->led_cdev.name = led->name;
253
led->led_cdev.default_trigger = trigger;
254
led->led_cdev.brightness_set = ath9k_led_brightness;
256
ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
258
ath_err(ath9k_hw_common(priv->ah),
259
"Failed to register led:%s", led->name);
263
INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
268
static void ath9k_unregister_led(struct ath_led *led)
270
if (led->registered) {
271
led_classdev_unregister(&led->led_cdev);
276
void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
278
priv->op_flags |= OP_LED_DEINIT;
279
ath9k_unregister_led(&priv->assoc_led);
280
priv->op_flags &= ~OP_LED_ASSOCIATED;
281
ath9k_unregister_led(&priv->tx_led);
282
ath9k_unregister_led(&priv->rx_led);
283
ath9k_unregister_led(&priv->radio_led);
286
void ath9k_init_leds(struct ath9k_htc_priv *priv)
291
if (AR_SREV_9287(priv->ah))
292
priv->ah->led_pin = ATH_LED_PIN_9287;
293
else if (AR_SREV_9271(priv->ah))
294
priv->ah->led_pin = ATH_LED_PIN_9271;
295
else if (AR_DEVID_7010(priv->ah))
296
priv->ah->led_pin = ATH_LED_PIN_7010;
298
priv->ah->led_pin = ATH_LED_PIN_DEF;
300
/* Configure gpio 1 for output */
301
ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
302
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
303
/* LED off, active low */
304
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
306
INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
308
trigger = ieee80211_get_radio_led_name(priv->hw);
309
snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
310
"ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
311
ret = ath9k_register_led(priv, &priv->radio_led, trigger);
312
priv->radio_led.led_type = ATH_LED_RADIO;
316
trigger = ieee80211_get_assoc_led_name(priv->hw);
317
snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
318
"ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
319
ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
320
priv->assoc_led.led_type = ATH_LED_ASSOC;
324
trigger = ieee80211_get_tx_led_name(priv->hw);
325
snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
326
"ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
327
ret = ath9k_register_led(priv, &priv->tx_led, trigger);
328
priv->tx_led.led_type = ATH_LED_TX;
332
trigger = ieee80211_get_rx_led_name(priv->hw);
333
snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
334
"ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
335
ret = ath9k_register_led(priv, &priv->rx_led, trigger);
336
priv->rx_led.led_type = ATH_LED_RX;
340
priv->op_flags &= ~OP_LED_DEINIT;
345
cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
346
ath9k_deinit_leds(priv);
349
/*******************/
351
/*******************/
353
static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
355
return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
356
priv->ah->rfkill_polarity;
359
void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
361
struct ath9k_htc_priv *priv = hw->priv;
362
bool blocked = !!ath_is_rfkill_set(priv);
364
wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
367
void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
369
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
370
wiphy_rfkill_start_polling(priv->hw->wiphy);
373
void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
375
struct ath9k_htc_priv *priv = hw->priv;
376
struct ath_hw *ah = priv->ah;
377
struct ath_common *common = ath9k_hw_common(ah);
382
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
385
ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
388
"Unable to reset hardware; reset status %d (freq %u MHz)\n",
389
ret, ah->curchan->channel);
392
ath_update_txpow(priv);
395
WMI_CMD(WMI_START_RECV_CMDID);
396
ath9k_host_rx_init(priv);
399
htc_start(priv->htc);
400
spin_lock_bh(&priv->tx_lock);
401
priv->tx_queues_stop = false;
402
spin_unlock_bh(&priv->tx_lock);
403
ieee80211_wake_queues(hw);
405
WMI_CMD(WMI_ENABLE_INTR_CMDID);
408
ath9k_hw_cfg_output(ah, ah->led_pin,
409
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
410
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
413
void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
415
struct ath9k_htc_priv *priv = hw->priv;
416
struct ath_hw *ah = priv->ah;
417
struct ath_common *common = ath9k_hw_common(ah);
421
ath9k_htc_ps_wakeup(priv);
424
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
425
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
427
WMI_CMD(WMI_DISABLE_INTR_CMDID);
430
ieee80211_stop_queues(hw);
432
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
433
skb_queue_purge(&priv->tx_queue);
436
WMI_CMD(WMI_STOP_RECV_CMDID);
439
* The MIB counters have to be disabled here,
440
* since the target doesn't do it.
442
ath9k_hw_disable_mib_counters(ah);
445
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
448
ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
451
"Unable to reset hardware; reset status %d (freq %u MHz)\n",
452
ret, ah->curchan->channel);
455
/* Disable the PHY */
456
ath9k_hw_phy_disable(ah);
458
ath9k_htc_ps_restore(priv);
459
ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);