aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorSujith <Sujith.Manoharan@atheros.com>2010-01-08 00:06:00 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-12 13:57:59 -0500
commit0fca65c1c0569d6a143e978b6f4974c519033e63 (patch)
tree60878fa99e7af727ab4bf880992adebb830d21a5 /drivers/net/wireless/ath
parentcc5d8a3772ee4e2ed29558ba548b4747959ba971 (diff)
ath9k: Add a new file for GPIO
Move all LED/RFKILL/BTCOEX related code to gpio.c Signed-off-by: Sujith <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h15
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c428
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c406
4 files changed, 444 insertions, 406 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 4985b2b1b0a9..332d6f20c6b6 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -1,4 +1,5 @@
1ath9k-y += beacon.o \ 1ath9k-y += beacon.o \
2 gpio.o \
2 main.o \ 3 main.o \
3 recv.o \ 4 recv.o \
4 xmit.o \ 5 xmit.o \
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9efebac5ed0e..bbdca5edcfbf 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -341,6 +341,10 @@ int ath_beaconq_config(struct ath_softc *sc);
341#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ 341#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
342#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ 342#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
343 343
344/**********/
345/* BTCOEX */
346/**********/
347
344/* Defines the BT AR_BT_COEX_WGHT used */ 348/* Defines the BT AR_BT_COEX_WGHT used */
345enum ath_stomp_type { 349enum ath_stomp_type {
346 ATH_BTCOEX_NO_STOMP, 350 ATH_BTCOEX_NO_STOMP,
@@ -361,6 +365,10 @@ struct ath_btcoex {
361 struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ 365 struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
362}; 366};
363 367
368int ath_init_btcoex_timer(struct ath_softc *sc);
369void ath9k_btcoex_timer_resume(struct ath_softc *sc);
370void ath9k_btcoex_timer_pause(struct ath_softc *sc);
371
364/********************/ 372/********************/
365/* LED Control */ 373/* LED Control */
366/********************/ 374/********************/
@@ -385,6 +393,9 @@ struct ath_led {
385 bool registered; 393 bool registered;
386}; 394};
387 395
396void ath_init_leds(struct ath_softc *sc);
397void ath_deinit_leds(struct ath_softc *sc);
398
388/********************/ 399/********************/
389/* Main driver core */ 400/* Main driver core */
390/********************/ 401/********************/
@@ -582,4 +593,8 @@ void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
582void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); 593void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
583 594
584int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); 595int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
596
597void ath_start_rfkill_poll(struct ath_softc *sc);
598extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
599
585#endif /* ATH9K_H */ 600#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
new file mode 100644
index 000000000000..e204bd25ff65
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -0,0 +1,428 @@
1/*
2 * Copyright (c) 2008-2009 Atheros Communications Inc.
3 *
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.
7 *
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.
15 */
16
17#include "ath9k.h"
18
19/********************************/
20/* LED functions */
21/********************************/
22
23static void ath_led_blink_work(struct work_struct *work)
24{
25 struct ath_softc *sc = container_of(work, struct ath_softc,
26 ath_led_blink_work.work);
27
28 if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
29 return;
30
31 if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
32 (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
33 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
34 else
35 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
36 (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
37
38 ieee80211_queue_delayed_work(sc->hw,
39 &sc->ath_led_blink_work,
40 (sc->sc_flags & SC_OP_LED_ON) ?
41 msecs_to_jiffies(sc->led_off_duration) :
42 msecs_to_jiffies(sc->led_on_duration));
43
44 sc->led_on_duration = sc->led_on_cnt ?
45 max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
46 ATH_LED_ON_DURATION_IDLE;
47 sc->led_off_duration = sc->led_off_cnt ?
48 max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
49 ATH_LED_OFF_DURATION_IDLE;
50 sc->led_on_cnt = sc->led_off_cnt = 0;
51 if (sc->sc_flags & SC_OP_LED_ON)
52 sc->sc_flags &= ~SC_OP_LED_ON;
53 else
54 sc->sc_flags |= SC_OP_LED_ON;
55}
56
57static void ath_led_brightness(struct led_classdev *led_cdev,
58 enum led_brightness brightness)
59{
60 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
61 struct ath_softc *sc = led->sc;
62
63 switch (brightness) {
64 case LED_OFF:
65 if (led->led_type == ATH_LED_ASSOC ||
66 led->led_type == ATH_LED_RADIO) {
67 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
68 (led->led_type == ATH_LED_RADIO));
69 sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
70 if (led->led_type == ATH_LED_RADIO)
71 sc->sc_flags &= ~SC_OP_LED_ON;
72 } else {
73 sc->led_off_cnt++;
74 }
75 break;
76 case LED_FULL:
77 if (led->led_type == ATH_LED_ASSOC) {
78 sc->sc_flags |= SC_OP_LED_ASSOCIATED;
79 ieee80211_queue_delayed_work(sc->hw,
80 &sc->ath_led_blink_work, 0);
81 } else if (led->led_type == ATH_LED_RADIO) {
82 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
83 sc->sc_flags |= SC_OP_LED_ON;
84 } else {
85 sc->led_on_cnt++;
86 }
87 break;
88 default:
89 break;
90 }
91}
92
93static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
94 char *trigger)
95{
96 int ret;
97
98 led->sc = sc;
99 led->led_cdev.name = led->name;
100 led->led_cdev.default_trigger = trigger;
101 led->led_cdev.brightness_set = ath_led_brightness;
102
103 ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
104 if (ret)
105 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
106 "Failed to register led:%s", led->name);
107 else
108 led->registered = 1;
109 return ret;
110}
111
112static void ath_unregister_led(struct ath_led *led)
113{
114 if (led->registered) {
115 led_classdev_unregister(&led->led_cdev);
116 led->registered = 0;
117 }
118}
119
120void ath_deinit_leds(struct ath_softc *sc)
121{
122 ath_unregister_led(&sc->assoc_led);
123 sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
124 ath_unregister_led(&sc->tx_led);
125 ath_unregister_led(&sc->rx_led);
126 ath_unregister_led(&sc->radio_led);
127 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
128}
129
130void ath_init_leds(struct ath_softc *sc)
131{
132 char *trigger;
133 int ret;
134
135 if (AR_SREV_9287(sc->sc_ah))
136 sc->sc_ah->led_pin = ATH_LED_PIN_9287;
137 else
138 sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
139
140 /* Configure gpio 1 for output */
141 ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
142 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
143 /* LED off, active low */
144 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
145
146 INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
147
148 trigger = ieee80211_get_radio_led_name(sc->hw);
149 snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
150 "ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
151 ret = ath_register_led(sc, &sc->radio_led, trigger);
152 sc->radio_led.led_type = ATH_LED_RADIO;
153 if (ret)
154 goto fail;
155
156 trigger = ieee80211_get_assoc_led_name(sc->hw);
157 snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
158 "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
159 ret = ath_register_led(sc, &sc->assoc_led, trigger);
160 sc->assoc_led.led_type = ATH_LED_ASSOC;
161 if (ret)
162 goto fail;
163
164 trigger = ieee80211_get_tx_led_name(sc->hw);
165 snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
166 "ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
167 ret = ath_register_led(sc, &sc->tx_led, trigger);
168 sc->tx_led.led_type = ATH_LED_TX;
169 if (ret)
170 goto fail;
171
172 trigger = ieee80211_get_rx_led_name(sc->hw);
173 snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
174 "ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
175 ret = ath_register_led(sc, &sc->rx_led, trigger);
176 sc->rx_led.led_type = ATH_LED_RX;
177 if (ret)
178 goto fail;
179
180 return;
181
182fail:
183 cancel_delayed_work_sync(&sc->ath_led_blink_work);
184 ath_deinit_leds(sc);
185}
186
187/*******************/
188/* Rfkill */
189/*******************/
190
191static bool ath_is_rfkill_set(struct ath_softc *sc)
192{
193 struct ath_hw *ah = sc->sc_ah;
194
195 return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
196 ah->rfkill_polarity;
197}
198
199void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
200{
201 struct ath_wiphy *aphy = hw->priv;
202 struct ath_softc *sc = aphy->sc;
203 bool blocked = !!ath_is_rfkill_set(sc);
204
205 wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
206}
207
208void ath_start_rfkill_poll(struct ath_softc *sc)
209{
210 struct ath_hw *ah = sc->sc_ah;
211
212 if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
213 wiphy_rfkill_start_polling(sc->hw->wiphy);
214}
215
216/******************/
217/* BTCOEX */
218/******************/
219
220/*
221 * Detects if there is any priority bt traffic
222 */
223static void ath_detect_bt_priority(struct ath_softc *sc)
224{
225 struct ath_btcoex *btcoex = &sc->btcoex;
226 struct ath_hw *ah = sc->sc_ah;
227
228 if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio))
229 btcoex->bt_priority_cnt++;
230
231 if (time_after(jiffies, btcoex->bt_priority_time +
232 msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
233 if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
234 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
235 "BT priority traffic detected");
236 sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
237 } else {
238 sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
239 }
240
241 btcoex->bt_priority_cnt = 0;
242 btcoex->bt_priority_time = jiffies;
243 }
244}
245
246/*
247 * Configures appropriate weight based on stomp type.
248 */
249static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
250 enum ath_stomp_type stomp_type)
251{
252 struct ath_hw *ah = sc->sc_ah;
253
254 switch (stomp_type) {
255 case ATH_BTCOEX_STOMP_ALL:
256 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
257 AR_STOMP_ALL_WLAN_WGHT);
258 break;
259 case ATH_BTCOEX_STOMP_LOW:
260 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
261 AR_STOMP_LOW_WLAN_WGHT);
262 break;
263 case ATH_BTCOEX_STOMP_NONE:
264 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
265 AR_STOMP_NONE_WLAN_WGHT);
266 break;
267 default:
268 ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
269 "Invalid Stomptype\n");
270 break;
271 }
272
273 ath9k_hw_btcoex_enable(ah);
274}
275
276static void ath9k_gen_timer_start(struct ath_hw *ah,
277 struct ath_gen_timer *timer,
278 u32 timer_next,
279 u32 timer_period)
280{
281 struct ath_common *common = ath9k_hw_common(ah);
282 struct ath_softc *sc = (struct ath_softc *) common->priv;
283
284 ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
285
286 if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
287 ath9k_hw_set_interrupts(ah, 0);
288 sc->imask |= ATH9K_INT_GENTIMER;
289 ath9k_hw_set_interrupts(ah, sc->imask);
290 }
291}
292
293static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
294{
295 struct ath_common *common = ath9k_hw_common(ah);
296 struct ath_softc *sc = (struct ath_softc *) common->priv;
297 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
298
299 ath9k_hw_gen_timer_stop(ah, timer);
300
301 /* if no timer is enabled, turn off interrupt mask */
302 if (timer_table->timer_mask.val == 0) {
303 ath9k_hw_set_interrupts(ah, 0);
304 sc->imask &= ~ATH9K_INT_GENTIMER;
305 ath9k_hw_set_interrupts(ah, sc->imask);
306 }
307}
308
309/*
310 * This is the master bt coex timer which runs for every
311 * 45ms, bt traffic will be given priority during 55% of this
312 * period while wlan gets remaining 45%
313 */
314static void ath_btcoex_period_timer(unsigned long data)
315{
316 struct ath_softc *sc = (struct ath_softc *) data;
317 struct ath_hw *ah = sc->sc_ah;
318 struct ath_btcoex *btcoex = &sc->btcoex;
319
320 ath_detect_bt_priority(sc);
321
322 spin_lock_bh(&btcoex->btcoex_lock);
323
324 ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
325
326 spin_unlock_bh(&btcoex->btcoex_lock);
327
328 if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
329 if (btcoex->hw_timer_enabled)
330 ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
331
332 ath9k_gen_timer_start(ah,
333 btcoex->no_stomp_timer,
334 (ath9k_hw_gettsf32(ah) +
335 btcoex->btcoex_no_stomp),
336 btcoex->btcoex_no_stomp * 10);
337 btcoex->hw_timer_enabled = true;
338 }
339
340 mod_timer(&btcoex->period_timer, jiffies +
341 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
342}
343
344/*
345 * Generic tsf based hw timer which configures weight
346 * registers to time slice between wlan and bt traffic
347 */
348static void ath_btcoex_no_stomp_timer(void *arg)
349{
350 struct ath_softc *sc = (struct ath_softc *)arg;
351 struct ath_hw *ah = sc->sc_ah;
352 struct ath_btcoex *btcoex = &sc->btcoex;
353
354 ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
355 "no stomp timer running \n");
356
357 spin_lock_bh(&btcoex->btcoex_lock);
358
359 if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
360 ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
361 else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
362 ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
363
364 spin_unlock_bh(&btcoex->btcoex_lock);
365}
366
367int ath_init_btcoex_timer(struct ath_softc *sc)
368{
369 struct ath_btcoex *btcoex = &sc->btcoex;
370
371 btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
372 btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
373 btcoex->btcoex_period / 100;
374
375 setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
376 (unsigned long) sc);
377
378 spin_lock_init(&btcoex->btcoex_lock);
379
380 btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
381 ath_btcoex_no_stomp_timer,
382 ath_btcoex_no_stomp_timer,
383 (void *) sc, AR_FIRST_NDP_TIMER);
384
385 if (!btcoex->no_stomp_timer)
386 return -ENOMEM;
387
388 return 0;
389}
390
391/*
392 * (Re)start btcoex timers
393 */
394void ath9k_btcoex_timer_resume(struct ath_softc *sc)
395{
396 struct ath_btcoex *btcoex = &sc->btcoex;
397 struct ath_hw *ah = sc->sc_ah;
398
399 ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
400 "Starting btcoex timers");
401
402 /* make sure duty cycle timer is also stopped when resuming */
403 if (btcoex->hw_timer_enabled)
404 ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
405
406 btcoex->bt_priority_cnt = 0;
407 btcoex->bt_priority_time = jiffies;
408 sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
409
410 mod_timer(&btcoex->period_timer, jiffies);
411}
412
413
414/*
415 * Pause btcoex timer and bt duty cycle timer
416 */
417void ath9k_btcoex_timer_pause(struct ath_softc *sc)
418{
419 struct ath_btcoex *btcoex = &sc->btcoex;
420 struct ath_hw *ah = sc->sc_ah;
421
422 del_timer_sync(&btcoex->period_timer);
423
424 if (btcoex->hw_timer_enabled)
425 ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
426
427 btcoex->hw_timer_enabled = false;
428}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 3777b8449789..31a33cf762da 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1000,174 +1000,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
1000 } 1000 }
1001} 1001}
1002 1002
1003/********************************/
1004/* LED functions */
1005/********************************/
1006
1007static void ath_led_blink_work(struct work_struct *work)
1008{
1009 struct ath_softc *sc = container_of(work, struct ath_softc,
1010 ath_led_blink_work.work);
1011
1012 if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
1013 return;
1014
1015 if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
1016 (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
1017 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
1018 else
1019 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
1020 (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
1021
1022 ieee80211_queue_delayed_work(sc->hw,
1023 &sc->ath_led_blink_work,
1024 (sc->sc_flags & SC_OP_LED_ON) ?
1025 msecs_to_jiffies(sc->led_off_duration) :
1026 msecs_to_jiffies(sc->led_on_duration));
1027
1028 sc->led_on_duration = sc->led_on_cnt ?
1029 max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
1030 ATH_LED_ON_DURATION_IDLE;
1031 sc->led_off_duration = sc->led_off_cnt ?
1032 max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
1033 ATH_LED_OFF_DURATION_IDLE;
1034 sc->led_on_cnt = sc->led_off_cnt = 0;
1035 if (sc->sc_flags & SC_OP_LED_ON)
1036 sc->sc_flags &= ~SC_OP_LED_ON;
1037 else
1038 sc->sc_flags |= SC_OP_LED_ON;
1039}
1040
1041static void ath_led_brightness(struct led_classdev *led_cdev,
1042 enum led_brightness brightness)
1043{
1044 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
1045 struct ath_softc *sc = led->sc;
1046
1047 switch (brightness) {
1048 case LED_OFF:
1049 if (led->led_type == ATH_LED_ASSOC ||
1050 led->led_type == ATH_LED_RADIO) {
1051 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
1052 (led->led_type == ATH_LED_RADIO));
1053 sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
1054 if (led->led_type == ATH_LED_RADIO)
1055 sc->sc_flags &= ~SC_OP_LED_ON;
1056 } else {
1057 sc->led_off_cnt++;
1058 }
1059 break;
1060 case LED_FULL:
1061 if (led->led_type == ATH_LED_ASSOC) {
1062 sc->sc_flags |= SC_OP_LED_ASSOCIATED;
1063 ieee80211_queue_delayed_work(sc->hw,
1064 &sc->ath_led_blink_work, 0);
1065 } else if (led->led_type == ATH_LED_RADIO) {
1066 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
1067 sc->sc_flags |= SC_OP_LED_ON;
1068 } else {
1069 sc->led_on_cnt++;
1070 }
1071 break;
1072 default:
1073 break;
1074 }
1075}
1076
1077static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
1078 char *trigger)
1079{
1080 int ret;
1081
1082 led->sc = sc;
1083 led->led_cdev.name = led->name;
1084 led->led_cdev.default_trigger = trigger;
1085 led->led_cdev.brightness_set = ath_led_brightness;
1086
1087 ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
1088 if (ret)
1089 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1090 "Failed to register led:%s", led->name);
1091 else
1092 led->registered = 1;
1093 return ret;
1094}
1095
1096static void ath_unregister_led(struct ath_led *led)
1097{
1098 if (led->registered) {
1099 led_classdev_unregister(&led->led_cdev);
1100 led->registered = 0;
1101 }
1102}
1103
1104static void ath_deinit_leds(struct ath_softc *sc)
1105{
1106 ath_unregister_led(&sc->assoc_led);
1107 sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
1108 ath_unregister_led(&sc->tx_led);
1109 ath_unregister_led(&sc->rx_led);
1110 ath_unregister_led(&sc->radio_led);
1111 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
1112}
1113
1114static void ath_init_leds(struct ath_softc *sc)
1115{
1116 char *trigger;
1117 int ret;
1118
1119 if (AR_SREV_9287(sc->sc_ah))
1120 sc->sc_ah->led_pin = ATH_LED_PIN_9287;
1121 else
1122 sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
1123
1124 /* Configure gpio 1 for output */
1125 ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
1126 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1127 /* LED off, active low */
1128 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
1129
1130 INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
1131
1132 trigger = ieee80211_get_radio_led_name(sc->hw);
1133 snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
1134 "ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
1135 ret = ath_register_led(sc, &sc->radio_led, trigger);
1136 sc->radio_led.led_type = ATH_LED_RADIO;
1137 if (ret)
1138 goto fail;
1139
1140 trigger = ieee80211_get_assoc_led_name(sc->hw);
1141 snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
1142 "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
1143 ret = ath_register_led(sc, &sc->assoc_led, trigger);
1144 sc->assoc_led.led_type = ATH_LED_ASSOC;
1145 if (ret)
1146 goto fail;
1147
1148 trigger = ieee80211_get_tx_led_name(sc->hw);
1149 snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
1150 "ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
1151 ret = ath_register_led(sc, &sc->tx_led, trigger);
1152 sc->tx_led.led_type = ATH_LED_TX;
1153 if (ret)
1154 goto fail;
1155
1156 trigger = ieee80211_get_rx_led_name(sc->hw);
1157 snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
1158 "ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
1159 ret = ath_register_led(sc, &sc->rx_led, trigger);
1160 sc->rx_led.led_type = ATH_LED_RX;
1161 if (ret)
1162 goto fail;
1163
1164 return;
1165
1166fail:
1167 cancel_delayed_work_sync(&sc->ath_led_blink_work);
1168 ath_deinit_leds(sc);
1169}
1170
1171void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) 1003void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
1172{ 1004{
1173 struct ath_hw *ah = sc->sc_ah; 1005 struct ath_hw *ah = sc->sc_ah;
@@ -1252,35 +1084,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
1252 ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); 1084 ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
1253} 1085}
1254 1086
1255/*******************/
1256/* Rfkill */
1257/*******************/
1258
1259static bool ath_is_rfkill_set(struct ath_softc *sc)
1260{
1261 struct ath_hw *ah = sc->sc_ah;
1262
1263 return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
1264 ah->rfkill_polarity;
1265}
1266
1267static void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
1268{
1269 struct ath_wiphy *aphy = hw->priv;
1270 struct ath_softc *sc = aphy->sc;
1271 bool blocked = !!ath_is_rfkill_set(sc);
1272
1273 wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
1274}
1275
1276static void ath_start_rfkill_poll(struct ath_softc *sc)
1277{
1278 struct ath_hw *ah = sc->sc_ah;
1279
1280 if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
1281 wiphy_rfkill_start_polling(sc->hw->wiphy);
1282}
1283
1284static void ath9k_uninit_hw(struct ath_softc *sc) 1087static void ath9k_uninit_hw(struct ath_softc *sc)
1285{ 1088{
1286 struct ath_hw *ah = sc->sc_ah; 1089 struct ath_hw *ah = sc->sc_ah;
@@ -1365,177 +1168,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
1365} 1168}
1366 1169
1367/* 1170/*
1368 * Detects if there is any priority bt traffic
1369 */
1370static void ath_detect_bt_priority(struct ath_softc *sc)
1371{
1372 struct ath_btcoex *btcoex = &sc->btcoex;
1373 struct ath_hw *ah = sc->sc_ah;
1374
1375 if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio))
1376 btcoex->bt_priority_cnt++;
1377
1378 if (time_after(jiffies, btcoex->bt_priority_time +
1379 msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
1380 if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
1381 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
1382 "BT priority traffic detected");
1383 sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
1384 } else {
1385 sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
1386 }
1387
1388 btcoex->bt_priority_cnt = 0;
1389 btcoex->bt_priority_time = jiffies;
1390 }
1391}
1392
1393/*
1394 * Configures appropriate weight based on stomp type.
1395 */
1396static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
1397 enum ath_stomp_type stomp_type)
1398{
1399 struct ath_hw *ah = sc->sc_ah;
1400
1401 switch (stomp_type) {
1402 case ATH_BTCOEX_STOMP_ALL:
1403 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
1404 AR_STOMP_ALL_WLAN_WGHT);
1405 break;
1406 case ATH_BTCOEX_STOMP_LOW:
1407 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
1408 AR_STOMP_LOW_WLAN_WGHT);
1409 break;
1410 case ATH_BTCOEX_STOMP_NONE:
1411 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
1412 AR_STOMP_NONE_WLAN_WGHT);
1413 break;
1414 default:
1415 ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
1416 "Invalid Stomptype\n");
1417 break;
1418 }
1419
1420 ath9k_hw_btcoex_enable(ah);
1421}
1422
1423static void ath9k_gen_timer_start(struct ath_hw *ah,
1424 struct ath_gen_timer *timer,
1425 u32 timer_next,
1426 u32 timer_period)
1427{
1428 struct ath_common *common = ath9k_hw_common(ah);
1429 struct ath_softc *sc = (struct ath_softc *) common->priv;
1430
1431 ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
1432
1433 if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
1434 ath9k_hw_set_interrupts(ah, 0);
1435 sc->imask |= ATH9K_INT_GENTIMER;
1436 ath9k_hw_set_interrupts(ah, sc->imask);
1437 }
1438}
1439
1440static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
1441{
1442 struct ath_common *common = ath9k_hw_common(ah);
1443 struct ath_softc *sc = (struct ath_softc *) common->priv;
1444 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
1445
1446 ath9k_hw_gen_timer_stop(ah, timer);
1447
1448 /* if no timer is enabled, turn off interrupt mask */
1449 if (timer_table->timer_mask.val == 0) {
1450 ath9k_hw_set_interrupts(ah, 0);
1451 sc->imask &= ~ATH9K_INT_GENTIMER;
1452 ath9k_hw_set_interrupts(ah, sc->imask);
1453 }
1454}
1455
1456/*
1457 * This is the master bt coex timer which runs for every
1458 * 45ms, bt traffic will be given priority during 55% of this
1459 * period while wlan gets remaining 45%
1460 */
1461static void ath_btcoex_period_timer(unsigned long data)
1462{
1463 struct ath_softc *sc = (struct ath_softc *) data;
1464 struct ath_hw *ah = sc->sc_ah;
1465 struct ath_btcoex *btcoex = &sc->btcoex;
1466
1467 ath_detect_bt_priority(sc);
1468
1469 spin_lock_bh(&btcoex->btcoex_lock);
1470
1471 ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
1472
1473 spin_unlock_bh(&btcoex->btcoex_lock);
1474
1475 if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
1476 if (btcoex->hw_timer_enabled)
1477 ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
1478
1479 ath9k_gen_timer_start(ah,
1480 btcoex->no_stomp_timer,
1481 (ath9k_hw_gettsf32(ah) +
1482 btcoex->btcoex_no_stomp),
1483 btcoex->btcoex_no_stomp * 10);
1484 btcoex->hw_timer_enabled = true;
1485 }
1486
1487 mod_timer(&btcoex->period_timer, jiffies +
1488 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
1489}
1490
1491/*
1492 * Generic tsf based hw timer which configures weight
1493 * registers to time slice between wlan and bt traffic
1494 */
1495static void ath_btcoex_no_stomp_timer(void *arg)
1496{
1497 struct ath_softc *sc = (struct ath_softc *)arg;
1498 struct ath_hw *ah = sc->sc_ah;
1499 struct ath_btcoex *btcoex = &sc->btcoex;
1500
1501 ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
1502 "no stomp timer running \n");
1503
1504 spin_lock_bh(&btcoex->btcoex_lock);
1505
1506 if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
1507 ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
1508 else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
1509 ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
1510
1511 spin_unlock_bh(&btcoex->btcoex_lock);
1512}
1513
1514static int ath_init_btcoex_timer(struct ath_softc *sc)
1515{
1516 struct ath_btcoex *btcoex = &sc->btcoex;
1517
1518 btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
1519 btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
1520 btcoex->btcoex_period / 100;
1521
1522 setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
1523 (unsigned long) sc);
1524
1525 spin_lock_init(&btcoex->btcoex_lock);
1526
1527 btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
1528 ath_btcoex_no_stomp_timer,
1529 ath_btcoex_no_stomp_timer,
1530 (void *) sc, AR_FIRST_NDP_TIMER);
1531
1532 if (!btcoex->no_stomp_timer)
1533 return -ENOMEM;
1534
1535 return 0;
1536}
1537
1538/*
1539 * Read and write, they both share the same lock. We do this to serialize 1171 * Read and write, they both share the same lock. We do this to serialize
1540 * reads and writes on Atheros 802.11n PCI devices only. This is required 1172 * reads and writes on Atheros 802.11n PCI devices only. This is required
1541 * as the FIFO on these devices can only accept sanely 2 requests. After 1173 * as the FIFO on these devices can only accept sanely 2 requests. After
@@ -2213,28 +1845,6 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
2213/* mac80211 callbacks */ 1845/* mac80211 callbacks */
2214/**********************/ 1846/**********************/
2215 1847
2216/*
2217 * (Re)start btcoex timers
2218 */
2219static void ath9k_btcoex_timer_resume(struct ath_softc *sc)
2220{
2221 struct ath_btcoex *btcoex = &sc->btcoex;
2222 struct ath_hw *ah = sc->sc_ah;
2223
2224 ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
2225 "Starting btcoex timers");
2226
2227 /* make sure duty cycle timer is also stopped when resuming */
2228 if (btcoex->hw_timer_enabled)
2229 ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
2230
2231 btcoex->bt_priority_cnt = 0;
2232 btcoex->bt_priority_time = jiffies;
2233 sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
2234
2235 mod_timer(&btcoex->period_timer, jiffies);
2236}
2237
2238static int ath9k_start(struct ieee80211_hw *hw) 1848static int ath9k_start(struct ieee80211_hw *hw)
2239{ 1849{
2240 struct ath_wiphy *aphy = hw->priv; 1850 struct ath_wiphy *aphy = hw->priv;
@@ -2461,22 +2071,6 @@ exit:
2461 return 0; 2071 return 0;
2462} 2072}
2463 2073
2464/*
2465 * Pause btcoex timer and bt duty cycle timer
2466 */
2467static void ath9k_btcoex_timer_pause(struct ath_softc *sc)
2468{
2469 struct ath_btcoex *btcoex = &sc->btcoex;
2470 struct ath_hw *ah = sc->sc_ah;
2471
2472 del_timer_sync(&btcoex->period_timer);
2473
2474 if (btcoex->hw_timer_enabled)
2475 ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
2476
2477 btcoex->hw_timer_enabled = false;
2478}
2479
2480static void ath9k_stop(struct ieee80211_hw *hw) 2074static void ath9k_stop(struct ieee80211_hw *hw)
2481{ 2075{
2482 struct ath_wiphy *aphy = hw->priv; 2076 struct ath_wiphy *aphy = hw->priv;