aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath5k/Kconfig8
-rw-r--r--drivers/net/wireless/ath/ath5k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h9
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c10
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h14
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c17
-rw-r--r--drivers/net/wireless/ath/ath5k/rfkill.c121
7 files changed, 163 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index 509b6f94f73b..4863f4bbf768 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -39,3 +39,11 @@ config ATH5K_DEBUG
39 39
40 modprobe ath5k debug=0x00000400 40 modprobe ath5k debug=0x00000400
41 41
42config ATH5K_RFKILL
43 bool "Atheros 5xxx rfkill support"
44 depends on ATH5K
45 default y
46 ---help---
47 Include support for enabling/disabling WiFi via rfkill switch
48 with Atheros 5xxx cards
49
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index 84a74c5248e5..f1e281c5a213 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -12,4 +12,5 @@ ath5k-y += attach.o
12ath5k-y += base.o 12ath5k-y += base.o
13ath5k-y += led.o 13ath5k-y += led.o
14ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o 14ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
15ath5k-$(CONFIG_ATH5K_RFKILL) += rfkill.o
15obj-$(CONFIG_ATH5K) += ath5k.o 16obj-$(CONFIG_ATH5K) += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 813718210338..4c84e308763c 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1256,6 +1256,15 @@ extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
1256extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); 1256extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
1257extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); 1257extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
1258 1258
1259/* rfkill Functions */
1260#ifdef CONFIG_ATH5K_RFKILL
1261extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
1262extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
1263#else
1264static inline void ath5k_rfkill_hw_start(struct ath5k_hw *ah) {}
1265static inline void ath5k_rfkill_hw_stop(struct ath5k_hw *ah) {}
1266#endif
1267
1259/* Misc functions */ 1268/* Misc functions */
1260int ath5k_hw_set_capabilities(struct ath5k_hw *ah); 1269int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
1261extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); 1270extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 85a00db4867d..f55675c23f2e 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2360,6 +2360,8 @@ ath5k_init(struct ath5k_softc *sc)
2360 if (ret) 2360 if (ret)
2361 goto done; 2361 goto done;
2362 2362
2363 ath5k_rfkill_hw_start(ah);
2364
2363 /* 2365 /*
2364 * Reset the key cache since some parts do not reset the 2366 * Reset the key cache since some parts do not reset the
2365 * contents on initial power up or resume from suspend. 2367 * contents on initial power up or resume from suspend.
@@ -2468,6 +2470,8 @@ ath5k_stop_hw(struct ath5k_softc *sc)
2468 tasklet_kill(&sc->restq); 2470 tasklet_kill(&sc->restq);
2469 tasklet_kill(&sc->beacontq); 2471 tasklet_kill(&sc->beacontq);
2470 2472
2473 ath5k_rfkill_hw_stop(sc->ah);
2474
2471 return ret; 2475 return ret;
2472} 2476}
2473 2477
@@ -2526,6 +2530,12 @@ ath5k_intr(int irq, void *dev_id)
2526 */ 2530 */
2527 ath5k_hw_update_mib_counters(ah, &sc->ll_stats); 2531 ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
2528 } 2532 }
2533#ifdef CONFIG_ATH5K_RFKILL
2534 if (status & AR5K_INT_GPIO)
2535 {
2536 tasklet_schedule(&sc->rf_kill.toggleq);
2537 }
2538#endif
2529 } 2539 }
2530 } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); 2540 } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
2531 2541
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 852b2c189fd8..7a0ecdd9c258 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -46,6 +46,7 @@
46#include <linux/wireless.h> 46#include <linux/wireless.h>
47#include <linux/if_ether.h> 47#include <linux/if_ether.h>
48#include <linux/leds.h> 48#include <linux/leds.h>
49#include <linux/rfkill.h>
49 50
50#include "ath5k.h" 51#include "ath5k.h"
51#include "debug.h" 52#include "debug.h"
@@ -91,6 +92,15 @@ struct ath5k_led
91 struct led_classdev led_dev; /* led classdev */ 92 struct led_classdev led_dev; /* led classdev */
92}; 93};
93 94
95/* Rfkill */
96struct ath5k_rfkill {
97 /* GPIO PIN for rfkill */
98 u16 gpio;
99 /* polarity of rfkill GPIO PIN */
100 bool polarity;
101 /* RFKILL toggle tasklet */
102 struct tasklet_struct toggleq;
103};
94 104
95#if CHAN_DEBUG 105#if CHAN_DEBUG
96#define ATH_CHAN_MAX (26+26+26+200+200) 106#define ATH_CHAN_MAX (26+26+26+200+200)
@@ -167,6 +177,10 @@ struct ath5k_softc {
167 struct tasklet_struct txtq; /* tx intr tasklet */ 177 struct tasklet_struct txtq; /* tx intr tasklet */
168 struct ath5k_led tx_led; /* tx led */ 178 struct ath5k_led tx_led; /* tx led */
169 179
180#ifdef CONFIG_ATH5K_RFKILL
181 struct ath5k_rfkill rf_kill;
182#endif
183
170 spinlock_t block; /* protects beacon */ 184 spinlock_t block; /* protects beacon */
171 struct tasklet_struct beacontq; /* beacon intr tasklet */ 185 struct tasklet_struct beacontq; /* beacon intr tasklet */
172 struct ath5k_buf *bbuf; /* beacon buffer */ 186 struct ath5k_buf *bbuf; /* beacon buffer */
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 66067733ddd3..bd0a97a38d34 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -1304,23 +1304,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
1304 if (ah->ah_version != AR5K_AR5210) 1304 if (ah->ah_version != AR5K_AR5210)
1305 ath5k_hw_set_imr(ah, ah->ah_imr); 1305 ath5k_hw_set_imr(ah, ah->ah_imr);
1306 1306
1307 /*
1308 * Setup RFKill interrupt if rfkill flag is set on eeprom.
1309 * TODO: Use gpio pin and polarity infos from eeprom
1310 * TODO: Handle this in ath5k_intr because it'll result
1311 * a nasty interrupt storm.
1312 */
1313#if 0
1314 if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
1315 ath5k_hw_set_gpio_input(ah, 0);
1316 ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
1317 if (ah->ah_gpio[0] == 0)
1318 ath5k_hw_set_gpio_intr(ah, 0, 1);
1319 else
1320 ath5k_hw_set_gpio_intr(ah, 0, 0);
1321 }
1322#endif
1323
1324 /* Enable 32KHz clock function for AR5212+ chips 1307 /* Enable 32KHz clock function for AR5212+ chips
1325 * Set clocks to 32KHz operation and use an 1308 * Set clocks to 32KHz operation and use an
1326 * external 32KHz crystal when sleeping if one 1309 * external 32KHz crystal when sleeping if one
diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c
new file mode 100644
index 000000000000..492ada92db56
--- /dev/null
+++ b/drivers/net/wireless/ath/ath5k/rfkill.c
@@ -0,0 +1,121 @@
1/*
2 * RFKILL support for ath5k
3 *
4 * Copyright (c) 2009 Tobias Doerffel <tobias.doerffel@gmail.com>
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer,
13 * without modification.
14 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
15 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
16 * redistribution must be conditioned upon including a substantially
17 * similar Disclaimer requirement for further binary redistribution.
18 * 3. Neither the names of the above-listed copyright holders nor the names
19 * of any contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * NO WARRANTY
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
26 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGES.
34 */
35
36#include "base.h"
37
38
39static inline void ath5k_rfkill_disable(struct ath5k_softc *sc)
40{
41 ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill disable (gpio:%d polarity:%d)\n",
42 sc->rf_kill.gpio, sc->rf_kill.polarity);
43 ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
44 ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity);
45}
46
47
48static inline void ath5k_rfkill_enable(struct ath5k_softc *sc)
49{
50 ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill enable (gpio:%d polarity:%d)\n",
51 sc->rf_kill.gpio, sc->rf_kill.polarity);
52 ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
53 ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity);
54}
55
56static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, bool enable)
57{
58 struct ath5k_hw *ah = sc->ah;
59 ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio);
60 ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio);
61 ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ?
62 !!ah->ah_gpio[0] : !ah->ah_gpio[0]);
63}
64
65static bool
66ath5k_is_rfkill_set(struct ath5k_softc *sc)
67{
68 /* configuring GPIO for input for some reason disables rfkill */
69 /*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/
70 return ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) ==
71 sc->rf_kill.polarity;
72}
73
74static void
75ath5k_tasklet_rfkill_toggle(unsigned long data)
76{
77 struct ath5k_softc *sc = (void *)data;
78 bool blocked;
79
80 blocked = ath5k_is_rfkill_set(sc);
81 wiphy_rfkill_set_hw_state(sc->hw->wiphy, blocked);
82}
83
84
85void
86ath5k_rfkill_hw_start(struct ath5k_hw *ah)
87{
88 struct ath5k_softc *sc = ah->ah_sc;
89
90 /* read rfkill GPIO configuration from EEPROM header */
91 sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin;
92 sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol;
93
94 tasklet_init(&sc->rf_kill.toggleq, ath5k_tasklet_rfkill_toggle,
95 (unsigned long)sc);
96
97 ath5k_rfkill_disable(sc);
98
99 /* enable interrupt for rfkill switch */
100 if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
101 ath5k_rfkill_set_intr(sc, true);
102 }
103}
104
105
106void
107ath5k_rfkill_hw_stop(struct ath5k_hw *ah)
108{
109 struct ath5k_softc *sc = ah->ah_sc;
110
111 /* disable interrupt for rfkill switch */
112 if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
113 ath5k_rfkill_set_intr(sc, false);
114 }
115
116 tasklet_kill(&sc->rf_kill.toggleq);
117
118 /* enable RFKILL when stopping HW so Wifi LED is turned off */
119 ath5k_rfkill_enable(sc);
120}
121