1 /* 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $FreeBSD$ 18 */ 19 #include "opt_ah.h" 20 21 #include "ah.h" 22 #include "ah_internal.h" 23 #include "ah_devid.h" 24 25 #include "ar5416/ar5416.h" 26 #include "ar5416/ar5416reg.h" 27 #include "ar5416/ar5416phy.h" 28 29 #define AR_GPIO_BIT(_gpio) (1 << _gpio) 30 31 /* 32 * Configure GPIO Output Mux control 33 */ 34 static void 35 cfgOutputMux(struct ath_hal *ah, uint32_t gpio, uint32_t type) 36 { 37 int addr; 38 uint32_t gpio_shift, reg; 39 40 /* each MUX controls 6 GPIO pins */ 41 if (gpio > 11) 42 addr = AR_GPIO_OUTPUT_MUX3; 43 else if (gpio > 5) 44 addr = AR_GPIO_OUTPUT_MUX2; 45 else 46 addr = AR_GPIO_OUTPUT_MUX1; 47 48 /* 49 * 5 bits per GPIO pin. Bits 0..4 for 1st pin in that mux, 50 * bits 5..9 for 2nd pin, etc. 51 */ 52 gpio_shift = (gpio % 6) * 5; 53 54 /* 55 * From Owl to Merlin 1.0, the value read from MUX1 bit 4 to bit 56 * 9 are wrong. Here is hardware's coding: 57 * PRDATA[4:0] <= gpio_output_mux[0]; 58 * PRDATA[9:4] <= gpio_output_mux[1]; 59 * <==== Bit 4 is used by both gpio_output_mux[0] [1]. 60 * Currently the max value for gpio_output_mux[] is 6. So bit 4 61 * will never be used. So it should be fine that bit 4 won't be 62 * able to recover. 63 */ 64 reg = OS_REG_READ(ah, addr); 65 if (addr == AR_GPIO_OUTPUT_MUX1 && !AR_SREV_MERLIN_20_OR_LATER(ah)) 66 reg = ((reg & 0x1F0) << 1) | (reg & ~0x1F0); 67 reg &= ~(0x1f << gpio_shift); 68 reg |= type << gpio_shift; 69 OS_REG_WRITE(ah, addr, reg); 70 } 71 72 /* 73 * Configure GPIO Output lines 74 */ 75 HAL_BOOL 76 ar5416GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type) 77 { 78 uint32_t gpio_shift, reg; 79 80 HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 81 82 /* NB: type maps directly to hardware */ 83 cfgOutputMux(ah, gpio, type); 84 gpio_shift = gpio << 1; /* 2 bits per output mode */ 85 86 reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 87 reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 88 reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 89 OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 90 91 return AH_TRUE; 92 } 93 94 /* 95 * Configure GPIO Input lines 96 */ 97 HAL_BOOL 98 ar5416GpioCfgInput(struct ath_hal *ah, uint32_t gpio) 99 { 100 uint32_t gpio_shift, reg; 101 102 HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 103 104 /* TODO: configure input mux for AR5416 */ 105 /* If configured as input, set output to tristate */ 106 gpio_shift = gpio << 1; 107 108 reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 109 reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 110 reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 111 OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 112 113 return AH_TRUE; 114 } 115 116 /* 117 * Once configured for I/O - set output lines 118 */ 119 HAL_BOOL 120 ar5416GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) 121 { 122 uint32_t reg; 123 124 HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 125 126 reg = OS_REG_READ(ah, AR_GPIO_IN_OUT); 127 if (val & 1) 128 reg |= AR_GPIO_BIT(gpio); 129 else 130 reg &= ~AR_GPIO_BIT(gpio); 131 OS_REG_WRITE(ah, AR_GPIO_IN_OUT, reg); 132 return AH_TRUE; 133 } 134 135 /* 136 * Once configured for I/O - get input lines 137 */ 138 uint32_t 139 ar5416GpioGet(struct ath_hal *ah, uint32_t gpio) 140 { 141 uint32_t bits; 142 143 if (gpio >= AH_PRIVATE(ah)->ah_caps.halNumGpioPins) 144 return 0xffffffff; 145 /* 146 * Read output value for all gpio's, shift it, 147 * and verify whether the specific bit is set. 148 */ 149 if (AR_SREV_MERLIN_10_OR_LATER(ah)) 150 bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL); 151 else 152 bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL); 153 return ((bits & AR_GPIO_BIT(gpio)) != 0); 154 } 155 156 /* 157 * Set the GPIO Interrupt Sync and Async interrupts are both set/cleared. 158 * Async GPIO interrupts may not be raised when the chip is put to sleep. 159 */ 160 void 161 ar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) 162 { 163 uint32_t val, mask; 164 165 HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 166 167 if (ilevel == HAL_GPIO_INTR_DISABLE) { 168 val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 169 AR_INTR_ASYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 170 OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 171 AR_INTR_ASYNC_ENABLE_GPIO, val); 172 173 mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 174 AR_INTR_ASYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 175 OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 176 AR_INTR_ASYNC_MASK_GPIO, mask); 177 178 /* Clear synchronous GPIO interrupt registers and pending interrupt flag */ 179 val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 180 AR_INTR_SYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 181 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 182 AR_INTR_SYNC_ENABLE_GPIO, val); 183 184 mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 185 AR_INTR_SYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 186 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 187 AR_INTR_SYNC_MASK_GPIO, mask); 188 189 val = MS(OS_REG_READ(ah, AR_INTR_SYNC_CAUSE), 190 AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 191 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_CAUSE, 192 AR_INTR_SYNC_ENABLE_GPIO, val); 193 } else { 194 val = MS(OS_REG_READ(ah, AR_GPIO_INTR_POL), 195 AR_GPIO_INTR_POL_VAL); 196 if (ilevel == HAL_GPIO_INTR_HIGH) { 197 /* 0 == interrupt on pin high */ 198 val &= ~AR_GPIO_BIT(gpio); 199 } else if (ilevel == HAL_GPIO_INTR_LOW) { 200 /* 1 == interrupt on pin low */ 201 val |= AR_GPIO_BIT(gpio); 202 } 203 OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_POL, 204 AR_GPIO_INTR_POL_VAL, val); 205 206 /* Change the interrupt mask. */ 207 val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 208 AR_INTR_ASYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 209 OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 210 AR_INTR_ASYNC_ENABLE_GPIO, val); 211 212 mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 213 AR_INTR_ASYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 214 OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 215 AR_INTR_ASYNC_MASK_GPIO, mask); 216 217 /* Set synchronous GPIO interrupt registers as well */ 218 val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 219 AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 220 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 221 AR_INTR_SYNC_ENABLE_GPIO, val); 222 223 mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 224 AR_INTR_SYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 225 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 226 AR_INTR_SYNC_MASK_GPIO, mask); 227 } 228 AH5416(ah)->ah_gpioMask = mask; /* for ar5416SetInterrupts */ 229 } 230