Commit | Line | Data |
---|---|---|
e6a3b616 TD |
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 |