Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / drivers / net / wireless / ath / ath9k / gpio.c
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
23 #ifdef CONFIG_MAC80211_LEDS
24 static void ath_led_brightness(struct led_classdev *led_cdev,
25                                enum led_brightness brightness)
26 {
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));
29 }
30
31 void ath_deinit_leds(struct ath_softc *sc)
32 {
33         if (!sc->led_registered)
34                 return;
35
36         ath_led_brightness(&sc->led_cdev, LED_OFF);
37         led_classdev_unregister(&sc->led_cdev);
38 }
39
40 void ath_init_leds(struct ath_softc *sc)
41 {
42         int ret;
43
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;
48         else
49                 sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
50
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);
56
57         if (!led_blink)
58                 sc->led_cdev.default_trigger =
59                         ieee80211_get_radio_led_name(sc->hw);
60
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;
65
66         ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
67         if (ret < 0)
68                 return;
69
70         sc->led_registered = true;
71 }
72 #endif
73
74 /*******************/
75 /*      Rfkill     */
76 /*******************/
77
78 static bool ath_is_rfkill_set(struct ath_softc *sc)
79 {
80         struct ath_hw *ah = sc->sc_ah;
81
82         return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
83                                   ah->rfkill_polarity;
84 }
85
86 void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
87 {
88         struct ath_softc *sc = hw->priv;
89         bool blocked = !!ath_is_rfkill_set(sc);
90
91         wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
92 }
93
94 void ath_start_rfkill_poll(struct ath_softc *sc)
95 {
96         struct ath_hw *ah = sc->sc_ah;
97
98         if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
99                 wiphy_rfkill_start_polling(sc->hw->wiphy);
100 }
101
102 /******************/
103 /*     BTCOEX     */
104 /******************/
105
106 /*
107  * Detects if there is any priority bt traffic
108  */
109 static void ath_detect_bt_priority(struct ath_softc *sc)
110 {
111         struct ath_btcoex *btcoex = &sc->btcoex;
112         struct ath_hw *ah = sc->sc_ah;
113
114         if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio))
115                 btcoex->bt_priority_cnt++;
116
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;
130                 }
131
132                 btcoex->bt_priority_cnt = 0;
133                 btcoex->bt_priority_time = jiffies;
134         }
135 }
136
137 static void ath9k_gen_timer_start(struct ath_hw *ah,
138                                   struct ath_gen_timer *timer,
139                                   u32 timer_next,
140                                   u32 timer_period)
141 {
142         ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
143
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);
148         }
149 }
150
151 static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
152 {
153         struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
154
155         ath9k_hw_gen_timer_stop(ah, timer);
156
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);
162         }
163 }
164
165 /*
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%
169  */
170 static void ath_btcoex_period_timer(unsigned long data)
171 {
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);
176         u32 timer_period;
177         bool is_btscan;
178
179         ath_detect_bt_priority(sc);
180
181         is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
182
183         spin_lock_bh(&btcoex->btcoex_lock);
184
185         ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
186                               btcoex->bt_stomp_type);
187
188         spin_unlock_bh(&btcoex->btcoex_lock);
189
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);
193
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,
197                                       timer_period * 10);
198                 btcoex->hw_timer_enabled = true;
199         }
200
201         mod_timer(&btcoex->period_timer, jiffies +
202                                   msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
203 }
204
205 /*
206  * Generic tsf based hw timer which configures weight
207  * registers to time slice between wlan and bt traffic
208  */
209 static void ath_btcoex_no_stomp_timer(void *arg)
210 {
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;
216
217         ath_dbg(common, ATH_DBG_BTCOEX,
218                 "no stomp timer running\n");
219
220         spin_lock_bh(&btcoex->btcoex_lock);
221
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);
226
227         spin_unlock_bh(&btcoex->btcoex_lock);
228 }
229
230 int ath_init_btcoex_timer(struct ath_softc *sc)
231 {
232         struct ath_btcoex *btcoex = &sc->btcoex;
233
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;
239
240         setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
241                         (unsigned long) sc);
242
243         spin_lock_init(&btcoex->btcoex_lock);
244
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);
249
250         if (!btcoex->no_stomp_timer)
251                 return -ENOMEM;
252
253         return 0;
254 }
255
256 /*
257  * (Re)start btcoex timers
258  */
259 void ath9k_btcoex_timer_resume(struct ath_softc *sc)
260 {
261         struct ath_btcoex *btcoex = &sc->btcoex;
262         struct ath_hw *ah = sc->sc_ah;
263
264         ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
265                 "Starting btcoex timers\n");
266
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);
270
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);
274
275         mod_timer(&btcoex->period_timer, jiffies);
276 }
277
278
279 /*
280  * Pause btcoex timer and bt duty cycle timer
281  */
282 void ath9k_btcoex_timer_pause(struct ath_softc *sc)
283 {
284         struct ath_btcoex *btcoex = &sc->btcoex;
285         struct ath_hw *ah = sc->sc_ah;
286
287         del_timer_sync(&btcoex->period_timer);
288
289         if (btcoex->hw_timer_enabled)
290                 ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
291
292         btcoex->hw_timer_enabled = false;
293 }