diff options
Diffstat (limited to 'sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c')
-rw-r--r-- | sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c | 647 |
1 files changed, 647 insertions, 0 deletions
diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c new file mode 100644 index 0000000..5660c1f --- /dev/null +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c @@ -0,0 +1,647 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "opt_ah.h" + +#include "ah.h" +#include "ah_internal.h" +#include "ah_devid.h" +#ifdef AH_DEBUG +#include "ah_desc.h" /* NB: for HAL_PHYERR* */ +#endif + +#include "ar9300/ar9300.h" +#include "ar9300/ar9300reg.h" +#include "ar9300/ar9300phy.h" + +#define AR_GPIO_BIT(_gpio) (1 << (_gpio)) + +/* + * Configure GPIO Output Mux control + */ +#if UMAC_SUPPORT_SMARTANTENNA +static void ar9340_soc_gpio_cfg_output_mux( + struct ath_hal *ah, + u_int32_t gpio, + u_int32_t ah_signal_type) +{ +#define ADDR_READ(addr) (*((volatile u_int32_t *)(addr))) +#define ADDR_WRITE(addr, b) (void)((*(volatile u_int32_t *) (addr)) = (b)) +#define AR9340_SOC_GPIO_FUN0 0xB804002c +#define AR9340_SOC_GPIO_OE 0xB8040000 +#if ATH_SMARTANTENNA_DISABLE_JTAG +#define AR9340_SOC_GPIO_FUNCTION (volatile u_int32_t*) 0xB804006c +#define WASP_DISABLE_JTAG 0x2 +#define MAX_JTAG_GPIO_PIN 1 +#endif + u_int8_t out_func, shift; + u_int32_t flags; + volatile u_int32_t* address; + + if (!ah_signal_type){ + return; + } +#if ATH_SMARTANTENNA_DISABLE_JTAG +/* + * To use GPIO pins 0 and 1 for controling antennas, JTAG needs to disabled. + */ + if (gpio <= MAX_JTAG_GPIO_PIN) { + flags = ADDR_READ(AR9340_SOC_GPIO_FUNCTION); + flags |= WASP_DISABLE_JTAG; + ADDR_WRITE(AR9340_SOC_GPIO_FUNCTION, flags); + } +#endif + out_func = gpio / 4; + shift = (gpio % 4); + address = (volatile u_int32_t *)(AR9340_SOC_GPIO_FUN0 + (out_func*4)); + + flags = ADDR_READ(address); + flags |= ah_signal_type << (8*shift); + ADDR_WRITE(address, flags); + flags = ADDR_READ(AR9340_SOC_GPIO_OE); + flags &= ~(1 << gpio); + ADDR_WRITE(AR9340_SOC_GPIO_OE, flags); + +} +#endif + +static void +ar9300_gpio_cfg_output_mux(struct ath_hal *ah, u_int32_t gpio, u_int32_t type) +{ + int addr; + u_int32_t gpio_shift; + + /* each MUX controls 6 GPIO pins */ + if (gpio > 11) { + addr = AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX3); + } else if (gpio > 5) { + addr = AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX2); + } else { + addr = AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1); + } + + /* + * 5 bits per GPIO pin. + * Bits 0..4 for 1st pin in that mux, + * bits 5..9 for 2nd pin, etc. + */ + gpio_shift = (gpio % 6) * 5; + + OS_REG_RMW(ah, addr, (type << gpio_shift), (0x1f << gpio_shift)); +} + +/* + * Configure GPIO Output lines + */ +HAL_BOOL +ar9300_gpio_cfg_output( + struct ath_hal *ah, + u_int32_t gpio, + HAL_GPIO_MUX_TYPE hal_signal_type) +{ + u_int32_t ah_signal_type; + u_int32_t gpio_shift; + u_int8_t smart_ant = 0; + static const u_int32_t mux_signal_conversion_table[] = { + /* HAL_GPIO_OUTPUT_MUX_AS_OUTPUT */ + AR_GPIO_OUTPUT_MUX_AS_OUTPUT, + /* HAL_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED */ + AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, + /* HAL_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED */ + AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, + /* HAL_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED */ + AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, + /* HAL_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED */ + AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, + /* HAL_GPIO_OUTPUT_MUX_AS_WLAN_ACTIVE */ + AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL, + /* HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME */ + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME, + /* HAL_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA */ + AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA, + /* HAL_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK */ + AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK, + /* HAL_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA */ + AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA, + /* HAL_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK */ + AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK, + /* HAL_GPIO_OUTPUT_MUX_AS_WL_IN_TX */ + AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX, + /* HAL_GPIO_OUTPUT_MUX_AS_WL_IN_RX */ + AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX, + /* HAL_GPIO_OUTPUT_MUX_AS_BT_IN_TX */ + AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX, + /* HAL_GPIO_OUTPUT_MUX_AS_BT_IN_RX */ + AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX, + /* HAL_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE */ + AR_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE, + /* HAL_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA */ + AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA, + /* HAL_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL0 */ + AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL0, + /* HAL_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL1 */ + AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL1, + /* HAL_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL2 */ + AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL2, + /* HAL_GPIO_OUTPUT_MUX_AS_SMARTANT_SWCOM3 */ + AR_GPIO_OUTPUT_MUX_AS_SWCOM3, + }; + + HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); + if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || + (gpio == AR9382_GPIO_PIN_11_RESERVED) || + (gpio == AR9382_GPIO_9_INPUT_ONLY)) + { + return AH_FALSE; + } + + /* Convert HAL signal type definitions to hardware-specific values. */ + if ((int) hal_signal_type < ARRAY_LENGTH(mux_signal_conversion_table)) + { + ah_signal_type = mux_signal_conversion_table[hal_signal_type]; + } else { + return AH_FALSE; + } + + if (gpio <= AR9382_MAX_JTAG_GPIO_PIN_NUM) { + OS_REG_SET_BIT(ah, + AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE); + } + +#if UMAC_SUPPORT_SMARTANTENNA + /* Get the pin and func values for smart antenna */ + switch (ah_signal_type) + { + case AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL0: + gpio = ATH_GPIOPIN_ANTCHAIN0; + ah_signal_type = ATH_GPIOFUNC_ANTCHAIN0; + smart_ant = 1; + break; + case AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL1: + gpio = ATH_GPIOPIN_ANTCHAIN1; + ah_signal_type = ATH_GPIOFUNC_ANTCHAIN1; + smart_ant = 1; + break; + case AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL2: + gpio = ATH_GPIOPIN_ANTCHAIN2; + ah_signal_type = ATH_GPIOFUNC_ANTCHAIN2; + smart_ant = 1; + break; +#if ATH_SMARTANTENNA_ROUTE_SWCOM_TO_GPIO + case AR_GPIO_OUTPUT_MUX_AS_SWCOM3: + gpio = ATH_GPIOPIN_ROUTE_SWCOM3; + ah_signal_type = ATH_GPIOFUNC_ROUTE_SWCOM3; + smart_ant = 1; + break; +#endif + default: + break; + } +#endif + + if (smart_ant && (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah))) + { +#if UMAC_SUPPORT_SMARTANTENNA + ar9340_soc_gpio_cfg_output_mux(ah, gpio, ah_signal_type); +#endif + return AH_TRUE; + } else + { + /* Configure the MUX */ + ar9300_gpio_cfg_output_mux(ah, gpio, ah_signal_type); + } + + /* 2 bits per output mode */ + gpio_shift = 2 * gpio; + + OS_REG_RMW(ah, + AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT), + (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); + return AH_TRUE; +} + +/* + * Configure GPIO Output lines -LED off + */ +HAL_BOOL +ar9300_gpio_cfg_output_led_off( + struct ath_hal *ah, + u_int32_t gpio, + HAL_GPIO_MUX_TYPE halSignalType) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + u_int32_t ah_signal_type; + u_int32_t gpio_shift; + u_int8_t smart_ant = 0; + + static const u_int32_t mux_signal_conversion_table[] = { + /* HAL_GPIO_OUTPUT_MUX_AS_OUTPUT */ + AR_GPIO_OUTPUT_MUX_AS_OUTPUT, + /* HAL_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED */ + AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, + /* HAL_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED */ + AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, + /* HAL_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED */ + AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, + /* HAL_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED */ + AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, + /* HAL_GPIO_OUTPUT_MUX_AS_WLAN_ACTIVE */ + AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL, + /* HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME */ + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME, + /* HAL_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA */ + AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA, + /* HAL_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK */ + AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK, + /* HAL_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA */ + AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA, + /* HAL_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK */ + AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK, + /* HAL_GPIO_OUTPUT_MUX_AS_WL_IN_TX */ + AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX, + /* HAL_GPIO_OUTPUT_MUX_AS_WL_IN_RX */ + AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX, + /* HAL_GPIO_OUTPUT_MUX_AS_BT_IN_TX */ + AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX, + /* HAL_GPIO_OUTPUT_MUX_AS_BT_IN_RX */ + AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX, + AR_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE, + AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA, + AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL0, + AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL1, + AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL2 + }; + HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.hal_num_gpio_pins); + + /* Convert HAL signal type definitions to hardware-specific values. */ + if ((int) halSignalType < ARRAY_LENGTH(mux_signal_conversion_table)) + { + ah_signal_type = mux_signal_conversion_table[halSignalType]; + } else { + return AH_FALSE; + } +#if UMAC_SUPPORT_SMARTANTENNA + /* Get the pin and func values for smart antenna */ + switch (halSignalType) + { + case AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL0: + gpio = ATH_GPIOPIN_ANTCHAIN0; + ah_signal_type = ATH_GPIOFUNC_ANTCHAIN0; + smart_ant = 1; + break; + case AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL1: + gpio = ATH_GPIOPIN_ANTCHAIN1; + ah_signal_type = ATH_GPIOFUNC_ANTCHAIN1; + smart_ant = 1; + break; + case AR_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL2: + gpio = ATH_GPIOPIN_ANTCHAIN2; + ah_signal_type = ATH_GPIOFUNC_ANTCHAIN2; + smart_ant = 1; + break; + default: + break; + } +#endif + + if (smart_ant && AR_SREV_WASP(ah)) + { + return AH_FALSE; + } + + // Configure the MUX + ar9300_gpio_cfg_output_mux(ah, gpio, ah_signal_type); + + // 2 bits per output mode + gpio_shift = 2*gpio; + + OS_REG_RMW(ah, + AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT), + (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); + + return AH_TRUE; +#undef N +} + +/* + * Configure GPIO Input lines + */ +HAL_BOOL +ar9300_gpio_cfg_input(struct ath_hal *ah, u_int32_t gpio) +{ + u_int32_t gpio_shift; + + HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); + if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || + (gpio == AR9382_GPIO_PIN_11_RESERVED) || + (gpio > AR9382_MAX_GPIO_INPUT_PIN_NUM)) + { + return AH_FALSE; + } + + if (gpio <= AR9382_MAX_JTAG_GPIO_PIN_NUM) { + OS_REG_SET_BIT(ah, + AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE); + } + /* TODO: configure input mux for AR9300 */ + /* If configured as input, set output to tristate */ + gpio_shift = 2 * gpio; + + OS_REG_RMW(ah, + AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT), + (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); + return AH_TRUE; +} + +/* + * Once configured for I/O - set output lines + * output the level of GPio PIN without care work mode + */ +HAL_BOOL +ar9300_gpio_set(struct ath_hal *ah, u_int32_t gpio, u_int32_t val) +{ + HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); + if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || + (gpio == AR9382_GPIO_PIN_11_RESERVED) || + (gpio == AR9382_GPIO_9_INPUT_ONLY)) + { + return AH_FALSE; + } + OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUT), + ((val & 1) << gpio), AR_GPIO_BIT(gpio)); + + return AH_TRUE; +} + +/* + * Once configured for I/O - get input lines + */ +u_int32_t +ar9300_gpio_get(struct ath_hal *ah, u_int32_t gpio) +{ + u_int32_t gpio_in; + HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); + if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || + (gpio == AR9382_GPIO_PIN_11_RESERVED)) + { + return 0xffffffff; + } + + gpio_in = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_IN)); + OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_IN), + (1 << gpio), AR_GPIO_BIT(gpio)); + return (MS(gpio_in, AR_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; +} + +u_int32_t +ar9300_gpio_get_intr(struct ath_hal *ah) +{ + unsigned int mask = 0; + struct ath_hal_9300 *ahp = AH9300(ah); + + mask = ahp->ah_gpio_cause; + return mask; +} + +/* + * Set the GPIO Interrupt + * Sync and Async interrupts are both set/cleared. + * Async GPIO interrupts may not be raised when the chip is put to sleep. + */ +void +ar9300_gpio_set_intr(struct ath_hal *ah, u_int gpio, u_int32_t ilevel) +{ + + + int i, reg_bit; + u_int32_t reg_val; + u_int32_t regs[2], shifts[2]; + +#ifdef AH_ASSERT + u_int32_t gpio_mask; + u_int32_t old_field_val = 0, field_val = 0; +#endif + +#ifdef ATH_GPIO_USE_ASYNC_CAUSE + regs[0] = AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE); + regs[1] = AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK); + shifts[0] = AR_INTR_ASYNC_ENABLE_GPIO_S; + shifts[1] = AR_INTR_ASYNC_MASK_GPIO_S; +#else + regs[0] = AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE); + regs[1] = AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK); + shifts[0] = AR_INTR_SYNC_ENABLE_GPIO_S; + shifts[1] = AR_INTR_SYNC_MASK_GPIO_S; +#endif + + HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); + + if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || + (gpio == AR9382_GPIO_PIN_11_RESERVED) || + (gpio > AR9382_MAX_GPIO_INPUT_PIN_NUM)) + { + return; + } + +#ifdef AH_ASSERT + gpio_mask = (1 << AH_PRIVATE(ah)->ah_caps.halNumGpioPins) - 1; +#endif + if (ilevel == HAL_GPIO_INTR_DISABLE) { + /* clear this GPIO's bit in the interrupt registers */ + for (i = 0; i < ARRAY_LENGTH(regs); i++) { + reg_val = OS_REG_READ(ah, regs[i]); + reg_bit = shifts[i] + gpio; + reg_val &= ~(1 << reg_bit); + OS_REG_WRITE(ah, regs[i], reg_val); + + /* check that each register has same GPIOs enabled */ +#ifdef AH_ASSERT + field_val = (reg_val >> shifts[i]) & gpio_mask; + HALASSERT(i == 0 || old_field_val == field_val); + old_field_val = field_val; +#endif + } + + } else { + reg_val = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL)); + reg_bit = gpio; + if (ilevel == HAL_GPIO_INTR_HIGH) { + /* 0 == interrupt on pin high */ + reg_val &= ~(1 << reg_bit); + } else if (ilevel == HAL_GPIO_INTR_LOW) { + /* 1 == interrupt on pin low */ + reg_val |= (1 << reg_bit); + } + OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL), reg_val); + + /* set this GPIO's bit in the interrupt registers */ + for (i = 0; i < ARRAY_LENGTH(regs); i++) { + reg_val = OS_REG_READ(ah, regs[i]); + reg_bit = shifts[i] + gpio; + reg_val |= (1 << reg_bit); + OS_REG_WRITE(ah, regs[i], reg_val); + + /* check that each register has same GPIOs enabled */ +#ifdef AH_ASSERT + field_val = (reg_val >> shifts[i]) & gpio_mask; + HALASSERT(i == 0 || old_field_val == field_val); + old_field_val = field_val; +#endif + } + } +} + +u_int32_t +ar9300_gpio_get_polarity(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL)); + +} + +void +ar9300_gpio_set_polarity(struct ath_hal *ah, u_int32_t pol_map, + u_int32_t changed_mask) +{ + u_int32_t gpio_mask; + + gpio_mask = (1 << AH_PRIVATE(ah)->ah_caps.halNumGpioPins) - 1; + OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL), gpio_mask & pol_map); + +#ifndef ATH_GPIO_USE_ASYNC_CAUSE + /* + * For SYNC_CAUSE type interrupts, we need to clear the cause register + * explicitly. Otherwise an interrupt with the original polarity setting + * will come up immediately (if there is already an interrupt source), + * which is not what we want usually. + */ + OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR), + changed_mask << AR_INTR_SYNC_ENABLE_GPIO_S); + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE_CLR)); +#endif +} + +/* + * get the GPIO input pin mask + * gpio0 - gpio13 + * gpio8, gpio11, regard as reserved by the chip ar9382 + */ + +u_int32_t +ar9300_gpio_get_mask(struct ath_hal *ah) +{ + u_int32_t mask = (1 << (AR9382_MAX_GPIO_INPUT_PIN_NUM + 1) ) - 1; + + if (AH_PRIVATE(ah)->ah_devid == AR9300_DEVID_AR9380_PCIE) { + mask = (1 << AR9382_MAX_GPIO_PIN_NUM) - 1; + mask &= ~(1 << AR9382_GPIO_PIN_8_RESERVED | + 1 << AR9382_GPIO_PIN_11_RESERVED); + } + return mask; +} + +int +ar9300_gpio_set_mask(struct ath_hal *ah, u_int32_t mask, u_int32_t pol_map) +{ + u_int32_t invalid = ~((1 << (AR9382_MAX_GPIO_INPUT_PIN_NUM + 1)) - 1); + + if (AH_PRIVATE(ah)->ah_devid == AR9300_DEVID_AR9380_PCIE) { + invalid = ~((1 << AR9382_MAX_GPIO_PIN_NUM) - 1); + invalid |= 1 << AR9382_GPIO_PIN_8_RESERVED | + 1 << AR9382_GPIO_PIN_11_RESERVED; + } + if (mask & invalid) { + ath_hal_printf(ah, "%s: invalid GPIO mask 0x%x\n", __func__, mask); + return -1; + } + AH9300(ah)->ah_gpio_mask = mask; + OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL), mask & pol_map); + + return 0; +} + +#ifdef AH_DEBUG +void ar9300_gpio_show(struct ath_hal *ah); +void ar9300_gpio_show(struct ath_hal *ah) +{ + ath_hal_printf(ah, "--- 9382 GPIOs ---(ah=%p)\n", ah ); + ath_hal_printf(ah, + "AH9300(_ah)->ah_hostifregs:%p\r\n", &(AH9300(ah)->ah_hostifregs)); + ath_hal_printf(ah, + "GPIO_OUT: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUT))); + ath_hal_printf(ah, + "GPIO_IN: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_IN))); + ath_hal_printf(ah, + "GPIO_OE: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OE_OUT))); + ath_hal_printf(ah, + "GPIO_OE1_OUT: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OE1_OUT))); + ath_hal_printf(ah, + "GPIO_INTR_POLAR: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_INTR_POL))); + ath_hal_printf(ah, + "GPIO_INPUT_VALUE: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL))); + ath_hal_printf(ah, + "GPIO_INPUT_MUX1: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_INPUT_MUX1))); + ath_hal_printf(ah, + "GPIO_INPUT_MUX2: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_INPUT_MUX2))); + ath_hal_printf(ah, + "GPIO_OUTPUT_MUX1: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1))); + ath_hal_printf(ah, + "GPIO_OUTPUT_MUX2: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX2))); + ath_hal_printf(ah, + "GPIO_OUTPUT_MUX3: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX3))); + ath_hal_printf(ah, + "GPIO_INPUT_STATE: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INPUT_STATE))); + ath_hal_printf(ah, + "GPIO_PDPU: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_PDPU))); + ath_hal_printf(ah, + "GPIO_DS: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_GPIO_DS))); + ath_hal_printf(ah, + "AR_INTR_ASYNC_ENABLE: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_ENABLE))); + ath_hal_printf(ah, + "AR_INTR_ASYNC_MASK: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_MASK))); + ath_hal_printf(ah, + "AR_INTR_SYNC_ENABLE: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE))); + ath_hal_printf(ah, + "AR_INTR_SYNC_MASK: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK))); + ath_hal_printf(ah, + "AR_INTR_ASYNC_CAUSE: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_ASYNC_CAUSE))); + ath_hal_printf(ah, + "AR_INTR_SYNC_CAUSE: 0x%08X\n", + OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE))); + +} +#endif /*AH_DEBUG*/ |