ar5416_gpio.c revision 237611
1139749Simp/* 259477Swpaul * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 359477Swpaul * Copyright (c) 2002-2008 Atheros Communications, Inc. 459477Swpaul * 559477Swpaul * Permission to use, copy, modify, and/or distribute this software for any 659477Swpaul * purpose with or without fee is hereby granted, provided that the above 759477Swpaul * copyright notice and this permission notice appear in all copies. 859477Swpaul * 959477Swpaul * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1059477Swpaul * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1159477Swpaul * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1259477Swpaul * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1359477Swpaul * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1459477Swpaul * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1559477Swpaul * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1659477Swpaul * 1759477Swpaul * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 237611 2012-06-26 22:16:53Z adrian $ 1859477Swpaul */ 1959477Swpaul#include "opt_ah.h" 2059477Swpaul 2159477Swpaul#include "ah.h" 2259477Swpaul#include "ah_internal.h" 2359477Swpaul#include "ah_devid.h" 2459477Swpaul 2559477Swpaul#include "ar5416/ar5416.h" 2659477Swpaul#include "ar5416/ar5416reg.h" 2759477Swpaul#include "ar5416/ar5416phy.h" 2859477Swpaul 2959477Swpaul#define AR_GPIO_BIT(_gpio) (1 << _gpio) 3059477Swpaul 3159477Swpaul/* 3259477Swpaul * Configure GPIO Output Mux control 33119418Sobrien */ 34119418Sobrienstatic void 35119418SobriencfgOutputMux(struct ath_hal *ah, uint32_t gpio, uint32_t type) 3659477Swpaul{ 3759477Swpaul int addr; 3859477Swpaul uint32_t gpio_shift, tmp; 3959477Swpaul 4059477Swpaul HALDEBUG(ah, HAL_DEBUG_GPIO, "%s: gpio=%d, type=%d\n", 4159477Swpaul __func__, gpio, type); 4259477Swpaul 4359477Swpaul /* each MUX controls 6 GPIO pins */ 44129876Sphk if (gpio > 11) 4559477Swpaul addr = AR_GPIO_OUTPUT_MUX3; 4659477Swpaul else if (gpio > 5) 4759477Swpaul addr = AR_GPIO_OUTPUT_MUX2; 4883029Swpaul else 4959477Swpaul addr = AR_GPIO_OUTPUT_MUX1; 5059477Swpaul 5159477Swpaul /* 5259477Swpaul * 5 bits per GPIO pin. Bits 0..4 for 1st pin in that mux, 5359477Swpaul * bits 5..9 for 2nd pin, etc. 5459477Swpaul */ 55109514Sobrien gpio_shift = (gpio % 6) * 5; 5659477Swpaul 5759477Swpaul /* 58117659Swpaul * From Owl to Merlin 1.0, the value read from MUX1 bit 4 to bit 59117659Swpaul * 9 are wrong. Here is hardware's coding: 60117659Swpaul * PRDATA[4:0] <= gpio_output_mux[0]; 6159477Swpaul * PRDATA[9:4] <= gpio_output_mux[1]; 62119285Simp * <==== Bit 4 is used by both gpio_output_mux[0] [1]. 63119285Simp * Currently the max value for gpio_output_mux[] is 6. So bit 4 64118814Swpaul * will never be used. So it should be fine that bit 4 won't be 6559477Swpaul * able to recover. 6659477Swpaul */ 67105135Salfred if (AR_SREV_MERLIN_20_OR_LATER(ah) || 68105135Salfred (addr != AR_GPIO_OUTPUT_MUX1)) { 6959477Swpaul OS_REG_RMW(ah, addr, (type << gpio_shift), 7059477Swpaul (0x1f << gpio_shift)); 7159477Swpaul } else { 7259477Swpaul tmp = OS_REG_READ(ah, addr); 7359477Swpaul tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); 7495722Sphk tmp &= ~(0x1f << gpio_shift); 7559477Swpaul tmp |= type << gpio_shift; 7659477Swpaul OS_REG_WRITE(ah, addr, tmp); 7759477Swpaul } 7859477Swpaul} 7959477Swpaul 8059477Swpaul/* 8159477Swpaul * Configure GPIO Output lines 8259477Swpaul */ 8359477SwpaulHAL_BOOL 8459477Swpaular5416GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type) 8559477Swpaul{ 8659477Swpaul uint32_t gpio_shift, reg; 8759477Swpaul 8859477Swpaul#define N(a) (sizeof(a) / sizeof(a[0])) 8984145Sjlemon 9084145Sjlemon HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 9196026Sphk 92114590Sps /* 93114590Sps * This table maps the HAL GPIO pins to the actual hardware 94114590Sps * values. 95114590Sps */ 96114590Sps static const u_int32_t MuxSignalConversionTable[] = { 97135772Sps AR_GPIO_OUTPUT_MUX_AS_OUTPUT, 98114590Sps AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, 9959477Swpaul AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, 100105135Salfred AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, 101150763Simp AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, 10259477Swpaul AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL, 10359477Swpaul AR_GPIO_OUTPUT_MUX_AS_TX_FRAME, 10459477Swpaul }; 10559477Swpaul 10659477Swpaul HALDEBUG(ah, HAL_DEBUG_GPIO, 10783029Swpaul "%s: gpio=%d, type=%d\n", __func__, gpio, type); 10883029Swpaul 10983029Swpaul /* 11083029Swpaul * Convert HAL signal type definitions to hardware-specific values. 11183029Swpaul */ 11259477Swpaul if (type >= N(MuxSignalConversionTable)) { 11383029Swpaul ath_hal_printf(ah, "%s: mux %d is invalid!\n", 11483029Swpaul __func__, 11583029Swpaul type); 11683029Swpaul return AH_FALSE; 11783029Swpaul } 11859477Swpaul cfgOutputMux(ah, gpio, MuxSignalConversionTable[type]); 11983029Swpaul 12083029Swpaul /* 2 bits per output mode */ 12183029Swpaul gpio_shift = gpio << 1; 12283029Swpaul 12383029Swpaul /* Always drive, rather than tristate/drive low/drive high */ 12483029Swpaul reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 12592931Swpaul reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 12692931Swpaul reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 12792931Swpaul OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 12892931Swpaul 12992931Swpaul return AH_TRUE; 13092931Swpaul#undef N 131103103Sjdp} 132103103Sjdp 133103103Sjdp/* 134103103Sjdp * Configure GPIO Input lines 135103103Sjdp */ 136103103SjdpHAL_BOOL 137114547Spsar5416GpioCfgInput(struct ath_hal *ah, uint32_t gpio) 138114547Sps{ 139114547Sps uint32_t gpio_shift, reg; 140114547Sps 141114547Sps HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 142114547Sps 143117659Swpaul HALDEBUG(ah, HAL_DEBUG_GPIO, "%s: gpio=%d\n", __func__, gpio); 144117659Swpaul 145117659Swpaul /* TODO: configure input mux for AR5416 */ 146117659Swpaul /* If configured as input, set output to tristate */ 147117659Swpaul gpio_shift = gpio << 1; 148117659Swpaul 149135772Sps reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 150135772Sps reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 151135772Sps reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 152135772Sps OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 153135772Sps 154135772Sps return AH_TRUE; 155146413Sps} 156146413Sps 157146413Sps/* 158146413Sps * Once configured for I/O - set output lines 159146413Sps */ 160146413SpsHAL_BOOL 161157041Solegar5416GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) 162157041Soleg{ 163157041Soleg uint32_t reg; 164157041Soleg 165157041Soleg HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 166157041Soleg HALDEBUG(ah, HAL_DEBUG_GPIO, 16783029Swpaul "%s: gpio=%d, val=%d\n", __func__, gpio, val); 16859477Swpaul 16959477Swpaul reg = OS_REG_READ(ah, AR_GPIO_IN_OUT); 170105135Salfred if (val & 1) 171150763Simp reg |= AR_GPIO_BIT(gpio); 17259477Swpaul else 17359477Swpaul reg &= ~AR_GPIO_BIT(gpio); 17459477Swpaul OS_REG_WRITE(ah, AR_GPIO_IN_OUT, reg); 17559477Swpaul return AH_TRUE; 17659477Swpaul} 177118814Swpaul 178118814Swpaul/* 17959477Swpaul * Once configured for I/O - get input lines 18059477Swpaul */ 18159477Swpauluint32_t 18259477Swpaular5416GpioGet(struct ath_hal *ah, uint32_t gpio) 18359477Swpaul{ 18459477Swpaul uint32_t bits; 18559477Swpaul 18659477Swpaul if (gpio >= AH_PRIVATE(ah)->ah_caps.halNumGpioPins) 18759477Swpaul return 0xffffffff; 18859477Swpaul /* 18959477Swpaul * Read output value for all gpio's, shift it, 19059477Swpaul * and verify whether the specific bit is set. 19159477Swpaul */ 19259477Swpaul if (AR_SREV_KIWI_10_OR_LATER(ah)) 19359477Swpaul bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9287_GPIO_IN_VAL); 19459477Swpaul if (AR_SREV_KITE_10_OR_LATER(ah)) 19559477Swpaul bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL); 19659477Swpaul else if (AR_SREV_MERLIN_10_OR_LATER(ah)) 19759477Swpaul bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL); 19859477Swpaul else 19959477Swpaul bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL); 20059477Swpaul return ((bits & AR_GPIO_BIT(gpio)) != 0); 20159477Swpaul} 20259477Swpaul 20359477Swpaul/* 204114590Sps * Set the GPIO Interrupt Sync and Async interrupts are both set/cleared. 205114590Sps * Async GPIO interrupts may not be raised when the chip is put to sleep. 20659477Swpaul */ 20783029Swpaulvoid 20895667Sphkar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) 20995667Sphk{ 21059477Swpaul uint32_t val, mask; 21195667Sphk 212118814Swpaul HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 213118814Swpaul HALDEBUG(ah, HAL_DEBUG_GPIO, 214118814Swpaul "%s: gpio=%d, ilevel=%d\n", __func__, gpio, ilevel); 215118814Swpaul 216118814Swpaul if (ilevel == HAL_GPIO_INTR_DISABLE) { 217121816Sbrooks val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 218118814Swpaul AR_INTR_ASYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 219118814Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 220118814Swpaul AR_INTR_ASYNC_ENABLE_GPIO, val); 221118814Swpaul 222118814Swpaul mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 223118814Swpaul AR_INTR_ASYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 224118814Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 225118814Swpaul AR_INTR_ASYNC_MASK_GPIO, mask); 226118814Swpaul 227118814Swpaul /* Clear synchronous GPIO interrupt registers and pending interrupt flag */ 228118814Swpaul val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 229118814Swpaul AR_INTR_SYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 230118814Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 231118814Swpaul AR_INTR_SYNC_ENABLE_GPIO, val); 23259477Swpaul 23359477Swpaul mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 23459477Swpaul AR_INTR_SYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 23559477Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 23659477Swpaul AR_INTR_SYNC_MASK_GPIO, mask); 23759477Swpaul 23859477Swpaul val = MS(OS_REG_READ(ah, AR_INTR_SYNC_CAUSE), 23959477Swpaul AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 24059477Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_CAUSE, 24159477Swpaul AR_INTR_SYNC_ENABLE_GPIO, val); 24259477Swpaul } else { 24384145Sjlemon val = MS(OS_REG_READ(ah, AR_GPIO_INTR_POL), 244150763Simp AR_GPIO_INTR_POL_VAL); 24559477Swpaul if (ilevel == HAL_GPIO_INTR_HIGH) { 24659477Swpaul /* 0 == interrupt on pin high */ 247114590Sps val &= ~AR_GPIO_BIT(gpio); 24859477Swpaul } else if (ilevel == HAL_GPIO_INTR_LOW) { 24959477Swpaul /* 1 == interrupt on pin low */ 25059477Swpaul val |= AR_GPIO_BIT(gpio); 25159477Swpaul } 25259477Swpaul OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_POL, 25359477Swpaul AR_GPIO_INTR_POL_VAL, val); 25459477Swpaul 25559477Swpaul /* Change the interrupt mask. */ 25659477Swpaul val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 25759477Swpaul AR_INTR_ASYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 25859477Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 25959477Swpaul AR_INTR_ASYNC_ENABLE_GPIO, val); 26059477Swpaul 26159477Swpaul mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 26259477Swpaul AR_INTR_ASYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 26359477Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 26459477Swpaul AR_INTR_ASYNC_MASK_GPIO, mask); 26559477Swpaul 26659477Swpaul /* Set synchronous GPIO interrupt registers as well */ 26759477Swpaul val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 26859477Swpaul AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 26959477Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 27059477Swpaul AR_INTR_SYNC_ENABLE_GPIO, val); 27159477Swpaul 27259477Swpaul mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 27359477Swpaul AR_INTR_SYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 27459477Swpaul OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 275114590Sps AR_INTR_SYNC_MASK_GPIO, mask); 27659477Swpaul } 27759477Swpaul AH5416(ah)->ah_gpioMask = mask; /* for ar5416SetInterrupts */ 27859477Swpaul} 27959477Swpaul