Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | /* * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /****************\ GPIO Functions \****************/ #include "ath5k.h" #include "reg.h" #include "debug.h" /** * DOC: GPIO/LED functions * * Here we control the 6 bidirectional GPIO pins provided by the hw. * We can set a GPIO pin to be an input or an output pin on GPIO control * register and then read or set its status from GPIO data input/output * registers. * * We also control the two LED pins provided by the hw, LED_0 is our * "power" LED and LED_1 is our "network activity" LED but many scenarios * are available from hw. Vendors might also provide LEDs connected to the * GPIO pins, we handle them through the LED subsystem on led.c */ /** * ath5k_hw_set_ledstate() - Set led state * @ah: The &struct ath5k_hw * @state: One of AR5K_LED_* * * Used to set the LED blinking state. This only * works for the LED connected to the LED_0, LED_1 pins, * not the GPIO based. */ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) { u32 led; /*5210 has different led mode handling*/ u32 led_5210; /*Reset led status*/ if (ah->ah_version != AR5K_AR5210) AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); else AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); /* * Some blinking values, define at your wish */ switch (state) { case AR5K_LED_SCAN: case AR5K_LED_AUTH: led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; break; case AR5K_LED_INIT: led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; led_5210 = AR5K_PCICFG_LED_PEND; break; case AR5K_LED_ASSOC: case AR5K_LED_RUN: led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; led_5210 = AR5K_PCICFG_LED_ASSOC; break; default: led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; led_5210 = AR5K_PCICFG_LED_PEND; break; } /*Write new status to the register*/ if (ah->ah_version != AR5K_AR5210) AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); else AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); } /** * ath5k_hw_set_gpio_input() - Set GPIO inputs * @ah: The &struct ath5k_hw * @gpio: GPIO pin to set as input */ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) { if (gpio >= AR5K_NUM_GPIO) return -EINVAL; ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); return 0; } /** * ath5k_hw_set_gpio_output() - Set GPIO outputs * @ah: The &struct ath5k_hw * @gpio: The GPIO pin to set as output */ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) { if (gpio >= AR5K_NUM_GPIO) return -EINVAL; ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); return 0; } /** * ath5k_hw_get_gpio() - Get GPIO state * @ah: The &struct ath5k_hw * @gpio: The GPIO pin to read */ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) { if (gpio >= AR5K_NUM_GPIO) return 0xffffffff; /* GPIO input magic */ return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & 0x1; } /** * ath5k_hw_set_gpio() - Set GPIO state * @ah: The &struct ath5k_hw * @gpio: The GPIO pin to set * @val: Value to set (boolean) */ int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) { u32 data; if (gpio >= AR5K_NUM_GPIO) return -EINVAL; /* GPIO output magic */ data = ath5k_hw_reg_read(ah, AR5K_GPIODO); data &= ~(1 << gpio); data |= (val & 1) << gpio; ath5k_hw_reg_write(ah, data, AR5K_GPIODO); return 0; } /** * ath5k_hw_set_gpio_intr() - Initialize the GPIO interrupt (RFKill switch) * @ah: The &struct ath5k_hw * @gpio: The GPIO pin to use * @interrupt_level: True to generate interrupt on active pin (high) * * This function is used to set up the GPIO interrupt for the hw RFKill switch. * That switch is connected to a GPIO pin and it's number is stored on EEPROM. * It can either open or close the circuit to indicate that we should disable * RF/Wireless to save power (we also get that from EEPROM). */ void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level) { u32 data; if (gpio >= AR5K_NUM_GPIO) return; /* * Set the GPIO interrupt */ data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); ath5k_hw_reg_write(ah, interrupt_level ? data : (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); ah->ah_imr |= AR5K_IMR_GPIO; /* Enable GPIO interrupts */ AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); } |