~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/net/wireless/ath/ath9k/htc_drv_gpio.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2010 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 "htc.h"
 
18
 
 
19
/******************/
 
20
/*     BTCOEX     */
 
21
/******************/
 
22
 
 
23
/*
 
24
 * Detects if there is any priority bt traffic
 
25
 */
 
26
static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
 
27
{
 
28
        struct ath_btcoex *btcoex = &priv->btcoex;
 
29
        struct ath_hw *ah = priv->ah;
 
30
 
 
31
        if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio))
 
32
                btcoex->bt_priority_cnt++;
 
33
 
 
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;
 
47
                }
 
48
 
 
49
                btcoex->bt_priority_cnt = 0;
 
50
                btcoex->bt_priority_time = jiffies;
 
51
        }
 
52
}
 
53
 
 
54
/*
 
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%
 
58
 */
 
59
static void ath_btcoex_period_work(struct work_struct *work)
 
60
{
 
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);
 
65
        u32 timer_period;
 
66
        bool is_btscan;
 
67
        int ret;
 
68
        u8 cmd_rsp, aggr;
 
69
 
 
70
        ath_detect_bt_priority(priv);
 
71
 
 
72
        is_btscan = !!(priv->op_flags & OP_BT_SCAN);
 
73
 
 
74
        aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
 
75
 
 
76
        WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
 
77
 
 
78
        ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
 
79
                        btcoex->bt_stomp_type);
 
80
 
 
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));
 
87
}
 
88
 
 
89
/*
 
90
 * Work to time slice between wlan and bt traffic and
 
91
 * configure weight registers
 
92
 */
 
93
static void ath_btcoex_duty_cycle_work(struct work_struct *work)
 
94
{
 
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;
 
101
 
 
102
        ath_dbg(common, ATH_DBG_BTCOEX,
 
103
                "time slice work for bt and wlan\n");
 
104
 
 
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);
 
109
}
 
110
 
 
111
void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
 
112
{
 
113
        struct ath_btcoex *btcoex = &priv->btcoex;
 
114
 
 
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);
 
122
}
 
123
 
 
124
/*
 
125
 * (Re)start btcoex work
 
126
 */
 
127
 
 
128
void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
 
129
{
 
130
        struct ath_btcoex *btcoex = &priv->btcoex;
 
131
        struct ath_hw *ah = priv->ah;
 
132
 
 
133
        ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Starting btcoex work\n");
 
134
 
 
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);
 
139
}
 
140
 
 
141
 
 
142
/*
 
143
 * Cancel btcoex and bt duty cycle work.
 
144
 */
 
145
void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
 
146
{
 
147
        cancel_delayed_work_sync(&priv->coex_period_work);
 
148
        cancel_delayed_work_sync(&priv->duty_cycle_work);
 
149
}
 
150
 
 
151
/*******/
 
152
/* LED */
 
153
/*******/
 
154
 
 
155
static void ath9k_led_blink_work(struct work_struct *work)
 
156
{
 
157
        struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
 
158
                                                   ath9k_led_blink_work.work);
 
159
 
 
160
        if (!(priv->op_flags & OP_LED_ASSOCIATED))
 
161
                return;
 
162
 
 
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);
 
166
        else
 
167
                ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
 
168
                                  (priv->op_flags & OP_LED_ON) ? 1 : 0);
 
169
 
 
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));
 
175
 
 
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;
 
183
 
 
184
        if (priv->op_flags & OP_LED_ON)
 
185
                priv->op_flags &= ~OP_LED_ON;
 
186
        else
 
187
                priv->op_flags |= OP_LED_ON;
 
188
}
 
189
 
 
190
static void ath9k_led_brightness_work(struct work_struct *work)
 
191
{
 
192
        struct ath_led *led = container_of(work, struct ath_led,
 
193
                                           brightness_work.work);
 
194
        struct ath9k_htc_priv *priv = led->priv;
 
195
 
 
196
        switch (led->brightness) {
 
197
        case LED_OFF:
 
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;
 
205
                } else {
 
206
                        priv->led_off_cnt++;
 
207
                }
 
208
                break;
 
209
        case LED_FULL:
 
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;
 
217
                } else {
 
218
                        priv->led_on_cnt++;
 
219
                }
 
220
                break;
 
221
        default:
 
222
                break;
 
223
        }
 
224
}
 
225
 
 
226
static void ath9k_led_brightness(struct led_classdev *led_cdev,
 
227
                                 enum led_brightness brightness)
 
228
{
 
229
        struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
 
230
        struct ath9k_htc_priv *priv = led->priv;
 
231
 
 
232
        led->brightness = brightness;
 
233
        if (!(priv->op_flags & OP_LED_DEINIT))
 
234
                ieee80211_queue_delayed_work(priv->hw,
 
235
                                             &led->brightness_work, 0);
 
236
}
 
237
 
 
238
void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
 
239
{
 
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);
 
244
}
 
245
 
 
246
static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
 
247
                              char *trigger)
 
