OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | /* |
2 | * Copyright 2012 Gateworks Corporation |
||
3 | * Chris Lang <clang@gateworks.com> |
||
4 | * Tim Harvey <tharvey@gateworks.com> |
||
5 | * |
||
6 | * This file 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 | */ |
||
10 | |||
11 | #include <linux/module.h> |
||
12 | #include <linux/init.h> |
||
13 | #include <linux/interrupt.h> |
||
14 | #include <linux/irqchip/chained_irq.h> |
||
15 | #include <linux/io.h> |
||
16 | #include <linux/gpio.h> |
||
17 | #include <linux/irq.h> |
||
18 | #include <linux/irqdomain.h> |
||
19 | |||
20 | #include <asm/mach/irq.h> |
||
21 | |||
22 | /* |
||
23 | * Registers |
||
24 | */ |
||
25 | #define GPIO_INPUT 0x04 |
||
26 | #define GPIO_DIR 0x08 |
||
27 | #define GPIO_SET 0x10 |
||
28 | #define GPIO_CLEAR 0x14 |
||
29 | #define GPIO_INTERRUPT_ENABLE 0x20 |
||
30 | #define GPIO_INTERRUPT_RAW_STATUS 0x24 |
||
31 | #define GPIO_INTERRUPT_MASKED_STATUS 0x28 |
||
32 | #define GPIO_INTERRUPT_MASK 0x2C |
||
33 | #define GPIO_INTERRUPT_CLEAR 0x30 |
||
34 | #define GPIO_INTERRUPT_TRIGGER_METHOD 0x34 |
||
35 | #define GPIO_INTERRUPT_TRIGGER_BOTH_EDGES 0x38 |
||
36 | #define GPIO_INTERRUPT_TRIGGER_TYPE 0x3C |
||
37 | |||
38 | #define GPIO_INTERRUPT_TRIGGER_METHOD_EDGE 0 |
||
39 | #define GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL 1 |
||
40 | #define GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE 0 |
||
41 | #define GPIO_INTERRUPT_TRIGGER_EDGE_BOTH 1 |
||
42 | #define GPIO_INTERRUPT_TRIGGER_TYPE_RISING 0 |
||
43 | #define GPIO_INTERRUPT_TRIGGER_TYPE_FALLING 1 |
||
44 | #define GPIO_INTERRUPT_TRIGGER_TYPE_HIGH 0 |
||
45 | #define GPIO_INTERRUPT_TRIGGER_TYPE_LOW 1 |
||
46 | |||
47 | struct cns3xxx_gpio_chip { |
||
48 | struct gpio_chip chip; |
||
49 | struct irq_domain *domain; |
||
50 | spinlock_t lock; |
||
51 | void __iomem *base; |
||
52 | }; |
||
53 | |||
54 | static struct cns3xxx_gpio_chip cns3xxx_gpio_chips[2]; |
||
55 | static int cns3xxx_gpio_chip_count; |
||
56 | |||
57 | static inline void |
||
58 | __set_direction(struct cns3xxx_gpio_chip *cchip, unsigned pin, int input) |
||
59 | { |
||
60 | u32 reg; |
||
61 | |||
62 | reg = __raw_readl(cchip->base + GPIO_DIR); |
||
63 | if (input) |
||
64 | reg &= ~(1 << pin); |
||
65 | else |
||
66 | reg |= (1 << pin); |
||
67 | __raw_writel(reg, cchip->base + GPIO_DIR); |
||
68 | } |
||
69 | |||
70 | /* |
||
71 | * GENERIC_GPIO primatives |
||
72 | */ |
||
73 | static int cns3xxx_gpio_direction_input(struct gpio_chip *chip, unsigned pin) |
||
74 | { |
||
75 | struct cns3xxx_gpio_chip *cchip = |
||
76 | container_of(chip, struct cns3xxx_gpio_chip, chip); |
||
77 | unsigned long flags; |
||
78 | |||
79 | spin_lock_irqsave(&cchip->lock, flags); |
||
80 | __set_direction(cchip, pin, 1); |
||
81 | spin_unlock_irqrestore(&cchip->lock, flags); |
||
82 | |||
83 | return 0; |
||
84 | } |
||
85 | |||
86 | static int cns3xxx_gpio_get(struct gpio_chip *chip, unsigned pin) |
||
87 | { |
||
88 | struct cns3xxx_gpio_chip *cchip = |
||
89 | container_of(chip, struct cns3xxx_gpio_chip, chip); |
||
90 | int val; |
||
91 | |||
92 | val = ((__raw_readl(cchip->base + GPIO_INPUT) >> pin) & 0x1); |
||
93 | |||
94 | return val; |
||
95 | } |
||
96 | |||
97 | static int cns3xxx_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int level) |
||
98 | { |
||
99 | struct cns3xxx_gpio_chip *cchip = |
||
100 | container_of(chip, struct cns3xxx_gpio_chip, chip); |
||
101 | unsigned long flags; |
||
102 | |||
103 | spin_lock_irqsave(&cchip->lock, flags); |
||
104 | if (level) |
||
105 | __raw_writel(1 << pin, cchip->base + GPIO_SET); |
||
106 | else |
||
107 | __raw_writel(1 << pin, cchip->base + GPIO_CLEAR); |
||
108 | __set_direction(cchip, pin, 0); |
||
109 | spin_unlock_irqrestore(&cchip->lock, flags); |
||
110 | |||
111 | return 0; |
||
112 | } |
||
113 | |||
114 | static void cns3xxx_gpio_set(struct gpio_chip *chip, unsigned pin, |
||
115 | int level) |
||
116 | { |
||
117 | struct cns3xxx_gpio_chip *cchip = |
||
118 | container_of(chip, struct cns3xxx_gpio_chip, chip); |
||
119 | |||
120 | if (level) |
||
121 | __raw_writel(1 << pin, cchip->base + GPIO_SET); |
||
122 | else |
||
123 | __raw_writel(1 << pin, cchip->base + GPIO_CLEAR); |
||
124 | } |
||
125 | |||
126 | static int cns3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned pin) |
||
127 | { |
||
128 | struct cns3xxx_gpio_chip *cchip = |
||
129 | container_of(chip, struct cns3xxx_gpio_chip, chip); |
||
130 | |||
131 | return irq_find_mapping(cchip->domain, pin); |
||
132 | } |
||
133 | |||
134 | |||
135 | /* |
||
136 | * IRQ support |
||
137 | */ |
||
138 | |||
139 | /* one interrupt per GPIO controller (GPIOA/GPIOB) |
||
140 | * this is called in task context, with IRQs enabled |
||
141 | */ |
||
142 | static void cns3xxx_gpio_irq_handler(struct irq_desc *desc) |
||
143 | { |
||
144 | struct cns3xxx_gpio_chip *cchip = irq_desc_get_handler_data(desc); |
||
145 | struct irq_chip *chip = irq_desc_get_chip(desc); |
||
146 | u16 i; |
||
147 | u32 reg; |
||
148 | |||
149 | chained_irq_enter(chip, desc); /* mask and ack the base interrupt */ |
||
150 | |||
151 | /* see which pin(s) triggered the interrupt */ |
||
152 | reg = __raw_readl(cchip->base + GPIO_INTERRUPT_RAW_STATUS); |
||
153 | for (i = 0; i < 32; i++) { |
||
154 | if (reg & (1 << i)) { |
||
155 | /* let the generic IRQ layer handle an interrupt */ |
||
156 | generic_handle_irq(irq_find_mapping(cchip->domain, i)); |
||
157 | } |
||
158 | } |
||
159 | |||
160 | chained_irq_exit(chip, desc); /* unmask the base interrupt */ |
||
161 | } |
||
162 | |||
163 | static int cns3xxx_gpio_irq_set_type(struct irq_data *d, u32 irqtype) |
||
164 | { |
||
165 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
||
166 | struct cns3xxx_gpio_chip *cchip = gc->private; |
||
167 | u32 gpio = d->hwirq; |
||
168 | unsigned long flags; |
||
169 | u32 method, edges, type; |
||
170 | |||
171 | spin_lock_irqsave(&cchip->lock, flags); |
||
172 | method = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_METHOD); |
||
173 | edges = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_BOTH_EDGES); |
||
174 | type = __raw_readl(cchip->base + GPIO_INTERRUPT_TRIGGER_TYPE); |
||
175 | method &= ~(1 << gpio); |
||
176 | edges &= ~(1 << gpio); |
||
177 | type &= ~(1 << gpio); |
||
178 | |||
179 | switch(irqtype) { |
||
180 | case IRQ_TYPE_EDGE_RISING: |
||
181 | method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio); |
||
182 | edges |= (GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE << gpio); |
||
183 | type |= (GPIO_INTERRUPT_TRIGGER_TYPE_RISING << gpio); |
||
184 | break; |
||
185 | case IRQ_TYPE_EDGE_FALLING: |
||
186 | method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio); |
||
187 | edges |= (GPIO_INTERRUPT_TRIGGER_EDGE_SINGLE << gpio); |
||
188 | type |= (GPIO_INTERRUPT_TRIGGER_TYPE_FALLING << gpio); |
||
189 | break; |
||
190 | case IRQ_TYPE_EDGE_BOTH: |
||
191 | method |= (GPIO_INTERRUPT_TRIGGER_METHOD_EDGE << gpio); |
||
192 | edges |= (GPIO_INTERRUPT_TRIGGER_EDGE_BOTH << gpio); |
||
193 | break; |
||
194 | case IRQ_TYPE_LEVEL_LOW: |
||
195 | method |= (GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL << gpio); |
||
196 | type |= (GPIO_INTERRUPT_TRIGGER_TYPE_LOW << gpio); |
||
197 | break; |
||
198 | case IRQ_TYPE_LEVEL_HIGH: |
||
199 | method |= (GPIO_INTERRUPT_TRIGGER_METHOD_LEVEL << gpio); |
||
200 | type |= (GPIO_INTERRUPT_TRIGGER_TYPE_HIGH << gpio); |
||
201 | break; |
||
202 | default: |
||
203 | printk(KERN_WARNING "No irq type\n"); |
||
204 | spin_unlock_irqrestore(&cchip->lock, flags); |
||
205 | return -EINVAL; |
||
206 | } |
||
207 | |||
208 | __raw_writel(method, cchip->base + GPIO_INTERRUPT_TRIGGER_METHOD); |
||
209 | __raw_writel(edges, cchip->base + GPIO_INTERRUPT_TRIGGER_BOTH_EDGES); |
||
210 | __raw_writel(type, cchip->base + GPIO_INTERRUPT_TRIGGER_TYPE); |
||
211 | spin_unlock_irqrestore(&cchip->lock, flags); |
||
212 | |||
213 | if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) |
||
214 | irq_set_handler_locked(d, handle_level_irq); |
||
215 | else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) |
||
216 | irq_set_handler_locked(d, handle_edge_irq); |
||
217 | |||
218 | return 0; |
||
219 | } |
||
220 | |||
221 | void __init cns3xxx_gpio_init(int gpio_base, int ngpio, |
||
222 | u32 base, int irq, int secondary_irq_base) |
||
223 | { |
||
224 | struct cns3xxx_gpio_chip *cchip; |
||
225 | struct irq_chip_generic *gc; |
||
226 | struct irq_chip_type *ct; |
||
227 | char gc_label[16]; |
||
228 | int irq_base; |
||
229 | |||
230 | if (cns3xxx_gpio_chip_count == ARRAY_SIZE(cns3xxx_gpio_chips)) |
||
231 | return; |
||
232 | |||
233 | snprintf(gc_label, sizeof(gc_label), "cns3xxx_gpio%d", |
||
234 | cns3xxx_gpio_chip_count); |
||
235 | |||
236 | cchip = cns3xxx_gpio_chips + cns3xxx_gpio_chip_count; |
||
237 | cchip->chip.label = kstrdup(gc_label, GFP_KERNEL); |
||
238 | cchip->chip.direction_input = cns3xxx_gpio_direction_input; |
||
239 | cchip->chip.get = cns3xxx_gpio_get; |
||
240 | cchip->chip.direction_output = cns3xxx_gpio_direction_output; |
||
241 | cchip->chip.set = cns3xxx_gpio_set; |
||
242 | cchip->chip.to_irq = cns3xxx_gpio_to_irq; |
||
243 | cchip->chip.base = gpio_base; |
||
244 | cchip->chip.ngpio = ngpio; |
||
245 | cchip->chip.can_sleep = 0; |
||
246 | spin_lock_init(&cchip->lock); |
||
247 | cchip->base = (void __iomem *)base; |
||
248 | |||
249 | BUG_ON(gpiochip_add(&cchip->chip) < 0); |
||
250 | cns3xxx_gpio_chip_count++; |
||
251 | |||
252 | /* clear GPIO interrupts */ |
||
253 | __raw_writel(0xffff, cchip->base + GPIO_INTERRUPT_CLEAR); |
||
254 | |||
255 | irq_base = irq_alloc_descs(-1, secondary_irq_base, ngpio, |
||
256 | numa_node_id()); |
||
257 | if (irq_base < 0) |
||
258 | goto out_irqdesc_free; |
||
259 | |||
260 | cchip->domain = irq_domain_add_legacy(NULL, ngpio, irq_base, 0, |
||
261 | &irq_domain_simple_ops, NULL); |
||
262 | if (!cchip->domain) |
||
263 | goto out_irqdesc_free; |
||
264 | |||
265 | /* |
||
266 | * IRQ chip init |
||
267 | */ |
||
268 | gc = irq_alloc_generic_chip("cns3xxx_gpio_irq", 1, irq_base, |
||
269 | cchip->base, handle_edge_irq); |
||
270 | |||
271 | gc->private = cchip; |
||
272 | |||
273 | ct = gc->chip_types; |
||
274 | ct->type = IRQ_TYPE_EDGE_FALLING; |
||
275 | ct->regs.ack = GPIO_INTERRUPT_CLEAR; |
||
276 | ct->chip.irq_ack = irq_gc_ack_set_bit; |
||
277 | ct->regs.mask = GPIO_INTERRUPT_ENABLE; |
||
278 | ct->chip.irq_enable = irq_gc_mask_set_bit; |
||
279 | ct->chip.irq_disable = irq_gc_mask_clr_bit; |
||
280 | ct->chip.irq_set_type = cns3xxx_gpio_irq_set_type; |
||
281 | ct->handler = handle_edge_irq; |
||
282 | |||
283 | irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE, |
||
284 | IRQ_NOREQUEST, 0); |
||
285 | irq_set_chained_handler(irq, cns3xxx_gpio_irq_handler); |
||
286 | irq_set_handler_data(irq, cchip); |
||
287 | |||
288 | return; |
||
289 | |||
290 | out_irqdesc_free: |
||
291 | irq_free_descs(irq_base, ngpio); |
||
292 | } |