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 "ath5k.h" |
37 | |
38 | |
39 | static inline void ath5k_rfkill_disable(struct ath5k_hw *ah) |
40 | { |
41 | ATH5K_DBG(ah, ATH5K_DEBUG_ANY, "rfkill disable (gpio:%d polarity:%d)\n" , |
42 | ah->rf_kill.gpio, ah->rf_kill.polarity); |
43 | ath5k_hw_set_gpio_output(ah, gpio: ah->rf_kill.gpio); |
44 | ath5k_hw_set_gpio(ah, gpio: ah->rf_kill.gpio, val: !ah->rf_kill.polarity); |
45 | } |
46 | |
47 | |
48 | static inline void ath5k_rfkill_enable(struct ath5k_hw *ah) |
49 | { |
50 | ATH5K_DBG(ah, ATH5K_DEBUG_ANY, "rfkill enable (gpio:%d polarity:%d)\n" , |
51 | ah->rf_kill.gpio, ah->rf_kill.polarity); |
52 | ath5k_hw_set_gpio_output(ah, gpio: ah->rf_kill.gpio); |
53 | ath5k_hw_set_gpio(ah, gpio: ah->rf_kill.gpio, val: ah->rf_kill.polarity); |
54 | } |
55 | |
56 | static inline void ath5k_rfkill_set_intr(struct ath5k_hw *ah, bool enable) |
57 | { |
58 | u32 curval; |
59 | |
60 | ath5k_hw_set_gpio_input(ah, gpio: ah->rf_kill.gpio); |
61 | curval = ath5k_hw_get_gpio(ah, gpio: ah->rf_kill.gpio); |
62 | ath5k_hw_set_gpio_intr(ah, gpio: ah->rf_kill.gpio, interrupt_level: enable ? |
63 | !!curval : !curval); |
64 | } |
65 | |
66 | static bool |
67 | ath5k_is_rfkill_set(struct ath5k_hw *ah) |
68 | { |
69 | /* configuring GPIO for input for some reason disables rfkill */ |
70 | /*ath5k_hw_set_gpio_input(ah, ah->rf_kill.gpio);*/ |
71 | return ath5k_hw_get_gpio(ah, gpio: ah->rf_kill.gpio) == |
72 | ah->rf_kill.polarity; |
73 | } |
74 | |
75 | static void |
76 | ath5k_tasklet_rfkill_toggle(struct tasklet_struct *t) |
77 | { |
78 | struct ath5k_hw *ah = from_tasklet(ah, t, rf_kill.toggleq); |
79 | bool blocked; |
80 | |
81 | blocked = ath5k_is_rfkill_set(ah); |
82 | wiphy_rfkill_set_hw_state(wiphy: ah->hw->wiphy, blocked); |
83 | } |
84 | |
85 | |
86 | void |
87 | ath5k_rfkill_hw_start(struct ath5k_hw *ah) |
88 | { |
89 | /* read rfkill GPIO configuration from EEPROM header */ |
90 | ah->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin; |
91 | ah->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol; |
92 | |
93 | tasklet_setup(t: &ah->rf_kill.toggleq, callback: ath5k_tasklet_rfkill_toggle); |
94 | |
95 | ath5k_rfkill_disable(ah); |
96 | |
97 | /* enable interrupt for rfkill switch */ |
98 | if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) |
99 | ath5k_rfkill_set_intr(ah, enable: true); |
100 | } |
101 | |
102 | |
103 | void |
104 | ath5k_rfkill_hw_stop(struct ath5k_hw *ah) |
105 | { |
106 | /* disable interrupt for rfkill switch */ |
107 | if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) |
108 | ath5k_rfkill_set_intr(ah, enable: false); |
109 | |
110 | tasklet_kill(t: &ah->rf_kill.toggleq); |
111 | |
112 | /* enable RFKILL when stopping HW so Wifi LED is turned off */ |
113 | ath5k_rfkill_enable(ah); |
114 | } |
115 | |
116 | |