Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / sys / dev / netif / ath / hal / ath_hal / ar5416 / ar5416_gpio.c
1 /*
2  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3  * Copyright (c) 2002-2008 Atheros Communications, Inc.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 203159 2010-01-29 10:10:14Z rpaulo $
18  * $DragonFly$
19  */
20 #include "opt_ah.h"
21
22 #include "ah.h"
23 #include "ah_internal.h"
24 #include "ah_devid.h"
25
26 #include "ar5416/ar5416.h"
27 #include "ar5416/ar5416reg.h"
28 #include "ar5416/ar5416phy.h"
29
30 #define AR_GPIO_BIT(_gpio)      (1 << _gpio)
31
32 /*
33  * Configure GPIO Output Mux control
34  */
35 static void
36 cfgOutputMux(struct ath_hal *ah, uint32_t gpio, uint32_t type)
37 {
38         int addr;
39         uint32_t gpio_shift, reg;
40
41         /* each MUX controls 6 GPIO pins */
42         if (gpio > 11)
43                 addr = AR_GPIO_OUTPUT_MUX3;
44         else if (gpio > 5)
45                 addr = AR_GPIO_OUTPUT_MUX2;
46         else
47                 addr = AR_GPIO_OUTPUT_MUX1;
48
49         /*
50          * 5 bits per GPIO pin. Bits 0..4 for 1st pin in that mux,
51          * bits 5..9 for 2nd pin, etc.
52          */
53         gpio_shift = (gpio % 6) * 5;
54
55         /*
56          * From Owl to Merlin 1.0, the value read from MUX1 bit 4 to bit
57          * 9 are wrong.  Here is hardware's coding:
58          * PRDATA[4:0] <= gpio_output_mux[0];
59          * PRDATA[9:4] <= gpio_output_mux[1];
60          *      <==== Bit 4 is used by both gpio_output_mux[0] [1].
61          * Currently the max value for gpio_output_mux[] is 6. So bit 4
62          * will never be used.  So it should be fine that bit 4 won't be
63          * able to recover.
64          */
65         reg = OS_REG_READ(ah, addr);
66         if (addr == AR_GPIO_OUTPUT_MUX1 && !AR_SREV_MERLIN_20_OR_LATER(ah))
67                 reg = ((reg & 0x1F0) << 1) | (reg & ~0x1F0);
68         reg &= ~(0x1f << gpio_shift);
69         reg |= type << gpio_shift;
70         OS_REG_WRITE(ah, addr, reg);
71 }
72
73 /*
74  * Configure GPIO Output lines
75  */
76 HAL_BOOL
77 ar5416GpioCfgOutput(struct ath_hal *ah, uint32_t gpio, HAL_GPIO_MUX_TYPE type)
78 {
79         uint32_t gpio_shift, reg;
80
81         HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
82
83         /* NB: type maps directly to hardware */
84         cfgOutputMux(ah, gpio, type);
85         gpio_shift = gpio << 1;                 /* 2 bits per output mode */
86
87         reg = OS_REG_READ(ah, AR_GPIO_OE_OUT);
88         reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift);
89         reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift;
90         OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg);
91
92         return AH_TRUE;
93 }
94  
95 /*
96  * Configure GPIO Input lines
97  */
98 HAL_BOOL
99 ar5416GpioCfgInput(struct ath_hal *ah, uint32_t gpio)
100 {
101         uint32_t gpio_shift, reg;
102
103         HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
104
105         /* TODO: configure input mux for AR5416 */
106         /* If configured as input, set output to tristate */
107         gpio_shift = gpio << 1;
108
109         reg = OS_REG_READ(ah, AR_GPIO_OE_OUT);
110         reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift);
111         reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift;
112         OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg);
113
114         return AH_TRUE;
115 }
116
117 /*
118  * Once configured for I/O - set output lines
119  */
120 HAL_BOOL
121 ar5416GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val)
122 {
123         uint32_t reg;
124
125         HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
126
127         reg = OS_REG_READ(ah, AR_GPIO_IN_OUT);
128         if (val & 1)
129                 reg |= AR_GPIO_BIT(gpio);
130         else 
131                 reg &= ~AR_GPIO_BIT(gpio);
132         OS_REG_WRITE(ah, AR_GPIO_IN_OUT, reg);  
133         return AH_TRUE;
134 }
135
136 /*
137  * Once configured for I/O - get input lines
138  */
139 uint32_t
140 ar5416GpioGet(struct ath_hal *ah, uint32_t gpio)
141 {
142         uint32_t bits;
143
144         if (gpio >= AH_PRIVATE(ah)->ah_caps.halNumGpioPins)
145                 return 0xffffffff;
146         /*
147          * Read output value for all gpio's, shift it,
148          * and verify whether the specific bit is set.
149          */
150         if (AR_SREV_KITE_10_OR_LATER(ah))
151                 bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL);
152         else if (AR_SREV_MERLIN_10_OR_LATER(ah))
153                 bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR928X_GPIO_IN_VAL);
154         else
155                 bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL);
156         return ((bits & AR_GPIO_BIT(gpio)) != 0);
157 }
158
159 /*
160  * Set the GPIO Interrupt Sync and Async interrupts are both set/cleared.
161  * Async GPIO interrupts may not be raised when the chip is put to sleep.
162  */
163 void
164 ar5416GpioSetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel)
165 {
166         uint32_t val, mask;
167
168         HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
169
170         if (ilevel == HAL_GPIO_INTR_DISABLE) {
171                 val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE),
172                          AR_INTR_ASYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio);
173                 OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE,
174                     AR_INTR_ASYNC_ENABLE_GPIO, val);
175
176                 mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK),
177                           AR_INTR_ASYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio);
178                 OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK,
179                     AR_INTR_ASYNC_MASK_GPIO, mask);
180
181                 /* Clear synchronous GPIO interrupt registers and pending interrupt flag */
182                 val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE),
183                          AR_INTR_SYNC_ENABLE_GPIO) &~ AR_GPIO_BIT(gpio);
184                 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE,
185                     AR_INTR_SYNC_ENABLE_GPIO, val);
186
187                 mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK),
188                           AR_INTR_SYNC_MASK_GPIO) &~ AR_GPIO_BIT(gpio);
189                 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK,
190                     AR_INTR_SYNC_MASK_GPIO, mask);
191
192                 val = MS(OS_REG_READ(ah, AR_INTR_SYNC_CAUSE),
193                          AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio);
194                 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_CAUSE,
195                     AR_INTR_SYNC_ENABLE_GPIO, val);
196         } else {
197                 val = MS(OS_REG_READ(ah, AR_GPIO_INTR_POL),
198                          AR_GPIO_INTR_POL_VAL);
199                 if (ilevel == HAL_GPIO_INTR_HIGH) {
200                         /* 0 == interrupt on pin high */
201                         val &= ~AR_GPIO_BIT(gpio);
202                 } else if (ilevel == HAL_GPIO_INTR_LOW) {
203                         /* 1 == interrupt on pin low */
204                         val |= AR_GPIO_BIT(gpio);
205                 }
206                 OS_REG_RMW_FIELD(ah, AR_GPIO_INTR_POL,
207                     AR_GPIO_INTR_POL_VAL, val);
208
209                 /* Change the interrupt mask. */
210                 val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE),
211                          AR_INTR_ASYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio);
212                 OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_ENABLE,
213                     AR_INTR_ASYNC_ENABLE_GPIO, val);
214
215                 mask = MS(OS_REG_READ(ah, AR_INTR_ASYNC_MASK),
216                           AR_INTR_ASYNC_MASK_GPIO) | AR_GPIO_BIT(gpio);
217                 OS_REG_RMW_FIELD(ah, AR_INTR_ASYNC_MASK,
218                     AR_INTR_ASYNC_MASK_GPIO, mask);
219
220                 /* Set synchronous GPIO interrupt registers as well */
221                 val = MS(OS_REG_READ(ah, AR_INTR_SYNC_ENABLE),
222                          AR_INTR_SYNC_ENABLE_GPIO) | AR_GPIO_BIT(gpio);
223                 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_ENABLE,
224                     AR_INTR_SYNC_ENABLE_GPIO, val);
225
226                 mask = MS(OS_REG_READ(ah, AR_INTR_SYNC_MASK),
227                           AR_INTR_SYNC_MASK_GPIO) | AR_GPIO_BIT(gpio);
228                 OS_REG_RMW_FIELD(ah, AR_INTR_SYNC_MASK,
229                     AR_INTR_SYNC_MASK_GPIO, mask);
230         }
231         AH5416(ah)->ah_gpioMask = mask;         /* for ar5416SetInterrupts */
232 }