Commit | Line | Data |
---|---|---|
9569dae7 LB |
1 | /* |
2 | * arch/arm/plat-orion/gpio.c | |
3 | * | |
4 | * Marvell Orion SoC GPIO handling. | |
5 | * | |
6 | * This file is licensed under the terms of the GNU General Public | |
7 | * License version 2. This program is licensed "as is" without any | |
8 | * warranty of any kind, whether express or implied. | |
9 | */ | |
10 | ||
11 | #include <linux/kernel.h> | |
12 | #include <linux/init.h> | |
07332318 | 13 | #include <linux/irq.h> |
9569dae7 LB |
14 | #include <linux/module.h> |
15 | #include <linux/spinlock.h> | |
16 | #include <linux/bitops.h> | |
17 | #include <linux/io.h> | |
a8865655 | 18 | #include <linux/gpio.h> |
9569dae7 LB |
19 | |
20 | static DEFINE_SPINLOCK(gpio_lock); | |
28d27cf4 NP |
21 | static unsigned long gpio_valid_input[BITS_TO_LONGS(GPIO_MAX)]; |
22 | static unsigned long gpio_valid_output[BITS_TO_LONGS(GPIO_MAX)]; | |
9569dae7 LB |
23 | |
24 | static inline void __set_direction(unsigned pin, int input) | |
25 | { | |
26 | u32 u; | |
27 | ||
28 | u = readl(GPIO_IO_CONF(pin)); | |
29 | if (input) | |
30 | u |= 1 << (pin & 31); | |
31 | else | |
32 | u &= ~(1 << (pin & 31)); | |
33 | writel(u, GPIO_IO_CONF(pin)); | |
34 | } | |
35 | ||
36 | static void __set_level(unsigned pin, int high) | |
37 | { | |
38 | u32 u; | |
39 | ||
40 | u = readl(GPIO_OUT(pin)); | |
41 | if (high) | |
42 | u |= 1 << (pin & 31); | |
43 | else | |
44 | u &= ~(1 << (pin & 31)); | |
45 | writel(u, GPIO_OUT(pin)); | |
46 | } | |
47 | ||
a8865655 | 48 | static inline void __set_blinking(unsigned pin, int blink) |
9569dae7 | 49 | { |
a8865655 | 50 | u32 u; |
9569dae7 | 51 | |
a8865655 EB |
52 | u = readl(GPIO_BLINK_EN(pin)); |
53 | if (blink) | |
54 | u |= 1 << (pin & 31); | |
55 | else | |
56 | u &= ~(1 << (pin & 31)); | |
57 | writel(u, GPIO_BLINK_EN(pin)); | |
58 | } | |
9569dae7 | 59 | |
a8865655 EB |
60 | static inline int orion_gpio_is_valid(unsigned pin, int mode) |
61 | { | |
62 | if (pin < GPIO_MAX) { | |
63 | if ((mode & GPIO_INPUT_OK) && !test_bit(pin, gpio_valid_input)) | |
64 | goto err_out; | |
65 | if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, gpio_valid_output)) | |
66 | goto err_out; | |
67 | return true; | |
68 | } | |
9569dae7 | 69 | |
a8865655 EB |
70 | err_out: |
71 | pr_debug("%s: invalid GPIO %d\n", __func__, pin); | |
72 | return false; | |
9569dae7 | 73 | } |
9569dae7 | 74 | |
a8865655 EB |
75 | /* |
76 | * GENERIC_GPIO primitives. | |
77 | */ | |
78 | static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin) | |
9569dae7 LB |
79 | { |
80 | unsigned long flags; | |
9569dae7 | 81 | |
a8865655 | 82 | if (!orion_gpio_is_valid(pin, GPIO_INPUT_OK)) |
9569dae7 | 83 | return -EINVAL; |
9569dae7 LB |
84 | |
85 | spin_lock_irqsave(&gpio_lock, flags); | |
86 | ||
a8865655 EB |
87 | /* Configure GPIO direction. */ |
88 | __set_direction(pin, 1); | |
9569dae7 LB |
89 | |
90 | spin_unlock_irqrestore(&gpio_lock, flags); | |
91 | ||
92 | return 0; | |
93 | } | |
9569dae7 | 94 | |
a8865655 | 95 | static int orion_gpio_get_value(struct gpio_chip *chip, unsigned pin) |
9569dae7 LB |
96 | { |
97 | int val; | |
98 | ||
99 | if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31))) | |
100 | val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin)); | |
101 | else | |
102 | val = readl(GPIO_OUT(pin)); | |
103 | ||
104 | return (val >> (pin & 31)) & 1; | |
105 | } | |
9569dae7 | 106 | |
a8865655 EB |
107 | static int orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, |
108 | int value) | |
9569dae7 LB |
109 | { |
110 | unsigned long flags; | |
a8865655 EB |
111 | |
112 | if (!orion_gpio_is_valid(pin, GPIO_OUTPUT_OK)) | |
113 | return -EINVAL; | |
9569dae7 LB |
114 | |
115 | spin_lock_irqsave(&gpio_lock, flags); | |
116 | ||
a8865655 EB |
117 | /* Disable blinking. */ |
118 | __set_blinking(pin, 0); | |
9569dae7 | 119 | |
a8865655 | 120 | /* Configure GPIO output value. */ |
9569dae7 LB |
121 | __set_level(pin, value); |
122 | ||
a8865655 EB |
123 | /* Configure GPIO direction. */ |
124 | __set_direction(pin, 0); | |
125 | ||
9569dae7 | 126 | spin_unlock_irqrestore(&gpio_lock, flags); |
a8865655 EB |
127 | |
128 | return 0; | |
9569dae7 | 129 | } |
9569dae7 | 130 | |
a8865655 EB |
131 | static void orion_gpio_set_value(struct gpio_chip *chip, unsigned pin, |
132 | int value) | |
9569dae7 LB |
133 | { |
134 | unsigned long flags; | |
9569dae7 LB |
135 | |
136 | spin_lock_irqsave(&gpio_lock, flags); | |
9569dae7 | 137 | |
a8865655 EB |
138 | /* Configure GPIO output value. */ |
139 | __set_level(pin, value); | |
140 | ||
141 | spin_unlock_irqrestore(&gpio_lock, flags); | |
9569dae7 | 142 | } |
9569dae7 | 143 | |
a8865655 | 144 | static int orion_gpio_request(struct gpio_chip *chip, unsigned pin) |
9569dae7 | 145 | { |
a8865655 EB |
146 | if (orion_gpio_is_valid(pin, GPIO_INPUT_OK) || |
147 | orion_gpio_is_valid(pin, GPIO_OUTPUT_OK)) | |
148 | return 0; | |
149 | return -EINVAL; | |
9569dae7 | 150 | } |
9569dae7 | 151 | |
a8865655 EB |
152 | static struct gpio_chip orion_gpiochip = { |
153 | .label = "orion_gpio", | |
154 | .direction_input = orion_gpio_direction_input, | |
155 | .get = orion_gpio_get_value, | |
156 | .direction_output = orion_gpio_direction_output, | |
157 | .set = orion_gpio_set_value, | |
158 | .request = orion_gpio_request, | |
159 | .base = 0, | |
160 | .ngpio = GPIO_MAX, | |
161 | .can_sleep = 0, | |
162 | }; | |
163 | ||
164 | void __init orion_gpio_init(void) | |
165 | { | |
166 | gpiochip_add(&orion_gpiochip); | |
167 | } | |
9569dae7 LB |
168 | |
169 | /* | |
170 | * Orion-specific GPIO API extensions. | |
171 | */ | |
172 | void __init orion_gpio_set_unused(unsigned pin) | |
173 | { | |
a8865655 | 174 | /* Configure as output, drive low. */ |
9569dae7 LB |
175 | __set_level(pin, 0); |
176 | __set_direction(pin, 0); | |
177 | } | |
178 | ||
28d27cf4 | 179 | void __init orion_gpio_set_valid(unsigned pin, int mode) |
9569dae7 | 180 | { |
28d27cf4 NP |
181 | if (mode == 1) |
182 | mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK; | |
183 | if (mode & GPIO_INPUT_OK) | |
184 | __set_bit(pin, gpio_valid_input); | |
9569dae7 | 185 | else |
28d27cf4 NP |
186 | __clear_bit(pin, gpio_valid_input); |
187 | if (mode & GPIO_OUTPUT_OK) | |
188 | __set_bit(pin, gpio_valid_output); | |
189 | else | |
190 | __clear_bit(pin, gpio_valid_output); | |
9569dae7 LB |
191 | } |
192 | ||
193 | void orion_gpio_set_blink(unsigned pin, int blink) | |
194 | { | |
195 | unsigned long flags; | |
9569dae7 LB |
196 | |
197 | spin_lock_irqsave(&gpio_lock, flags); | |
198 | ||
a8865655 | 199 | /* Set output value to zero. */ |
9569dae7 LB |
200 | __set_level(pin, 0); |
201 | ||
a8865655 EB |
202 | /* Set blinking. */ |
203 | __set_blinking(pin, blink); | |
9569dae7 LB |
204 | |
205 | spin_unlock_irqrestore(&gpio_lock, flags); | |
206 | } | |
207 | EXPORT_SYMBOL(orion_gpio_set_blink); | |
07332318 LB |
208 | |
209 | ||
210 | /***************************************************************************** | |
211 | * Orion GPIO IRQ | |
212 | * | |
213 | * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same | |
214 | * value of the line or the opposite value. | |
215 | * | |
216 | * Level IRQ handlers: DATA_IN is used directly as cause register. | |
217 | * Interrupt are masked by LEVEL_MASK registers. | |
218 | * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. | |
219 | * Interrupt are masked by EDGE_MASK registers. | |
220 | * Both-edge handlers: Similar to regular Edge handlers, but also swaps | |
221 | * the polarity to catch the next line transaction. | |
222 | * This is a race condition that might not perfectly | |
223 | * work on some use cases. | |
224 | * | |
225 | * Every eight GPIO lines are grouped (OR'ed) before going up to main | |
226 | * cause register. | |
227 | * | |
228 | * EDGE cause mask | |
229 | * data-in /--------| |-----| |----\ | |
230 | * -----| |----- ---- to main cause reg | |
231 | * X \----------------| |----/ | |
232 | * polarity LEVEL mask | |
233 | * | |
234 | ****************************************************************************/ | |
3b0c8d40 | 235 | static void gpio_irq_ack(struct irq_data *d) |
07332318 | 236 | { |
3b0c8d40 | 237 | int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK; |
fd4b9b36 | 238 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { |
3b0c8d40 | 239 | int pin = irq_to_gpio(d->irq); |
fd4b9b36 NP |
240 | writel(~(1 << (pin & 31)), GPIO_EDGE_CAUSE(pin)); |
241 | } | |
07332318 LB |
242 | } |
243 | ||
3b0c8d40 | 244 | static void gpio_irq_mask(struct irq_data *d) |
07332318 | 245 | { |
3b0c8d40 LB |
246 | int pin = irq_to_gpio(d->irq); |
247 | int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK; | |
fd4b9b36 NP |
248 | u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ? |
249 | GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin); | |
250 | u32 u = readl(reg); | |
07332318 | 251 | u &= ~(1 << (pin & 31)); |
fd4b9b36 | 252 | writel(u, reg); |
07332318 LB |
253 | } |
254 | ||
3b0c8d40 | 255 | static void gpio_irq_unmask(struct irq_data *d) |
07332318 | 256 | { |
3b0c8d40 LB |
257 | int pin = irq_to_gpio(d->irq); |
258 | int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK; | |
fd4b9b36 NP |
259 | u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ? |
260 | GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin); | |
261 | u32 u = readl(reg); | |
07332318 | 262 | u |= 1 << (pin & 31); |
fd4b9b36 | 263 | writel(u, reg); |
07332318 LB |
264 | } |
265 | ||
3b0c8d40 | 266 | static int gpio_irq_set_type(struct irq_data *d, u32 type) |
07332318 | 267 | { |
3b0c8d40 | 268 | int pin = irq_to_gpio(d->irq); |
07332318 LB |
269 | struct irq_desc *desc; |
270 | u32 u; | |
271 | ||
272 | u = readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31)); | |
273 | if (!u) { | |
274 | printk(KERN_ERR "orion gpio_irq_set_type failed " | |
3b0c8d40 | 275 | "(irq %d, pin %d).\n", d->irq, pin); |
07332318 LB |
276 | return -EINVAL; |
277 | } | |
278 | ||
3b0c8d40 | 279 | desc = irq_desc + d->irq; |
07332318 LB |
280 | |
281 | /* | |
282 | * Set edge/level type. | |
283 | */ | |
284 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { | |
fd4b9b36 | 285 | desc->handle_irq = handle_edge_irq; |
07332318 | 286 | } else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { |
fd4b9b36 | 287 | desc->handle_irq = handle_level_irq; |
07332318 | 288 | } else { |
3b0c8d40 | 289 | printk(KERN_ERR "failed to set irq=%d (type=%d)\n", d->irq, type); |
07332318 LB |
290 | return -EINVAL; |
291 | } | |
292 | ||
293 | /* | |
294 | * Configure interrupt polarity. | |
295 | */ | |
296 | if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) { | |
297 | u = readl(GPIO_IN_POL(pin)); | |
298 | u &= ~(1 << (pin & 31)); | |
299 | writel(u, GPIO_IN_POL(pin)); | |
300 | } else if (type == IRQ_TYPE_EDGE_FALLING || type == IRQ_TYPE_LEVEL_LOW) { | |
301 | u = readl(GPIO_IN_POL(pin)); | |
302 | u |= 1 << (pin & 31); | |
303 | writel(u, GPIO_IN_POL(pin)); | |
304 | } else if (type == IRQ_TYPE_EDGE_BOTH) { | |
305 | u32 v; | |
306 | ||
307 | v = readl(GPIO_IN_POL(pin)) ^ readl(GPIO_DATA_IN(pin)); | |
308 | ||
309 | /* | |
310 | * set initial polarity based on current input level | |
311 | */ | |
312 | u = readl(GPIO_IN_POL(pin)); | |
313 | if (v & (1 << (pin & 31))) | |
314 | u |= 1 << (pin & 31); /* falling */ | |
315 | else | |
316 | u &= ~(1 << (pin & 31)); /* rising */ | |
317 | writel(u, GPIO_IN_POL(pin)); | |
318 | } | |
319 | ||
320 | desc->status = (desc->status & ~IRQ_TYPE_SENSE_MASK) | type; | |
321 | ||
322 | return 0; | |
323 | } | |
324 | ||
fd4b9b36 | 325 | struct irq_chip orion_gpio_irq_chip = { |
a8865655 | 326 | .name = "orion_gpio_irq", |
3b0c8d40 LB |
327 | .irq_ack = gpio_irq_ack, |
328 | .irq_mask = gpio_irq_mask, | |
329 | .irq_unmask = gpio_irq_unmask, | |
330 | .irq_set_type = gpio_irq_set_type, | |
07332318 LB |
331 | }; |
332 | ||
333 | void orion_gpio_irq_handler(int pinoff) | |
334 | { | |
335 | u32 cause; | |
336 | int pin; | |
337 | ||
338 | cause = readl(GPIO_DATA_IN(pinoff)) & readl(GPIO_LEVEL_MASK(pinoff)); | |
339 | cause |= readl(GPIO_EDGE_CAUSE(pinoff)) & readl(GPIO_EDGE_MASK(pinoff)); | |
340 | ||
341 | for (pin = pinoff; pin < pinoff + 8; pin++) { | |
342 | int irq = gpio_to_irq(pin); | |
343 | struct irq_desc *desc = irq_desc + irq; | |
344 | ||
345 | if (!(cause & (1 << (pin & 31)))) | |
346 | continue; | |
347 | ||
348 | if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { | |
349 | /* Swap polarity (race with GPIO line) */ | |
350 | u32 polarity; | |
351 | ||
352 | polarity = readl(GPIO_IN_POL(pin)); | |
353 | polarity ^= 1 << (pin & 31); | |
354 | writel(polarity, GPIO_IN_POL(pin)); | |
355 | } | |
356 | desc_handle_irq(irq, desc); | |
357 | } | |
358 | } |