diff options
-rw-r--r-- | drivers/net/wireless/ath/ath5k/Kconfig | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/ath5k.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.h | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/reset.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/rfkill.c | 121 |
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 | ||
42 | config 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 | |||
12 | ath5k-y += base.o | 12 | ath5k-y += base.o |
13 | ath5k-y += led.o | 13 | ath5k-y += led.o |
14 | ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o | 14 | ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o |
15 | ath5k-$(CONFIG_ATH5K_RFKILL) += rfkill.o | ||
15 | obj-$(CONFIG_ATH5K) += ath5k.o | 16 | obj-$(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); | |||
1256 | extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); | 1256 | extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); |
1257 | extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); | 1257 | extern 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 | ||
1261 | extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah); | ||
1262 | extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); | ||
1263 | #else | ||
1264 | static inline void ath5k_rfkill_hw_start(struct ath5k_hw *ah) {} | ||
1265 | static inline void ath5k_rfkill_hw_stop(struct ath5k_hw *ah) {} | ||
1266 | #endif | ||
1267 | |||
1259 | /* Misc functions */ | 1268 | /* Misc functions */ |
1260 | int ath5k_hw_set_capabilities(struct ath5k_hw *ah); | 1269 | int ath5k_hw_set_capabilities(struct ath5k_hw *ah); |
1261 | extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); | 1270 | extern 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 */ | ||
96 | struct 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 | |||
39 | static 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 | |||
48 | static 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 | |||
56 | static 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 | |||
65 | static bool | ||
66 | ath5k_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 | |||
74 | static void | ||
75 | ath5k_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 | |||
85 | void | ||
86 | ath5k_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 | |||
106 | void | ||
107 | ath5k_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 | |||