1185377Ssam/* 2188976Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17188974Ssam * $FreeBSD$ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam#include "ah_devid.h" 24185377Ssam 25185377Ssam#include "ar5416/ar5416.h" 26185377Ssam#include "ar5416/ar5416reg.h" 27185377Ssam#include "ar5416/ar5416phy.h" 28185377Ssam 29185377Ssam#define AR_GPIO_BIT(_gpio) (1 << _gpio) 30185377Ssam 31185377Ssam/* 32188976Ssam * Configure GPIO Output Mux control 33188976Ssam */ 34188976Ssamstatic void 35188976SsamcfgOutputMux(struct ath_hal *ah, uint32_t gpio, uint32_t type) 36188976Ssam{ 37188976Ssam int addr; 38188976Ssam uint32_t gpio_shift, reg; 39188976Ssam 40188976Ssam /* each MUX controls 6 GPIO pins */ 41188976Ssam if (gpio > 11) 42188976Ssam addr = AR_GPIO_OUTPUT_MUX3; 43188976Ssam else if (gpio > 5) 44188976Ssam addr = AR_GPIO_OUTPUT_MUX2; 45188976Ssam else 46188976Ssam addr = AR_GPIO_OUTPUT_MUX1; 47188976Ssam 48188976Ssam /* 49188976Ssam * 5 bits per GPIO pin. Bits 0..4 for 1st pin in that mux, 50188976Ssam * bits 5..9 for 2nd pin, etc. 51188976Ssam */ 52188976Ssam gpio_shift = (gpio % 6) * 5; 53188976Ssam 54188976Ssam /* 55188976Ssam * From Owl to Merlin 1.0, the value read from MUX1 bit 4 to bit 56188976Ssam * 9 are wrong. Here is hardware's coding: 57188976Ssam * PRDATA[4:0] <= gpio_output_mux[0]; 58188976Ssam * PRDATA[9:4] <= gpio_output_mux[1]; 59188976Ssam * <==== Bit 4 is used by both gpio_output_mux[0] [1]. 60188976Ssam * Currently the max value for gpio_output_mux[] is 6. So bit 4 61188976Ssam * will never be used. So it should be fine that bit 4 won't be 62188976Ssam * able to recover. 63188976Ssam */ 64188976Ssam reg = OS_REG_READ(ah, addr); 65188976Ssam if (addr == AR_GPIO_OUTPUT_MUX1 && !AR_SREV_MERLIN_20_OR_LATER(ah)) 66188976Ssam reg = ((reg & 0x1F0) << 1) | (reg & ~0x1F0); 67188976Ssam reg &= ~(0x1f << gpio_shift); 68188976Ssam reg |= type << gpio_shift; 69188976Ssam OS_REG_WRITE(ah, addr, reg); 70188976Ssam} 71188976Ssam 72188976Ssam/* 73185377Ssam * Configure GPIO Output lines 74185377Ssam */ 75185377SsamHAL_BOOL 76188974Ssamar5416GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type) 77185377Ssam{ 78188976Ssam uint32_t gpio_shift, reg; 79188976Ssam 80188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 81188976Ssam 82188976Ssam /* NB: type maps directly to hardware */ 83188976Ssam cfgOutputMux(ah, gpio, type); 84188976Ssam gpio_shift = gpio << 1; /* 2 bits per output mode */ 85188976Ssam 86188976Ssam reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 87188976Ssam reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 88188993Ssam reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 89188976Ssam OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 90188976Ssam 91185377Ssam return AH_TRUE; 92185377Ssam} 93188976Ssam 94185377Ssam/* 95185377Ssam * Configure GPIO Input lines 96185377Ssam */ 97185377SsamHAL_BOOL 98185377Ssamar5416GpioCfgInput(struct ath_hal *ah, uint32_t gpio) 99185377Ssam{ 100188976Ssam uint32_t gpio_shift, reg; 101188976Ssam 102188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 103188976Ssam 104188976Ssam /* TODO: configure input mux for AR5416 */ 105188976Ssam /* If configured as input, set output to tristate */ 106188976Ssam gpio_shift = gpio << 1; 107188976Ssam 108188976Ssam reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 109188976Ssam reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 110188993Ssam reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 111188976Ssam OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 112188976Ssam 113185377Ssam return AH_TRUE; 114185377Ssam} 115185377Ssam 116185377Ssam/* 117185377Ssam * Once configured for I/O - set output lines 118185377Ssam */ 119185377SsamHAL_BOOL 120185377Ssamar5416GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) 121185377Ssam{ 122185377Ssam uint32_t reg; 123185377Ssam 124188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 125188976Ssam 126188976Ssam reg = OS_REG_READ(ah, AR_GPIO_IN_OUT); 127185377Ssam if (val & 1) 128185377Ssam reg |= AR_GPIO_BIT(gpio); 129185377Ssam else 130185377Ssam reg &= ~AR_GPIO_BIT(gpio); 131188976Ssam OS_REG_WRITE(ah, AR_GPIO_IN_OUT, reg); 132185377Ssam return AH_TRUE; 133185377Ssam} 134185377Ssam 135185377Ssam/* 136185377Ssam * Once configured for I/O - get input lines 137185377Ssam */ 138185377Ssamuint32_t 139185377Ssamar5416GpioGet(struct ath_hal *ah, uint32_t gpio) 140185377Ssam{ 141188976Ssam uint32_t bits; 142188976Ssam 143188976Ssam if (gpio >= AH_PRIVATE(ah)->ah_caps.halNumGpioPins) 144185377Ssam return 0xffffffff; 145188976Ssam /* 146188976Ssam * Read output value for all gpio's, shift it, 147188976Ssam * and verify whether the specific bit is set. 148188976Ssam */ 149203159Srpaulo if (AR_SREV_KITE_10_OR_LATER(ah)) 150203159Srpaulo bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL); 151203159Srpaulo else if (AR_SREV_MERLIN_10_OR_LATER(ah)) 152188976Ssam bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL); 153188976Ssam else 154188976Ssam bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL); 155188976Ssam return ((bits & AR_GPIO_BIT(gpio)) != 0); 156185377Ssam} 157185377Ssam 158185377Ssam/* 159188976Ssam * Set the GPIO Interrupt Sync and Async interrupts are both set/cleared. 160188976Ssam * Async GPIO interrupts may not be raised when the chip is put to sleep. 161185377Ssam */ 162185377Ssamvoid 163185377Ssamar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) 164185377Ssam{ 165188976Ssam uint32_t val, mask; 166185377Ssam 167188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 168185377Ssam 169188976Ssam if (ilevel == HAL_GPIO_INTR_DISABLE) { 170188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 171188976Ssam AR_INTR_ASYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 172188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 173188976Ssam AR_INTR_ASYNC_ENABLE_GPIO, val); 174188976Ssam 175188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 176188976Ssam AR_INTR_ASYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 177188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 178188976Ssam AR_INTR_ASYNC_MASK_GPIO, mask); 179188976Ssam 180188976Ssam /* Clear synchronous GPIO interrupt registers and pending interrupt flag */ 181188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 182188976Ssam AR_INTR_SYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 183188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 184188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 185188976Ssam 186188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 187188976Ssam AR_INTR_SYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 188188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 189188976Ssam AR_INTR_SYNC_MASK_GPIO, mask); 190188976Ssam 191188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_CAUSE), 192188976Ssam AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 193188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_CAUSE, 194188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 195188976Ssam } else { 196188976Ssam val = MS(OS_REG_READ(ah, AR_GPIO_INTR_POL), 197188976Ssam AR_GPIO_INTR_POL_VAL); 198188976Ssam if (ilevel == HAL_GPIO_INTR_HIGH) { 199188976Ssam /* 0 == interrupt on pin high */ 200188976Ssam val &= ~AR_GPIO_BIT(gpio); 201188976Ssam } else if (ilevel == HAL_GPIO_INTR_LOW) { 202188976Ssam /* 1 == interrupt on pin low */ 203188976Ssam val |= AR_GPIO_BIT(gpio); 204188976Ssam } 205188976Ssam OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_POL, 206188976Ssam AR_GPIO_INTR_POL_VAL, val); 207188976Ssam 208188976Ssam /* Change the interrupt mask. */ 209188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 210188976Ssam AR_INTR_ASYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 211188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 212188976Ssam AR_INTR_ASYNC_ENABLE_GPIO, val); 213188976Ssam 214188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 215188976Ssam AR_INTR_ASYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 216188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 217188976Ssam AR_INTR_ASYNC_MASK_GPIO, mask); 218188976Ssam 219188976Ssam /* Set synchronous GPIO interrupt registers as well */ 220188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 221188976Ssam AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 222188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 223188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 224188976Ssam 225188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 226188976Ssam AR_INTR_SYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 227188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 228188976Ssam AR_INTR_SYNC_MASK_GPIO, mask); 229188976Ssam } 230188976Ssam AH5416(ah)->ah_gpioMask = mask; /* for ar5416SetInterrupts */ 231185377Ssam} 232