ar5416_gpio.c revision 228836
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: head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 228836 2011-12-23 08:53:22Z 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 88188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 89188976Ssam 90228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, 91228836Sadrian "%s: gpio=%d, type=%d\n", __func__, gpio, type); 92228836Sadrian 93188976Ssam /* NB: type maps directly to hardware */ 94228836Sadrian /* XXX this may not actually be the case, for anything but output */ 95188976Ssam cfgOutputMux(ah, gpio, type); 96188976Ssam gpio_shift = gpio << 1; /* 2 bits per output mode */ 97188976Ssam 98188976Ssam reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 99188976Ssam reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 100228836Sadrian /* Always drive, rather than tristate/drive low/drive high */ 101188993Ssam reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 102188976Ssam OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 103188976Ssam 104185377Ssam return AH_TRUE; 105185377Ssam} 106188976Ssam 107185377Ssam/* 108185377Ssam * Configure GPIO Input lines 109185377Ssam */ 110185377SsamHAL_BOOL 111185377Ssamar5416GpioCfgInput(struct ath_hal *ah, uint32_t gpio) 112185377Ssam{ 113188976Ssam uint32_t gpio_shift, reg; 114188976Ssam 115188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 116188976Ssam 117228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, "%s: gpio=%d\n", __func__, gpio); 118228836Sadrian 119188976Ssam /* TODO: configure input mux for AR5416 */ 120188976Ssam /* If configured as input, set output to tristate */ 121188976Ssam gpio_shift = gpio << 1; 122188976Ssam 123188976Ssam reg = OS_REG_READ(ah, AR_GPIO_OE_OUT); 124188976Ssam reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift); 125188993Ssam reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift; 126188976Ssam OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg); 127188976Ssam 128185377Ssam return AH_TRUE; 129185377Ssam} 130185377Ssam 131185377Ssam/* 132185377Ssam * Once configured for I/O - set output lines 133185377Ssam */ 134185377SsamHAL_BOOL 135185377Ssamar5416GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) 136185377Ssam{ 137185377Ssam uint32_t reg; 138185377Ssam 139188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 140228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, 141228836Sadrian "%s: gpio=%d, val=%d\n", __func__, gpio, val); 142188976Ssam 143188976Ssam reg = OS_REG_READ(ah, AR_GPIO_IN_OUT); 144185377Ssam if (val & 1) 145185377Ssam reg |= AR_GPIO_BIT(gpio); 146185377Ssam else 147185377Ssam reg &= ~AR_GPIO_BIT(gpio); 148188976Ssam OS_REG_WRITE(ah, AR_GPIO_IN_OUT, reg); 149185377Ssam return AH_TRUE; 150185377Ssam} 151185377Ssam 152185377Ssam/* 153185377Ssam * Once configured for I/O - get input lines 154185377Ssam */ 155185377Ssamuint32_t 156185377Ssamar5416GpioGet(struct ath_hal *ah, uint32_t gpio) 157185377Ssam{ 158188976Ssam uint32_t bits; 159188976Ssam 160188976Ssam if (gpio >= AH_PRIVATE(ah)->ah_caps.halNumGpioPins) 161185377Ssam return 0xffffffff; 162188976Ssam /* 163188976Ssam * Read output value for all gpio's, shift it, 164188976Ssam * and verify whether the specific bit is set. 165188976Ssam */ 166228836Sadrian if (AR_SREV_KIWI_10_OR_LATER(ah)) 167228836Sadrian bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9287_GPIO_IN_VAL); 168203159Srpaulo if (AR_SREV_KITE_10_OR_LATER(ah)) 169203159Srpaulo bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL); 170203159Srpaulo else if (AR_SREV_MERLIN_10_OR_LATER(ah)) 171188976Ssam bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL); 172188976Ssam else 173188976Ssam bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL); 174188976Ssam return ((bits & AR_GPIO_BIT(gpio)) != 0); 175185377Ssam} 176185377Ssam 177185377Ssam/* 178188976Ssam * Set the GPIO Interrupt Sync and Async interrupts are both set/cleared. 179188976Ssam * Async GPIO interrupts may not be raised when the chip is put to sleep. 180185377Ssam */ 181185377Ssamvoid 182185377Ssamar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) 183185377Ssam{ 184188976Ssam uint32_t val, mask; 185185377Ssam 186188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 187228836Sadrian HALDEBUG(ah, HAL_DEBUG_GPIO, 188228836Sadrian "%s: gpio=%d, ilevel=%d\n", __func__, gpio, ilevel); 189185377Ssam 190188976Ssam if (ilevel == HAL_GPIO_INTR_DISABLE) { 191188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 192188976Ssam AR_INTR_ASYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 193188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 194188976Ssam AR_INTR_ASYNC_ENABLE_GPIO, val); 195188976Ssam 196188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 197188976Ssam AR_INTR_ASYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 198188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 199188976Ssam AR_INTR_ASYNC_MASK_GPIO, mask); 200188976Ssam 201188976Ssam /* Clear synchronous GPIO interrupt registers and pending interrupt flag */ 202188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 203188976Ssam AR_INTR_SYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 204188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 205188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 206188976Ssam 207188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 208188976Ssam AR_INTR_SYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 209188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 210188976Ssam AR_INTR_SYNC_MASK_GPIO, mask); 211188976Ssam 212188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_CAUSE), 213188976Ssam AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 214188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_CAUSE, 215188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 216188976Ssam } else { 217188976Ssam val = MS(OS_REG_READ(ah, AR_GPIO_INTR_POL), 218188976Ssam AR_GPIO_INTR_POL_VAL); 219188976Ssam if (ilevel == HAL_GPIO_INTR_HIGH) { 220188976Ssam /* 0 == interrupt on pin high */ 221188976Ssam val &= ~AR_GPIO_BIT(gpio); 222188976Ssam } else if (ilevel == HAL_GPIO_INTR_LOW) { 223188976Ssam /* 1 == interrupt on pin low */ 224188976Ssam val |= AR_GPIO_BIT(gpio); 225188976Ssam } 226188976Ssam OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_POL, 227188976Ssam AR_GPIO_INTR_POL_VAL, val); 228188976Ssam 229188976Ssam /* Change the interrupt mask. */ 230188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 231188976Ssam AR_INTR_ASYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 232188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 233188976Ssam AR_INTR_ASYNC_ENABLE_GPIO, val); 234188976Ssam 235188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 236188976Ssam AR_INTR_ASYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 237188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 238188976Ssam AR_INTR_ASYNC_MASK_GPIO, mask); 239188976Ssam 240188976Ssam /* Set synchronous GPIO interrupt registers as well */ 241188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 242188976Ssam AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 243188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 244188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 245188976Ssam 246188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 247188976Ssam AR_INTR_SYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 248188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 249188976Ssam AR_INTR_SYNC_MASK_GPIO, mask); 250188976Ssam } 251188976Ssam AH5416(ah)->ah_gpioMask = mask; /* for ar5416SetInterrupts */ 252185377Ssam} 253