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: releng/10.3/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 237611 2012-06-26 22:16:53Z adrian $ 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; 38228836Sadrian uint32_t gpio_shift, tmp; 39188976Ssam 40228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, "%s: gpio=%d, type=%d\n", 41228836Sadrian __func__, gpio, type); 42228836Sadrian 43188976Ssam /* each MUX controls 6 GPIO pins */ 44188976Ssam if (gpio > 11) 45188976Ssam addr = AR_GPIO_OUTPUT_MUX3; 46188976Ssam else if (gpio > 5) 47188976Ssam addr = AR_GPIO_OUTPUT_MUX2; 48188976Ssam else 49188976Ssam addr = AR_GPIO_OUTPUT_MUX1; 50188976Ssam 51188976Ssam /* 52188976Ssam * 5 bits per GPIO pin. Bits 0..4 for 1st pin in that mux, 53188976Ssam * bits 5..9 for 2nd pin, etc. 54188976Ssam */ 55188976Ssam gpio_shift = (gpio % 6) * 5; 56188976Ssam 57188976Ssam /* 58188976Ssam * From Owl to Merlin 1.0, the value read from MUX1 bit 4 to bit 59188976Ssam * 9 are wrong. Here is hardware's coding: 60188976Ssam * PRDATA[4:0] <= gpio_output_mux[0]; 61188976Ssam * PRDATA[9:4] <= gpio_output_mux[1]; 62188976Ssam * <==== Bit 4 is used by both gpio_output_mux[0] [1]. 63188976Ssam * Currently the max value for gpio_output_mux[] is 6. So bit 4 64188976Ssam * will never be used. So it should be fine that bit 4 won't be 65188976Ssam * able to recover. 66188976Ssam */ 67228836Sadrian if (AR_SREV_MERLIN_20_OR_LATER(ah) || 68228836Sadrian (addr != AR_GPIO_OUTPUT_MUX1)) { 69228836Sadrian OS_REG_RMW(ah, addr, (type << gpio_shift), 70228836Sadrian (0x1f << gpio_shift)); 71228836Sadrian } else { 72228836Sadrian tmp = OS_REG_READ(ah, addr); 73228836Sadrian tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); 74228836Sadrian tmp &= ~(0x1f << gpio_shift); 75228836Sadrian tmp |= type << gpio_shift; 76228836Sadrian OS_REG_WRITE(ah, addr, tmp); 77228836Sadrian } 78188976Ssam} 79188976Ssam 80188976Ssam/* 81185377Ssam * Configure GPIO Output lines 82185377Ssam */ 83185377SsamHAL_BOOL 84188974Ssamar5416GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type) 85185377Ssam{ 86188976Ssam uint32_t gpio_shift, reg; 87188976Ssam 88237611Sadrian#define N(a) (sizeof(a) / sizeof(a[0])) 89237611Sadrian 90188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 91188976Ssam 92237611Sadrian /* 93237611Sadrian * This table maps the HAL GPIO pins to the actual hardware 94237611Sadrian * values. 95237611Sadrian */ 96237611Sadrian static const u_int32_t MuxSignalConversionTable[] = { 97237611Sadrian AR_GPIO_OUTPUT_MUX_AS_OUTPUT, 98237611Sadrian AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, 99237611Sadrian AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, 100237611Sadrian AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, 101237611Sadrian AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, 102237611Sadrian AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL, 103237611Sadrian AR_GPIO_OUTPUT_MUX_AS_TX_FRAME, 104237611Sadrian }; 105237611Sadrian 106228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, 107228836Sadrian "%s: gpio=%d, type=%d\n", __func__, gpio, type); 108228836Sadrian 109237611Sadrian /* 110237611Sadrian * Convert HAL signal type definitions to hardware-specific values. 111237611Sadrian */ 112237611Sadrian if (type >= N(MuxSignalConversionTable)) { 113237611Sadrian ath_hal_printf(ah, "%s: mux %d is invalid!\n", 114237611Sadrian __func__, 115237611Sadrian type); 116237611Sadrian return AH_FALSE; 117237611Sadrian } 118237611Sadrian cfgOutputMux(ah, gpio, MuxSignalConversionTable[type]); 119188976Ssam 120237611Sadrian /* 2 bits per output mode */ 121237611Sadrian gpio_shift = gpio << 1; 122237611Sadrian 123237611Sadrian /* Always drive, rather than tristate/drive low/drive high */ 124188976Ssam reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 125188976Ssam reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 126188993Ssam reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 127188976Ssam OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 128188976Ssam 129185377Ssam return AH_TRUE; 130237611Sadrian#undef N 131185377Ssam} 132188976Ssam 133185377Ssam/* 134185377Ssam * Configure GPIO Input lines 135185377Ssam */ 136185377SsamHAL_BOOL 137185377Ssamar5416GpioCfgInput(struct ath_hal *ah, uint32_t gpio) 138185377Ssam{ 139188976Ssam uint32_t gpio_shift, reg; 140188976Ssam 141188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 142188976Ssam 143228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, "%s: gpio=%d\n", __func__, gpio); 144228836Sadrian 145188976Ssam /* TODO: configure input mux for AR5416 */ 146188976Ssam /* If configured as input, set output to tristate */ 147188976Ssam gpio_shift = gpio << 1; 148188976Ssam 149188976Ssam reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 150188976Ssam reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 151188993Ssam reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 152188976Ssam OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 153188976Ssam 154185377Ssam return AH_TRUE; 155185377Ssam} 156185377Ssam 157185377Ssam/* 158185377Ssam * Once configured for I/O - set output lines 159185377Ssam */ 160185377SsamHAL_BOOL 161185377Ssamar5416GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) 162185377Ssam{ 163185377Ssam uint32_t reg; 164185377Ssam 165188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 166228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, 167228836Sadrian "%s: gpio=%d, val=%d\n", __func__, gpio, val); 168188976Ssam 169188976Ssam reg = OS_REG_READ(ah, AR_GPIO_IN_OUT); 170185377Ssam if (val & 1) 171185377Ssam reg |= AR_GPIO_BIT(gpio); 172185377Ssam else 173185377Ssam reg &= ~AR_GPIO_BIT(gpio); 174188976Ssam OS_REG_WRITE(ah, AR_GPIO_IN_OUT, reg); 175185377Ssam return AH_TRUE; 176185377Ssam} 177185377Ssam 178185377Ssam/* 179185377Ssam * Once configured for I/O - get input lines 180185377Ssam */ 181185377Ssamuint32_t 182185377Ssamar5416GpioGet(struct ath_hal *ah, uint32_t gpio) 183185377Ssam{ 184188976Ssam uint32_t bits; 185188976Ssam 186188976Ssam if (gpio >= AH_PRIVATE(ah)->ah_caps.halNumGpioPins) 187185377Ssam return 0xffffffff; 188188976Ssam /* 189188976Ssam * Read output value for all gpio's, shift it, 190188976Ssam * and verify whether the specific bit is set. 191188976Ssam */ 192228836Sadrian if (AR_SREV_KIWI_10_OR_LATER(ah)) 193228836Sadrian bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9287_GPIO_IN_VAL); 194203159Srpaulo if (AR_SREV_KITE_10_OR_LATER(ah)) 195203159Srpaulo bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL); 196203159Srpaulo else if (AR_SREV_MERLIN_10_OR_LATER(ah)) 197188976Ssam bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL); 198188976Ssam else 199188976Ssam bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL); 200188976Ssam return ((bits & AR_GPIO_BIT(gpio)) != 0); 201185377Ssam} 202185377Ssam 203185377Ssam/* 204188976Ssam * Set the GPIO Interrupt Sync and Async interrupts are both set/cleared. 205188976Ssam * Async GPIO interrupts may not be raised when the chip is put to sleep. 206185377Ssam */ 207185377Ssamvoid 208185377Ssamar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) 209185377Ssam{ 210188976Ssam uint32_t val, mask; 211185377Ssam 212188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 213228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, 214228836Sadrian "%s: gpio=%d, ilevel=%d\n", __func__, gpio, ilevel); 215185377Ssam 216188976Ssam if (ilevel == HAL_GPIO_INTR_DISABLE) { 217188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 218188976Ssam AR_INTR_ASYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 219188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 220188976Ssam AR_INTR_ASYNC_ENABLE_GPIO, val); 221188976Ssam 222188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 223188976Ssam AR_INTR_ASYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 224188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 225188976Ssam AR_INTR_ASYNC_MASK_GPIO, mask); 226188976Ssam 227188976Ssam /* Clear synchronous GPIO interrupt registers and pending interrupt flag */ 228188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 229188976Ssam AR_INTR_SYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 230188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 231188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 232188976Ssam 233188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 234188976Ssam AR_INTR_SYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 235188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 236188976Ssam AR_INTR_SYNC_MASK_GPIO, mask); 237188976Ssam 238188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_CAUSE), 239188976Ssam AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 240188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_CAUSE, 241188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 242188976Ssam } else { 243188976Ssam val = MS(OS_REG_READ(ah, AR_GPIO_INTR_POL), 244188976Ssam AR_GPIO_INTR_POL_VAL); 245188976Ssam if (ilevel == HAL_GPIO_INTR_HIGH) { 246188976Ssam /* 0 == interrupt on pin high */ 247188976Ssam val &= ~AR_GPIO_BIT(gpio); 248188976Ssam } else if (ilevel == HAL_GPIO_INTR_LOW) { 249188976Ssam /* 1 == interrupt on pin low */ 250188976Ssam val |= AR_GPIO_BIT(gpio); 251188976Ssam } 252188976Ssam OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_POL, 253188976Ssam AR_GPIO_INTR_POL_VAL, val); 254188976Ssam 255188976Ssam /* Change the interrupt mask. */ 256188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 257188976Ssam AR_INTR_ASYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 258188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 259188976Ssam AR_INTR_ASYNC_ENABLE_GPIO, val); 260188976Ssam 261188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 262188976Ssam AR_INTR_ASYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 263188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 264188976Ssam AR_INTR_ASYNC_MASK_GPIO, mask); 265188976Ssam 266188976Ssam /* Set synchronous GPIO interrupt registers as well */ 267188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 268188976Ssam AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 269188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 270188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 271188976Ssam 272188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 273188976Ssam AR_INTR_SYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 274188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 275188976Ssam AR_INTR_SYNC_MASK_GPIO, mask); 276188976Ssam } 277188976Ssam AH5416(ah)->ah_gpioMask = mask; /* for ar5416SetInterrupts */ 278185377Ssam} 279