ar5416_gpio.c revision 188976
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 188976 2009-02-24 00:33:08Z sam $ 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); 88188976Ssam 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); 110188976Ssam 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 */ 149188976Ssam if (AR_SREV_MERLIN_10_OR_LATER(ah)) 150188976Ssam bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL); 151188976Ssam else 152188976Ssam bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL); 153188976Ssam return ((bits & AR_GPIO_BIT(gpio)) != 0); 154185377Ssam} 155185377Ssam 156185377Ssam/* 157188976Ssam * Set the GPIO Interrupt Sync and Async interrupts are both set/cleared. 158188976Ssam * Async GPIO interrupts may not be raised when the chip is put to sleep. 159185377Ssam */ 160185377Ssamvoid 161185377Ssamar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) 162185377Ssam{ 163188976Ssam uint32_t val, mask; 164185377Ssam 165188976Ssam HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); 166185377Ssam 167188976Ssam if (ilevel == HAL_GPIO_INTR_DISABLE) { 168188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 169188976Ssam AR_INTR_ASYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 170188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 171188976Ssam AR_INTR_ASYNC_ENABLE_GPIO, val); 172188976Ssam 173188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 174188976Ssam AR_INTR_ASYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 175188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 176188976Ssam AR_INTR_ASYNC_MASK_GPIO, mask); 177188976Ssam 178188976Ssam /* Clear synchronous GPIO interrupt registers and pending interrupt flag */ 179188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 180188976Ssam AR_INTR_SYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio); 181188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 182188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 183188976Ssam 184188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 185188976Ssam AR_INTR_SYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio); 186188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 187188976Ssam AR_INTR_SYNC_MASK_GPIO, mask); 188188976Ssam 189188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_CAUSE), 190188976Ssam AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 191188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_CAUSE, 192188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 193188976Ssam } else { 194188976Ssam val = MS(OS_REG_READ(ah, AR_GPIO_INTR_POL), 195188976Ssam AR_GPIO_INTR_POL_VAL); 196188976Ssam if (ilevel == HAL_GPIO_INTR_HIGH) { 197188976Ssam /* 0 == interrupt on pin high */ 198188976Ssam val &= ~AR_GPIO_BIT(gpio); 199188976Ssam } else if (ilevel == HAL_GPIO_INTR_LOW) { 200188976Ssam /* 1 == interrupt on pin low */ 201188976Ssam val |= AR_GPIO_BIT(gpio); 202188976Ssam } 203188976Ssam OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_POL, 204188976Ssam AR_GPIO_INTR_POL_VAL, val); 205188976Ssam 206188976Ssam /* Change the interrupt mask. */ 207188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE), 208188976Ssam AR_INTR_ASYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 209188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE, 210188976Ssam AR_INTR_ASYNC_ENABLE_GPIO, val); 211188976Ssam 212188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK), 213188976Ssam AR_INTR_ASYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 214188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK, 215188976Ssam AR_INTR_ASYNC_MASK_GPIO, mask); 216188976Ssam 217188976Ssam /* Set synchronous GPIO interrupt registers as well */ 218188976Ssam val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE), 219188976Ssam AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio); 220188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE, 221188976Ssam AR_INTR_SYNC_ENABLE_GPIO, val); 222188976Ssam 223188976Ssam mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK), 224188976Ssam AR_INTR_SYNC_MASK_GPIO) | AR_GPIO_BIT(gpio); 225188976Ssam OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK, 226188976Ssam AR_INTR_SYNC_MASK_GPIO, mask); 227188976Ssam } 228188976Ssam AH5416(ah)->ah_gpioMask = mask; /* for ar5416SetInterrupts */ 229185377Ssam} 230