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 | |
| 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 | |