]>
Commit | Line | Data |
---|---|---|
45528e38 DB |
1 | /* |
2 | * linux/arch/arm/mach-sa1100/gpio.c | |
3 | * | |
4 | * Generic SA-1100 GPIO handling | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | */ | |
827fb6af | 10 | #include <linux/gpio/driver.h> |
45528e38 DB |
11 | #include <linux/init.h> |
12 | #include <linux/module.h> | |
40ca061b | 13 | #include <linux/io.h> |
a0ea298d | 14 | #include <linux/syscore_ops.h> |
9dd4819e | 15 | #include <soc/sa1100/pwer.h> |
a09e64fb | 16 | #include <mach/hardware.h> |
f314f33b | 17 | #include <mach/irqs.h> |
45528e38 | 18 | |
07242b24 RK |
19 | struct sa1100_gpio_chip { |
20 | struct gpio_chip chip; | |
21 | void __iomem *membase; | |
22 | int irqbase; | |
23 | u32 irqmask; | |
24 | u32 irqrising; | |
25 | u32 irqfalling; | |
26 | u32 irqwake; | |
27 | }; | |
28 | ||
29 | #define sa1100_gpio_chip(x) container_of(x, struct sa1100_gpio_chip, chip) | |
30 | ||
31 | enum { | |
32 | R_GPLR = 0x00, | |
33 | R_GPDR = 0x04, | |
34 | R_GPSR = 0x08, | |
35 | R_GPCR = 0x0c, | |
36 | R_GRER = 0x10, | |
37 | R_GFER = 0x14, | |
38 | R_GEDR = 0x18, | |
39 | R_GAFR = 0x1c, | |
40 | }; | |
41 | ||
45528e38 DB |
42 | static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset) |
43 | { | |
07242b24 RK |
44 | return readl_relaxed(sa1100_gpio_chip(chip)->membase + R_GPLR) & |
45 | BIT(offset); | |
45528e38 DB |
46 | } |
47 | ||
48 | static void sa1100_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |
49 | { | |
07242b24 RK |
50 | int reg = value ? R_GPSR : R_GPCR; |
51 | ||
52 | writel_relaxed(BIT(offset), sa1100_gpio_chip(chip)->membase + reg); | |
45528e38 DB |
53 | } |
54 | ||
c65d1fd3 RK |
55 | static int sa1100_get_direction(struct gpio_chip *chip, unsigned offset) |
56 | { | |
57 | void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR; | |
58 | ||
59 | return !(readl_relaxed(gpdr) & BIT(offset)); | |
60 | } | |
61 | ||
45528e38 DB |
62 | static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset) |
63 | { | |
07242b24 | 64 | void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR; |
45528e38 DB |
65 | unsigned long flags; |
66 | ||
67 | local_irq_save(flags); | |
07242b24 | 68 | writel_relaxed(readl_relaxed(gpdr) & ~BIT(offset), gpdr); |
45528e38 | 69 | local_irq_restore(flags); |
07242b24 | 70 | |
45528e38 DB |
71 | return 0; |
72 | } | |
73 | ||
74 | static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int value) | |
75 | { | |
07242b24 | 76 | void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR; |
45528e38 DB |
77 | unsigned long flags; |
78 | ||
79 | local_irq_save(flags); | |
80 | sa1100_gpio_set(chip, offset, value); | |
07242b24 | 81 | writel_relaxed(readl_relaxed(gpdr) | BIT(offset), gpdr); |
45528e38 | 82 | local_irq_restore(flags); |
07242b24 | 83 | |
45528e38 DB |
84 | return 0; |
85 | } | |
86 | ||
f408c985 RK |
87 | static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset) |
88 | { | |
07242b24 | 89 | return sa1100_gpio_chip(chip)->irqbase + offset; |
f408c985 RK |
90 | } |
91 | ||
07242b24 RK |
92 | static struct sa1100_gpio_chip sa1100_gpio_chip = { |
93 | .chip = { | |
94 | .label = "gpio", | |
c65d1fd3 | 95 | .get_direction = sa1100_get_direction, |
07242b24 RK |
96 | .direction_input = sa1100_direction_input, |
97 | .direction_output = sa1100_direction_output, | |
98 | .set = sa1100_gpio_set, | |
99 | .get = sa1100_gpio_get, | |
100 | .to_irq = sa1100_to_irq, | |
101 | .base = 0, | |
102 | .ngpio = GPIO_MAX + 1, | |
103 | }, | |
104 | .membase = (void *)&GPLR, | |
105 | .irqbase = IRQ_GPIO0, | |
45528e38 DB |
106 | }; |
107 | ||
a0ea298d DB |
108 | /* |
109 | * SA1100 GPIO edge detection for IRQs: | |
110 | * IRQs are generated on Falling-Edge, Rising-Edge, or both. | |
111 | * Use this instead of directly setting GRER/GFER. | |
112 | */ | |
07242b24 RK |
113 | static void sa1100_update_edge_regs(struct sa1100_gpio_chip *sgc) |
114 | { | |
115 | void *base = sgc->membase; | |
116 | u32 grer, gfer; | |
117 | ||
118 | grer = sgc->irqrising & sgc->irqmask; | |
119 | gfer = sgc->irqfalling & sgc->irqmask; | |
120 | ||
121 | writel_relaxed(grer, base + R_GRER); | |
122 | writel_relaxed(gfer, base + R_GFER); | |
123 | } | |
a0ea298d DB |
124 | |
125 | static int sa1100_gpio_type(struct irq_data *d, unsigned int type) | |
126 | { | |
07242b24 RK |
127 | struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); |
128 | unsigned int mask = BIT(d->hwirq); | |
a0ea298d DB |
129 | |
130 | if (type == IRQ_TYPE_PROBE) { | |
07242b24 | 131 | if ((sgc->irqrising | sgc->irqfalling) & mask) |
a0ea298d DB |
132 | return 0; |
133 | type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | |
134 | } | |
135 | ||
136 | if (type & IRQ_TYPE_EDGE_RISING) | |
07242b24 | 137 | sgc->irqrising |= mask; |
a0ea298d | 138 | else |
07242b24 | 139 | sgc->irqrising &= ~mask; |
a0ea298d | 140 | if (type & IRQ_TYPE_EDGE_FALLING) |
07242b24 | 141 | sgc->irqfalling |= mask; |
a0ea298d | 142 | else |
07242b24 | 143 | sgc->irqfalling &= ~mask; |
a0ea298d | 144 | |
07242b24 | 145 | sa1100_update_edge_regs(sgc); |
a0ea298d DB |
146 | |
147 | return 0; | |
148 | } | |
149 | ||
150 | /* | |
151 | * GPIO IRQs must be acknowledged. | |
152 | */ | |
153 | static void sa1100_gpio_ack(struct irq_data *d) | |
154 | { | |
07242b24 RK |
155 | struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); |
156 | ||
157 | writel_relaxed(BIT(d->hwirq), sgc->membase + R_GEDR); | |
a0ea298d DB |
158 | } |
159 | ||
160 | static void sa1100_gpio_mask(struct irq_data *d) | |
161 | { | |
07242b24 | 162 | struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); |
a0ea298d DB |
163 | unsigned int mask = BIT(d->hwirq); |
164 | ||
07242b24 | 165 | sgc->irqmask &= ~mask; |
a0ea298d | 166 | |
07242b24 | 167 | sa1100_update_edge_regs(sgc); |
a0ea298d DB |
168 | } |
169 | ||
170 | static void sa1100_gpio_unmask(struct irq_data *d) | |
171 | { | |
07242b24 | 172 | struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); |
a0ea298d DB |
173 | unsigned int mask = BIT(d->hwirq); |
174 | ||
07242b24 | 175 | sgc->irqmask |= mask; |
a0ea298d | 176 | |
07242b24 | 177 | sa1100_update_edge_regs(sgc); |
a0ea298d DB |
178 | } |
179 | ||
180 | static int sa1100_gpio_wake(struct irq_data *d, unsigned int on) | |
181 | { | |
07242b24 | 182 | struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); |
9dd4819e RK |
183 | int ret = sa11x0_gpio_set_wake(d->hwirq, on); |
184 | if (!ret) { | |
185 | if (on) | |
07242b24 | 186 | sgc->irqwake |= BIT(d->hwirq); |
9dd4819e | 187 | else |
07242b24 | 188 | sgc->irqwake &= ~BIT(d->hwirq); |
9dd4819e RK |
189 | } |
190 | return ret; | |
a0ea298d DB |
191 | } |
192 | ||
193 | /* | |
194 | * This is for GPIO IRQs | |
195 | */ | |
196 | static struct irq_chip sa1100_gpio_irq_chip = { | |
197 | .name = "GPIO", | |
198 | .irq_ack = sa1100_gpio_ack, | |
199 | .irq_mask = sa1100_gpio_mask, | |
200 | .irq_unmask = sa1100_gpio_unmask, | |
201 | .irq_set_type = sa1100_gpio_type, | |
202 | .irq_set_wake = sa1100_gpio_wake, | |
203 | }; | |
204 | ||
205 | static int sa1100_gpio_irqdomain_map(struct irq_domain *d, | |
206 | unsigned int irq, irq_hw_number_t hwirq) | |
207 | { | |
07242b24 RK |
208 | struct sa1100_gpio_chip *sgc = d->host_data; |
209 | ||
210 | irq_set_chip_data(irq, sgc); | |
211 | irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, handle_edge_irq); | |
56beac95 | 212 | irq_set_probe(irq); |
a0ea298d DB |
213 | |
214 | return 0; | |
215 | } | |
216 | ||
0b354dc4 | 217 | static const struct irq_domain_ops sa1100_gpio_irqdomain_ops = { |
a0ea298d DB |
218 | .map = sa1100_gpio_irqdomain_map, |
219 | .xlate = irq_domain_xlate_onetwocell, | |
220 | }; | |
221 | ||
222 | static struct irq_domain *sa1100_gpio_irqdomain; | |
223 | ||
224 | /* | |
225 | * IRQ 0-11 (GPIO) handler. We enter here with the | |
226 | * irq_controller_lock held, and IRQs disabled. Decode the IRQ | |
227 | * and call the handler. | |
228 | */ | |
bd0b9ac4 | 229 | static void sa1100_gpio_handler(struct irq_desc *desc) |
a0ea298d | 230 | { |
07242b24 | 231 | struct sa1100_gpio_chip *sgc = irq_desc_get_handler_data(desc); |
2951a799 | 232 | unsigned int irq, mask; |
07242b24 | 233 | void __iomem *gedr = sgc->membase + R_GEDR; |
a0ea298d | 234 | |
07242b24 | 235 | mask = readl_relaxed(gedr); |
a0ea298d DB |
236 | do { |
237 | /* | |
238 | * clear down all currently active IRQ sources. | |
239 | * We will be processing them all. | |
240 | */ | |
07242b24 | 241 | writel_relaxed(mask, gedr); |
a0ea298d | 242 | |
07242b24 | 243 | irq = sgc->irqbase; |
a0ea298d DB |
244 | do { |
245 | if (mask & 1) | |
246 | generic_handle_irq(irq); | |
247 | mask >>= 1; | |
248 | irq++; | |
249 | } while (mask); | |
250 | ||
07242b24 | 251 | mask = readl_relaxed(gedr); |
a0ea298d DB |
252 | } while (mask); |
253 | } | |
254 | ||
255 | static int sa1100_gpio_suspend(void) | |
256 | { | |
07242b24 RK |
257 | struct sa1100_gpio_chip *sgc = &sa1100_gpio_chip; |
258 | ||
a0ea298d DB |
259 | /* |
260 | * Set the appropriate edges for wakeup. | |
261 | */ | |
07242b24 RK |
262 | writel_relaxed(sgc->irqwake & sgc->irqrising, sgc->membase + R_GRER); |
263 | writel_relaxed(sgc->irqwake & sgc->irqfalling, sgc->membase + R_GFER); | |
a0ea298d DB |
264 | |
265 | /* | |
266 | * Clear any pending GPIO interrupts. | |
267 | */ | |
07242b24 RK |
268 | writel_relaxed(readl_relaxed(sgc->membase + R_GEDR), |
269 | sgc->membase + R_GEDR); | |
a0ea298d DB |
270 | |
271 | return 0; | |
272 | } | |
273 | ||
274 | static void sa1100_gpio_resume(void) | |
275 | { | |
07242b24 | 276 | sa1100_update_edge_regs(&sa1100_gpio_chip); |
a0ea298d DB |
277 | } |
278 | ||
279 | static struct syscore_ops sa1100_gpio_syscore_ops = { | |
280 | .suspend = sa1100_gpio_suspend, | |
281 | .resume = sa1100_gpio_resume, | |
282 | }; | |
283 | ||
284 | static int __init sa1100_gpio_init_devicefs(void) | |
285 | { | |
286 | register_syscore_ops(&sa1100_gpio_syscore_ops); | |
287 | return 0; | |
288 | } | |
289 | ||
290 | device_initcall(sa1100_gpio_init_devicefs); | |
291 | ||
07242b24 RK |
292 | static const int sa1100_gpio_irqs[] __initconst = { |
293 | /* Install handlers for GPIO 0-10 edge detect interrupts */ | |
294 | IRQ_GPIO0_SC, | |
295 | IRQ_GPIO1_SC, | |
296 | IRQ_GPIO2_SC, | |
297 | IRQ_GPIO3_SC, | |
298 | IRQ_GPIO4_SC, | |
299 | IRQ_GPIO5_SC, | |
300 | IRQ_GPIO6_SC, | |
301 | IRQ_GPIO7_SC, | |
302 | IRQ_GPIO8_SC, | |
303 | IRQ_GPIO9_SC, | |
304 | IRQ_GPIO10_SC, | |
305 | /* Install handler for GPIO 11-27 edge detect interrupts */ | |
306 | IRQ_GPIO11_27, | |
307 | }; | |
308 | ||
45528e38 DB |
309 | void __init sa1100_init_gpio(void) |
310 | { | |
07242b24 RK |
311 | struct sa1100_gpio_chip *sgc = &sa1100_gpio_chip; |
312 | int i; | |
313 | ||
a0ea298d | 314 | /* clear all GPIO edge detects */ |
07242b24 RK |
315 | writel_relaxed(0, sgc->membase + R_GFER); |
316 | writel_relaxed(0, sgc->membase + R_GRER); | |
317 | writel_relaxed(-1, sgc->membase + R_GEDR); | |
a0ea298d | 318 | |
07242b24 | 319 | gpiochip_add_data(&sa1100_gpio_chip.chip, NULL); |
a0ea298d DB |
320 | |
321 | sa1100_gpio_irqdomain = irq_domain_add_simple(NULL, | |
322 | 28, IRQ_GPIO0, | |
07242b24 | 323 | &sa1100_gpio_irqdomain_ops, sgc); |
a0ea298d | 324 | |
07242b24 RK |
325 | for (i = 0; i < ARRAY_SIZE(sa1100_gpio_irqs); i++) |
326 | irq_set_chained_handler_and_data(sa1100_gpio_irqs[i], | |
327 | sa1100_gpio_handler, sgc); | |
45528e38 | 328 | } |