Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 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 | |
Pavel Roskin | 931be26 | 2011-07-26 22:26:59 -0400 | [diff] [blame^] | 36 | #include "ath5k.h" |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 37 | |
| 38 | |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 39 | static inline void ath5k_rfkill_disable(struct ath5k_hw *ah) |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 40 | { |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 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, ah->rf_kill.gpio); |
| 44 | ath5k_hw_set_gpio(ah, ah->rf_kill.gpio, !ah->rf_kill.polarity); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 45 | } |
| 46 | |
| 47 | |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 48 | static inline void ath5k_rfkill_enable(struct ath5k_hw *ah) |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 49 | { |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 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, ah->rf_kill.gpio); |
| 53 | ath5k_hw_set_gpio(ah, ah->rf_kill.gpio, ah->rf_kill.polarity); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 54 | } |
| 55 | |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 56 | static inline void ath5k_rfkill_set_intr(struct ath5k_hw *ah, bool enable) |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 57 | { |
Bob Copeland | a6ae071 | 2009-06-09 23:43:11 -0400 | [diff] [blame] | 58 | u32 curval; |
| 59 | |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 60 | ath5k_hw_set_gpio_input(ah, ah->rf_kill.gpio); |
| 61 | curval = ath5k_hw_get_gpio(ah, ah->rf_kill.gpio); |
| 62 | ath5k_hw_set_gpio_intr(ah, ah->rf_kill.gpio, enable ? |
Bob Copeland | a6ae071 | 2009-06-09 23:43:11 -0400 | [diff] [blame] | 63 | !!curval : !curval); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | static bool |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 67 | ath5k_is_rfkill_set(struct ath5k_hw *ah) |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 68 | { |
| 69 | /* configuring GPIO for input for some reason disables rfkill */ |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 70 | /*ath5k_hw_set_gpio_input(ah, ah->rf_kill.gpio);*/ |
| 71 | return ath5k_hw_get_gpio(ah, ah->rf_kill.gpio) == |
| 72 | ah->rf_kill.polarity; |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | static void |
| 76 | ath5k_tasklet_rfkill_toggle(unsigned long data) |
| 77 | { |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 78 | struct ath5k_hw *ah = (void *)data; |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 79 | bool blocked; |
| 80 | |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 81 | blocked = ath5k_is_rfkill_set(ah); |
| 82 | wiphy_rfkill_set_hw_state(ah->hw->wiphy, blocked); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | |
| 86 | void |
| 87 | ath5k_rfkill_hw_start(struct ath5k_hw *ah) |
| 88 | { |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 89 | /* read rfkill GPIO configuration from EEPROM header */ |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 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; |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 92 | |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 93 | tasklet_init(&ah->rf_kill.toggleq, ath5k_tasklet_rfkill_toggle, |
| 94 | (unsigned long)ah); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 95 | |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 96 | ath5k_rfkill_disable(ah); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 97 | |
| 98 | /* enable interrupt for rfkill switch */ |
Bob Copeland | a6ae071 | 2009-06-09 23:43:11 -0400 | [diff] [blame] | 99 | if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 100 | ath5k_rfkill_set_intr(ah, true); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | |
| 104 | void |
| 105 | ath5k_rfkill_hw_stop(struct ath5k_hw *ah) |
| 106 | { |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 107 | /* disable interrupt for rfkill switch */ |
Bob Copeland | a6ae071 | 2009-06-09 23:43:11 -0400 | [diff] [blame] | 108 | if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 109 | ath5k_rfkill_set_intr(ah, false); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 110 | |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 111 | tasklet_kill(&ah->rf_kill.toggleq); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 112 | |
| 113 | /* enable RFKILL when stopping HW so Wifi LED is turned off */ |
Pavel Roskin | e0d687b | 2011-07-14 20:21:55 -0400 | [diff] [blame] | 114 | ath5k_rfkill_enable(ah); |
Tobias Doerffel | e6a3b61 | 2009-06-09 17:33:27 +0200 | [diff] [blame] | 115 | } |
| 116 | |