aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Doerffel <tobias.doerffel@gmail.com>2009-06-09 11:33:27 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-06-10 13:27:54 -0400
commite6a3b61681dcb963e6465ffbc4330b44824f35e3 (patch)
tree1628eb26f1a79858391686a64e9e72780cd6340a
parent207ee1621722876bb79828689582bf77fd1be200 (diff)
ath5k: added cfg80211 based rfkill support
This patch introduces initial rfkill support for the ath5k driver based on rfkill support in the cfg80211 framework. All rfkill related code is separated into newly created rfkill.c. Changes to existing code are minimal: * added a new data structure ath5k_rfkill to the ath5k_softc structure * inserted calls to HW rfkill init/deinit routines * ath5k_intr() has been extended to handle AR5K_INT_GPIO interrupts Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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