diff options
author | Peter Korsgaard <jacmet@sunsite.dk> | 2010-01-07 11:57:46 -0500 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2010-05-17 11:48:28 -0400 |
commit | 345e5c8a1cc30ebd527bcc122d9540538942f1ba (patch) | |
tree | 7a413e2b6360cb5d8936e5b083279297f08a3080 | |
parent | 1ed31d6db90d51010545921e59d369d2f92b7ac2 (diff) |
powerpc: Add interrupt support to mpc8xxx_gpio
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Acked-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r-- | Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt | 22 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpc8xxx_gpio.c | 147 |
2 files changed, 168 insertions, 1 deletions
diff --git a/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt index d015dcec4011..b0019eb5330e 100644 --- a/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt +++ b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt | |||
@@ -11,7 +11,7 @@ Required properties: | |||
11 | 83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx. | 11 | 83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx. |
12 | - #gpio-cells : Should be two. The first cell is the pin number and the | 12 | - #gpio-cells : Should be two. The first cell is the pin number and the |
13 | second cell is used to specify optional parameters (currently unused). | 13 | second cell is used to specify optional parameters (currently unused). |
14 | - interrupts : Interrupt mapping for GPIO IRQ (currently unused). | 14 | - interrupts : Interrupt mapping for GPIO IRQ. |
15 | - interrupt-parent : Phandle for the interrupt controller that | 15 | - interrupt-parent : Phandle for the interrupt controller that |
16 | services interrupts for this device. | 16 | services interrupts for this device. |
17 | - gpio-controller : Marks the port as GPIO controller. | 17 | - gpio-controller : Marks the port as GPIO controller. |
@@ -38,3 +38,23 @@ Example of gpio-controller nodes for a MPC8347 SoC: | |||
38 | 38 | ||
39 | See booting-without-of.txt for details of how to specify GPIO | 39 | See booting-without-of.txt for details of how to specify GPIO |
40 | information for devices. | 40 | information for devices. |
41 | |||
42 | To use GPIO pins as interrupt sources for peripherals, specify the | ||
43 | GPIO controller as the interrupt parent and define GPIO number + | ||
44 | trigger mode using the interrupts property, which is defined like | ||
45 | this: | ||
46 | |||
47 | interrupts = <number trigger>, where: | ||
48 | - number: GPIO pin (0..31) | ||
49 | - trigger: trigger mode: | ||
50 | 2 = trigger on falling edge | ||
51 | 3 = trigger on both edges | ||
52 | |||
53 | Example of device using this is: | ||
54 | |||
55 | funkyfpga@0 { | ||
56 | compatible = "funky-fpga"; | ||
57 | ... | ||
58 | interrupts = <4 3>; | ||
59 | interrupt-parent = <&gpio1>; | ||
60 | }; | ||
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index 6478eb10691a..83f519655fac 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/of_gpio.h> | 16 | #include <linux/of_gpio.h> |
17 | #include <linux/gpio.h> | 17 | #include <linux/gpio.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/irq.h> | ||
19 | 20 | ||
20 | #define MPC8XXX_GPIO_PINS 32 | 21 | #define MPC8XXX_GPIO_PINS 32 |
21 | 22 | ||
@@ -35,6 +36,7 @@ struct mpc8xxx_gpio_chip { | |||
35 | * open drain mode safely | 36 | * open drain mode safely |
36 | */ | 37 | */ |
37 | u32 data; | 38 | u32 data; |
39 | struct irq_host *irq; | ||
38 | }; | 40 | }; |
39 | 41 | ||
40 | static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) | 42 | static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) |
@@ -128,12 +130,136 @@ static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val | |||
128 | return 0; | 130 | return 0; |
129 | } | 131 | } |
130 | 132 | ||
133 | static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | ||
134 | { | ||
135 | struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); | ||
136 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); | ||
137 | |||
138 | if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS) | ||
139 | return irq_create_mapping(mpc8xxx_gc->irq, offset); | ||
140 | else | ||
141 | return -ENXIO; | ||
142 | } | ||
143 | |||
144 | static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) | ||
145 | { | ||
146 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_desc_data(desc); | ||
147 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | ||
148 | unsigned int mask; | ||
149 | |||
150 | mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR); | ||
151 | if (mask) | ||
152 | generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, | ||
153 | 32 - ffs(mask))); | ||
154 | } | ||
155 | |||
156 | static void mpc8xxx_irq_unmask(unsigned int virq) | ||
157 | { | ||
158 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); | ||
159 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | ||
160 | unsigned long flags; | ||
161 | |||
162 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | ||
163 | |||
164 | setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq))); | ||
165 | |||
166 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | ||
167 | } | ||
168 | |||
169 | static void mpc8xxx_irq_mask(unsigned int virq) | ||
170 | { | ||
171 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); | ||
172 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | ||
173 | unsigned long flags; | ||
174 | |||
175 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | ||
176 | |||
177 | clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq))); | ||
178 | |||
179 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | ||
180 | } | ||
181 | |||
182 | static void mpc8xxx_irq_ack(unsigned int virq) | ||
183 | { | ||
184 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); | ||
185 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | ||
186 | |||
187 | out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(virq))); | ||
188 | } | ||
189 | |||
190 | static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type) | ||
191 | { | ||
192 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); | ||
193 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | ||
194 | unsigned long flags; | ||
195 | |||
196 | switch (flow_type) { | ||
197 | case IRQ_TYPE_EDGE_FALLING: | ||
198 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | ||
199 | setbits32(mm->regs + GPIO_ICR, | ||
200 | mpc8xxx_gpio2mask(virq_to_hw(virq))); | ||
201 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | ||
202 | break; | ||
203 | |||
204 | case IRQ_TYPE_EDGE_BOTH: | ||
205 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | ||
206 | clrbits32(mm->regs + GPIO_ICR, | ||
207 | mpc8xxx_gpio2mask(virq_to_hw(virq))); | ||
208 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | ||
209 | break; | ||
210 | |||
211 | default: | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static struct irq_chip mpc8xxx_irq_chip = { | ||
219 | .name = "mpc8xxx-gpio", | ||
220 | .unmask = mpc8xxx_irq_unmask, | ||
221 | .mask = mpc8xxx_irq_mask, | ||
222 | .ack = mpc8xxx_irq_ack, | ||
223 | .set_type = mpc8xxx_irq_set_type, | ||
224 | }; | ||
225 | |||
226 | static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, | ||
227 | irq_hw_number_t hw) | ||
228 | { | ||
229 | set_irq_chip_data(virq, h->host_data); | ||
230 | set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); | ||
231 | set_irq_type(virq, IRQ_TYPE_NONE); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct, | ||
237 | const u32 *intspec, unsigned int intsize, | ||
238 | irq_hw_number_t *out_hwirq, | ||
239 | unsigned int *out_flags) | ||
240 | |||
241 | { | ||
242 | /* interrupt sense values coming from the device tree equal either | ||
243 | * EDGE_FALLING or EDGE_BOTH | ||
244 | */ | ||
245 | *out_hwirq = intspec[0]; | ||
246 | *out_flags = intspec[1]; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static struct irq_host_ops mpc8xxx_gpio_irq_ops = { | ||
252 | .map = mpc8xxx_gpio_irq_map, | ||
253 | .xlate = mpc8xxx_gpio_irq_xlate, | ||
254 | }; | ||
255 | |||
131 | static void __init mpc8xxx_add_controller(struct device_node *np) | 256 | static void __init mpc8xxx_add_controller(struct device_node *np) |
132 | { | 257 | { |
133 | struct mpc8xxx_gpio_chip *mpc8xxx_gc; | 258 | struct mpc8xxx_gpio_chip *mpc8xxx_gc; |
134 | struct of_mm_gpio_chip *mm_gc; | 259 | struct of_mm_gpio_chip *mm_gc; |
135 | struct of_gpio_chip *of_gc; | 260 | struct of_gpio_chip *of_gc; |
136 | struct gpio_chip *gc; | 261 | struct gpio_chip *gc; |
262 | unsigned hwirq; | ||
137 | int ret; | 263 | int ret; |
138 | 264 | ||
139 | mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); | 265 | mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); |
@@ -158,11 +284,32 @@ static void __init mpc8xxx_add_controller(struct device_node *np) | |||
158 | else | 284 | else |
159 | gc->get = mpc8xxx_gpio_get; | 285 | gc->get = mpc8xxx_gpio_get; |
160 | gc->set = mpc8xxx_gpio_set; | 286 | gc->set = mpc8xxx_gpio_set; |
287 | gc->to_irq = mpc8xxx_gpio_to_irq; | ||
161 | 288 | ||
162 | ret = of_mm_gpiochip_add(np, mm_gc); | 289 | ret = of_mm_gpiochip_add(np, mm_gc); |
163 | if (ret) | 290 | if (ret) |
164 | goto err; | 291 | goto err; |
165 | 292 | ||
293 | hwirq = irq_of_parse_and_map(np, 0); | ||
294 | if (hwirq == NO_IRQ) | ||
295 | goto skip_irq; | ||
296 | |||
297 | mpc8xxx_gc->irq = | ||
298 | irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, | ||
299 | &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); | ||
300 | if (!mpc8xxx_gc->irq) | ||
301 | goto skip_irq; | ||
302 | |||
303 | mpc8xxx_gc->irq->host_data = mpc8xxx_gc; | ||
304 | |||
305 | /* ack and mask all irqs */ | ||
306 | out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); | ||
307 | out_be32(mm_gc->regs + GPIO_IMR, 0); | ||
308 | |||
309 | set_irq_data(hwirq, mpc8xxx_gc); | ||
310 | set_irq_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); | ||
311 | |||
312 | skip_irq: | ||
166 | return; | 313 | return; |
167 | 314 | ||
168 | err: | 315 | err: |