248
{
 
249
        int ret;
 
250
 
 
251
        led->priv = priv;
 
252
        led->led_cdev.name = led->name;
 
253
        led->led_cdev.default_trigger = trigger;
 
254
        led->led_cdev.brightness_set = ath9k_led_brightness;
 
255
 
 
256
        ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
 
257
        if (ret)
 
258
                ath_err(ath9k_hw_common(priv->ah),
 
259
                        "Failed to register led:%s", led->name);
 
260
        else
 
261
                led->registered = 1;
 
262
 
 
263
        INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
 
264
 
 
265
        return ret;
 
266
}
 
267
 
 
268
static void ath9k_unregister_led(struct ath_led *led)
 
269
{
 
270
        if (led->registered) {
 
271
                led_classdev_unregister(&led->led_cdev);
 
272
                led->registered = 0;
 
273
        }
 
274
}
 
275
 
 
276
void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
 
277
{
 
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);
 
284
}
 
285
 
 
286
void ath9k_init_leds(struct ath9k_htc_priv *priv)
 
287
{
 
288
        char *trigger;
 
289
        int ret;
 
290
 
 
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;
 
297
        else
 
298
                priv->ah->led_pin = ATH_LED_PIN_DEF;
 
299
 
 
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);
 
305
 
 
306
        INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
 
307
 
 
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;
 
313
        if (ret)
 
314
                goto fail;
 
315
 
 
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;
 
321
        if (ret)
 
322
                goto fail;
 
323
 
 
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;
 
329
        if (ret)
 
330
                goto fail;
 
331
 
 
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;
 
337
        if (ret)
 
338
                goto fail;
 
339
 
 
340
        priv->op_flags &= ~OP_LED_DEINIT;
 
341
 
 
342
        return;
 
343
 
 
344
fail:
 
345
        cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
 
346
        ath9k_deinit_leds(priv);
 
347
}
 
348
 
 
349
/*******************/
 
350
/*      Rfkill     */
 
351
/*******************/
 
352
 
 
353
static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
 
354
{
 
355
        return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
 
356
                priv->ah->rfkill_polarity;
 
357
}
 
358
 
 
359
void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
 
360
{
 
361
        struct ath9k_htc_priv *priv = hw->priv;
 
362
        bool blocked = !!ath_is_rfkill_set(priv);
 
363
 
 
364
        wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
 
365
}
 
366
 
 
367
void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
 
368
{
 
369
        if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 
370
                wiphy_rfkill_start_polling(priv->hw->wiphy);
 
371
}
 
372
 
 
373
void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
 
374
{
 
375
        struct ath9k_htc_priv *priv = hw->priv;
 
376
        struct ath_hw *ah = priv->ah;
 
377
        struct ath_common *common = ath9k_hw_common(ah);
 
378
        int ret;
 
379
        u8 cmd_rsp;
 
380
 
 
381
        if (!ah->curchan)
 
382
                ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 
383
 
 
384
        /* Reset the HW */
 
385
        ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 
386
        if (ret) {
 
387
                ath_err(common,
 
388
                        "Unable to reset hardware; reset status %d (freq %u MHz)\n",
 
389
                        ret, ah->curchan->channel);
 
390
        }
 
391
 
 
392
        ath_update_txpow(priv);
 
393
 
 
394
        /* Start RX */
 
395
        WMI_CMD(WMI_START_RECV_CMDID);
 
396
        ath9k_host_rx_init(priv);
 
397
 
 
398
        /* Start TX */
 
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);
 
404
 
 
405
        WMI_CMD(WMI_ENABLE_INTR_CMDID);
 
406
 
 
407
        /* Enable LED */
 
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);
 
411
}
 
412
 
 
413
void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
 
414
{
 
415
        struct ath9k_htc_priv *priv = hw->priv;
 
416
        struct ath_hw *ah = priv->ah;
 
417
        struct ath_common *common = ath9k_hw_common(ah);
 
418
        int ret;
 
419
        u8 cmd_rsp;
 
420
 
 
421
        ath9k_htc_ps_wakeup(priv);
 
422
 
 
423
        /* Disable LED */
 
424
        ath9k_hw_set_gpio(ah, ah->led_pin, 1);
 
425
        ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
 
426
 
 
427
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
 
428
 
 
429
        /* Stop TX */
 
430
        ieee80211_stop_queues(hw);
 
431
        htc_stop(priv->htc);
 
432
        WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
 
433
        skb_queue_purge(&priv->tx_queue);
 
434
 
 
435
        /* Stop RX */
 
436
        WMI_CMD(WMI_STOP_RECV_CMDID);
 
437
 
 
438
        /*
 
439
         * The MIB counters have to be disabled here,
 
440
         * since the target doesn't do it.
 
441
         */
 
442
        ath9k_hw_disable_mib_counters(ah);
 
443
 
 
444
        if (!ah->curchan)
 
445
                ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 
446
 
 
447
        /* Reset the HW */
 
448
        ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 
449
        if (ret) {
 
450
                ath_err(common,
 
451
                        "Unable to reset hardware; reset status %d (freq %u MHz)\n",
 
452
                        ret, ah->curchan->channel);
 
453
        }
 
454
 
 
455
        /* Disable the PHY */
 
456
        ath9k_hw_phy_disable(ah);
 
457
 
 
458
        ath9k_htc_ps_restore(priv);
 
459
        ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
 
460
}