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