Commit | Line | Data |
---|---|---|
68b64931 | 1 | // SPDX-License-Identifier: GPL-2.0 |
b685004f | 2 | /* |
b685004f RM |
3 | * Generic EP93xx GPIO handling |
4 | * | |
1c5454ee | 5 | * Copyright (c) 2008 Ryan Mallon |
1e4c8842 | 6 | * Copyright (c) 2011 H Hartley Sweeten <hsweeten@visionengravers.com> |
b685004f RM |
7 | * |
8 | * Based on code originally from: | |
9 | * linux/arch/arm/mach-ep93xx/core.c | |
b685004f RM |
10 | */ |
11 | ||
12 | #include <linux/init.h> | |
bb207ef1 | 13 | #include <linux/module.h> |
1e4c8842 | 14 | #include <linux/platform_device.h> |
fced80c7 | 15 | #include <linux/io.h> |
595c050d | 16 | #include <linux/irq.h> |
1e4c8842 | 17 | #include <linux/slab.h> |
0f4630f3 | 18 | #include <linux/gpio/driver.h> |
51ba88e3 | 19 | #include <linux/bitops.h> |
216f3736 | 20 | #include <linux/seq_file.h> |
b685004f | 21 | |
991ce74e LW |
22 | #define EP93XX_GPIO_F_INT_STATUS 0x5c |
23 | #define EP93XX_GPIO_A_INT_STATUS 0xa0 | |
24 | #define EP93XX_GPIO_B_INT_STATUS 0xbc | |
4c2baed3 AB |
25 | |
26 | /* Maximum value for gpio line identifiers */ | |
27 | #define EP93XX_GPIO_LINE_MAX 63 | |
28 | ||
8b81a7ab NS |
29 | /* Number of GPIO chips in EP93XX */ |
30 | #define EP93XX_GPIO_CHIP_NUM 8 | |
31 | ||
4c2baed3 AB |
32 | /* Maximum value for irq capable line identifiers */ |
33 | #define EP93XX_GPIO_LINE_MAX_IRQ 23 | |
34 | ||
35d9e695 NS |
35 | #define EP93XX_GPIO_A_IRQ_BASE 64 |
36 | #define EP93XX_GPIO_B_IRQ_BASE 72 | |
d875cc27 | 37 | /* |
a419a3d9 LW |
38 | * Static mapping of GPIO bank F IRQS: |
39 | * F0..F7 (16..24) to irq 80..87. | |
d875cc27 | 40 | */ |
a419a3d9 | 41 | #define EP93XX_GPIO_F_IRQ_BASE 80 |
d875cc27 | 42 | |
8b81a7ab NS |
43 | struct ep93xx_gpio_irq_chip { |
44 | u8 irq_offset; | |
45 | u8 int_unmasked; | |
46 | u8 int_enabled; | |
47 | u8 int_type1; | |
48 | u8 int_type2; | |
49 | u8 int_debounce; | |
1e4c8842 HS |
50 | }; |
51 | ||
8b81a7ab NS |
52 | struct ep93xx_gpio_chip { |
53 | struct gpio_chip gc; | |
54 | struct ep93xx_gpio_irq_chip *eic; | |
55 | }; | |
d056ab78 | 56 | |
8b81a7ab NS |
57 | struct ep93xx_gpio { |
58 | void __iomem *base; | |
59 | struct ep93xx_gpio_chip gc[EP93XX_GPIO_CHIP_NUM]; | |
60 | }; | |
d056ab78 | 61 | |
8b81a7ab | 62 | #define to_ep93xx_gpio_chip(x) container_of(x, struct ep93xx_gpio_chip, gc) |
d056ab78 | 63 | |
8b81a7ab NS |
64 | static struct ep93xx_gpio_irq_chip *to_ep93xx_gpio_irq_chip(struct gpio_chip *gc) |
65 | { | |
66 | struct ep93xx_gpio_chip *egc = to_ep93xx_gpio_chip(gc); | |
d056ab78 | 67 | |
8b81a7ab | 68 | return egc->eic; |
d056ab78 HS |
69 | } |
70 | ||
8b81a7ab NS |
71 | /************************************************************************* |
72 | * Interrupt handling for EP93xx on-chip GPIOs | |
73 | *************************************************************************/ | |
74 | #define EP93XX_INT_TYPE1_OFFSET 0x00 | |
75 | #define EP93XX_INT_TYPE2_OFFSET 0x04 | |
76 | #define EP93XX_INT_EOI_OFFSET 0x08 | |
77 | #define EP93XX_INT_EN_OFFSET 0x0c | |
78 | #define EP93XX_INT_STATUS_OFFSET 0x10 | |
79 | #define EP93XX_INT_RAW_STATUS_OFFSET 0x14 | |
80 | #define EP93XX_INT_DEBOUNCE_OFFSET 0x18 | |
81 | ||
82 | static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg, | |
83 | struct ep93xx_gpio_irq_chip *eic) | |
d056ab78 | 84 | { |
8b81a7ab | 85 | writeb_relaxed(0, epg->base + eic->irq_offset + EP93XX_INT_EN_OFFSET); |
fd935fc4 | 86 | |
8b81a7ab NS |
87 | writeb_relaxed(eic->int_type2, |
88 | epg->base + eic->irq_offset + EP93XX_INT_TYPE2_OFFSET); | |
fd935fc4 | 89 | |
8b81a7ab NS |
90 | writeb_relaxed(eic->int_type1, |
91 | epg->base + eic->irq_offset + EP93XX_INT_TYPE1_OFFSET); | |
fd935fc4 | 92 | |
8b81a7ab NS |
93 | writeb_relaxed(eic->int_unmasked & eic->int_enabled, |
94 | epg->base + eic->irq_offset + EP93XX_INT_EN_OFFSET); | |
fd935fc4 LW |
95 | } |
96 | ||
97 | static void ep93xx_gpio_int_debounce(struct gpio_chip *gc, | |
98 | unsigned int offset, bool enable) | |
99 | { | |
100 | struct ep93xx_gpio *epg = gpiochip_get_data(gc); | |
8b81a7ab | 101 | struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); |
fd935fc4 | 102 | int port_mask = BIT(offset); |
d056ab78 HS |
103 | |
104 | if (enable) | |
8b81a7ab | 105 | eic->int_debounce |= port_mask; |
d056ab78 | 106 | else |
8b81a7ab | 107 | eic->int_debounce &= ~port_mask; |
d056ab78 | 108 | |
8b81a7ab NS |
109 | writeb(eic->int_debounce, |
110 | epg->base + eic->irq_offset + EP93XX_INT_DEBOUNCE_OFFSET); | |
d056ab78 | 111 | } |
d056ab78 | 112 | |
bd0b9ac4 | 113 | static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc) |
d056ab78 | 114 | { |
991ce74e LW |
115 | struct gpio_chip *gc = irq_desc_get_handler_data(desc); |
116 | struct ep93xx_gpio *epg = gpiochip_get_data(gc); | |
99399f40 | 117 | struct irq_chip *irqchip = irq_desc_get_chip(desc); |
68491b07 LW |
118 | unsigned long stat; |
119 | int offset; | |
d056ab78 | 120 | |
99399f40 LW |
121 | chained_irq_enter(irqchip, desc); |
122 | ||
a419a3d9 LW |
123 | /* |
124 | * Dispatch the IRQs to the irqdomain of each A and B | |
125 | * gpiochip irqdomains depending on what has fired. | |
126 | * The tricky part is that the IRQ line is shared | |
127 | * between bank A and B and each has their own gpiochip. | |
128 | */ | |
68491b07 | 129 | stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS); |
a419a3d9 | 130 | for_each_set_bit(offset, &stat, 8) |
dbd1c54f MZ |
131 | generic_handle_domain_irq(epg->gc[0].gc.irq.domain, |
132 | offset); | |
d056ab78 | 133 | |
68491b07 | 134 | stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS); |
a419a3d9 | 135 | for_each_set_bit(offset, &stat, 8) |
dbd1c54f MZ |
136 | generic_handle_domain_irq(epg->gc[1].gc.irq.domain, |
137 | offset); | |
99399f40 LW |
138 | |
139 | chained_irq_exit(irqchip, desc); | |
d056ab78 HS |
140 | } |
141 | ||
bd0b9ac4 | 142 | static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc) |
d056ab78 HS |
143 | { |
144 | /* | |
25985edc | 145 | * map discontiguous hw irq range to continuous sw irq range: |
d056ab78 | 146 | * |
d875cc27 | 147 | * IRQ_EP93XX_GPIO{0..7}MUX -> EP93XX_GPIO_LINE_F{0..7} |
d056ab78 | 148 | */ |
99399f40 | 149 | struct irq_chip *irqchip = irq_desc_get_chip(desc); |
e43ea7a7 | 150 | unsigned int irq = irq_desc_get_irq(desc); |
0f04cdbd | 151 | int port_f_idx = (irq & 7) ^ 4; /* {20..23,48..51} -> {0..7} */ |
a419a3d9 | 152 | int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx; |
d056ab78 | 153 | |
99399f40 | 154 | chained_irq_enter(irqchip, desc); |
d056ab78 | 155 | generic_handle_irq(gpio_irq); |
99399f40 | 156 | chained_irq_exit(irqchip, desc); |
d056ab78 HS |
157 | } |
158 | ||
c0afc916 | 159 | static void ep93xx_gpio_irq_ack(struct irq_data *d) |
d056ab78 | 160 | { |
991ce74e | 161 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
8b81a7ab | 162 | struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); |
991ce74e | 163 | struct ep93xx_gpio *epg = gpiochip_get_data(gc); |
51ba88e3 | 164 | int port_mask = BIT(d->irq & 7); |
d056ab78 | 165 | |
d1735a2e | 166 | if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { |
8b81a7ab NS |
167 | eic->int_type2 ^= port_mask; /* switch edge direction */ |
168 | ep93xx_gpio_update_int_params(epg, eic); | |
d056ab78 HS |
169 | } |
170 | ||
8b81a7ab | 171 | writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET); |
d056ab78 HS |
172 | } |
173 | ||
c0afc916 | 174 | static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) |
d056ab78 | 175 | { |
991ce74e | 176 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
8b81a7ab | 177 | struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); |
991ce74e | 178 | struct ep93xx_gpio *epg = gpiochip_get_data(gc); |
51ba88e3 | 179 | int port_mask = BIT(d->irq & 7); |
d056ab78 | 180 | |
d1735a2e | 181 | if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) |
8b81a7ab | 182 | eic->int_type2 ^= port_mask; /* switch edge direction */ |
d056ab78 | 183 | |
8b81a7ab NS |
184 | eic->int_unmasked &= ~port_mask; |
185 | ep93xx_gpio_update_int_params(epg, eic); | |
d056ab78 | 186 | |
8b81a7ab | 187 | writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET); |
216f3736 | 188 | gpiochip_disable_irq(gc, irqd_to_hwirq(d)); |
d056ab78 HS |
189 | } |
190 | ||
c0afc916 | 191 | static void ep93xx_gpio_irq_mask(struct irq_data *d) |
d056ab78 | 192 | { |
991ce74e | 193 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
8b81a7ab | 194 | struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); |
991ce74e | 195 | struct ep93xx_gpio *epg = gpiochip_get_data(gc); |
d056ab78 | 196 | |
8b81a7ab NS |
197 | eic->int_unmasked &= ~BIT(d->irq & 7); |
198 | ep93xx_gpio_update_int_params(epg, eic); | |
216f3736 | 199 | gpiochip_disable_irq(gc, irqd_to_hwirq(d)); |
d056ab78 HS |
200 | } |
201 | ||
c0afc916 | 202 | static void ep93xx_gpio_irq_unmask(struct irq_data *d) |
d056ab78 | 203 | { |
991ce74e | 204 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
8b81a7ab | 205 | struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); |
991ce74e | 206 | struct ep93xx_gpio *epg = gpiochip_get_data(gc); |
d056ab78 | 207 | |
216f3736 | 208 | gpiochip_enable_irq(gc, irqd_to_hwirq(d)); |
8b81a7ab NS |
209 | eic->int_unmasked |= BIT(d->irq & 7); |
210 | ep93xx_gpio_update_int_params(epg, eic); | |
d056ab78 HS |
211 | } |
212 | ||
213 | /* | |
214 | * gpio_int_type1 controls whether the interrupt is level (0) or | |
215 | * edge (1) triggered, while gpio_int_type2 controls whether it | |
216 | * triggers on low/falling (0) or high/rising (1). | |
217 | */ | |
c0afc916 | 218 | static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) |
d056ab78 | 219 | { |
991ce74e | 220 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
8b81a7ab | 221 | struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc); |
991ce74e | 222 | struct ep93xx_gpio *epg = gpiochip_get_data(gc); |
51ba88e3 LW |
223 | int offset = d->irq & 7; |
224 | int port_mask = BIT(offset); | |
d1735a2e | 225 | irq_flow_handler_t handler; |
d056ab78 | 226 | |
51ba88e3 | 227 | gc->direction_input(gc, offset); |
d056ab78 HS |
228 | |
229 | switch (type) { | |
230 | case IRQ_TYPE_EDGE_RISING: | |
8b81a7ab NS |
231 | eic->int_type1 |= port_mask; |
232 | eic->int_type2 |= port_mask; | |
d1735a2e | 233 | handler = handle_edge_irq; |
d056ab78 HS |
234 | break; |
235 | case IRQ_TYPE_EDGE_FALLING: | |
8b81a7ab NS |
236 | eic->int_type1 |= port_mask; |
237 | eic->int_type2 &= ~port_mask; | |
d1735a2e | 238 | handler = handle_edge_irq; |
d056ab78 HS |
239 | break; |
240 | case IRQ_TYPE_LEVEL_HIGH: | |
8b81a7ab NS |
241 | eic->int_type1 &= ~port_mask; |
242 | eic->int_type2 |= port_mask; | |
d1735a2e | 243 | handler = handle_level_irq; |
d056ab78 HS |
244 | break; |
245 | case IRQ_TYPE_LEVEL_LOW: | |
8b81a7ab NS |
246 | eic->int_type1 &= ~port_mask; |
247 | eic->int_type2 &= ~port_mask; | |
d1735a2e | 248 | handler = handle_level_irq; |
d056ab78 HS |
249 | break; |
250 | case IRQ_TYPE_EDGE_BOTH: | |
8b81a7ab | 251 | eic->int_type1 |= port_mask; |
d056ab78 | 252 | /* set initial polarity based on current input level */ |
51ba88e3 | 253 | if (gc->get(gc, offset)) |
8b81a7ab | 254 | eic->int_type2 &= ~port_mask; /* falling */ |
d056ab78 | 255 | else |
8b81a7ab | 256 | eic->int_type2 |= port_mask; /* rising */ |
d1735a2e | 257 | handler = handle_edge_irq; |
d056ab78 HS |
258 | break; |
259 | default: | |
d056ab78 HS |
260 | return -EINVAL; |
261 | } | |
262 | ||
72b2a9ef | 263 | irq_set_handler_locked(d, handler); |
d056ab78 | 264 | |
8b81a7ab | 265 | eic->int_enabled |= port_mask; |
d056ab78 | 266 | |
8b81a7ab | 267 | ep93xx_gpio_update_int_params(epg, eic); |
d056ab78 HS |
268 | |
269 | return 0; | |
270 | } | |
271 | ||
d056ab78 HS |
272 | /************************************************************************* |
273 | * gpiolib interface for EP93xx on-chip GPIOs | |
274 | *************************************************************************/ | |
1e4c8842 HS |
275 | struct ep93xx_gpio_bank { |
276 | const char *label; | |
277 | int data; | |
278 | int dir; | |
8b81a7ab | 279 | int irq; |
1e4c8842 | 280 | int base; |
3c38b3a3 | 281 | bool has_irq; |
d2b09196 LW |
282 | bool has_hierarchical_irq; |
283 | unsigned int irq_base; | |
b685004f RM |
284 | }; |
285 | ||
8b81a7ab | 286 | #define EP93XX_GPIO_BANK(_label, _data, _dir, _irq, _base, _has_irq, _has_hier, _irq_base) \ |
1e4c8842 HS |
287 | { \ |
288 | .label = _label, \ | |
289 | .data = _data, \ | |
290 | .dir = _dir, \ | |
8b81a7ab | 291 | .irq = _irq, \ |
1e4c8842 | 292 | .base = _base, \ |
3c38b3a3 | 293 | .has_irq = _has_irq, \ |
d2b09196 LW |
294 | .has_hierarchical_irq = _has_hier, \ |
295 | .irq_base = _irq_base, \ | |
1e4c8842 | 296 | } |
b685004f | 297 | |
1e4c8842 | 298 | static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = { |
d2b09196 | 299 | /* Bank A has 8 IRQs */ |
35d9e695 | 300 | EP93XX_GPIO_BANK("A", 0x00, 0x10, 0x90, 0, true, false, EP93XX_GPIO_A_IRQ_BASE), |
d2b09196 | 301 | /* Bank B has 8 IRQs */ |
35d9e695 | 302 | EP93XX_GPIO_BANK("B", 0x04, 0x14, 0xac, 8, true, false, EP93XX_GPIO_B_IRQ_BASE), |
8b81a7ab NS |
303 | EP93XX_GPIO_BANK("C", 0x08, 0x18, 0x00, 40, false, false, 0), |
304 | EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 0x00, 24, false, false, 0), | |
305 | EP93XX_GPIO_BANK("E", 0x20, 0x24, 0x00, 32, false, false, 0), | |
d2b09196 | 306 | /* Bank F has 8 IRQs */ |
35d9e695 | 307 | EP93XX_GPIO_BANK("F", 0x30, 0x34, 0x4c, 16, false, true, EP93XX_GPIO_F_IRQ_BASE), |
8b81a7ab NS |
308 | EP93XX_GPIO_BANK("G", 0x38, 0x3c, 0x00, 48, false, false, 0), |
309 | EP93XX_GPIO_BANK("H", 0x40, 0x44, 0x00, 56, false, false, 0), | |
1e4c8842 HS |
310 | }; |
311 | ||
991ce74e | 312 | static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset, |
2956b5d9 | 313 | unsigned long config) |
b685004f | 314 | { |
2956b5d9 MW |
315 | u32 debounce; |
316 | ||
317 | if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) | |
318 | return -ENOTSUPP; | |
b685004f | 319 | |
2956b5d9 | 320 | debounce = pinconf_to_config_argument(config); |
fd935fc4 | 321 | ep93xx_gpio_int_debounce(gc, offset, debounce ? true : false); |
b685004f RM |
322 | |
323 | return 0; | |
324 | } | |
325 | ||
216f3736 | 326 | static void ep93xx_irq_print_chip(struct irq_data *data, struct seq_file *p) |
28dc10eb | 327 | { |
216f3736 NS |
328 | struct gpio_chip *gc = irq_data_get_irq_chip_data(data); |
329 | ||
330 | seq_printf(p, dev_name(gc->parent)); | |
28dc10eb NS |
331 | } |
332 | ||
216f3736 NS |
333 | static const struct irq_chip gpio_eic_irq_chip = { |
334 | .name = "ep93xx-gpio-eic", | |
335 | .irq_ack = ep93xx_gpio_irq_ack, | |
336 | .irq_mask = ep93xx_gpio_irq_mask, | |
337 | .irq_unmask = ep93xx_gpio_irq_unmask, | |
338 | .irq_mask_ack = ep93xx_gpio_irq_mask_ack, | |
339 | .irq_set_type = ep93xx_gpio_irq_type, | |
340 | .irq_print_chip = ep93xx_irq_print_chip, | |
341 | .flags = IRQCHIP_IMMUTABLE, | |
342 | GPIOCHIP_IRQ_RESOURCE_HELPERS, | |
343 | }; | |
344 | ||
8b81a7ab | 345 | static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, |
d2b09196 | 346 | struct platform_device *pdev, |
991ce74e LW |
347 | struct ep93xx_gpio *epg, |
348 | struct ep93xx_gpio_bank *bank) | |
b685004f | 349 | { |
991ce74e LW |
350 | void __iomem *data = epg->base + bank->data; |
351 | void __iomem *dir = epg->base + bank->dir; | |
8b81a7ab | 352 | struct gpio_chip *gc = &egc->gc; |
d2b09196 LW |
353 | struct device *dev = &pdev->dev; |
354 | struct gpio_irq_chip *girq; | |
1e4c8842 | 355 | int err; |
b685004f | 356 | |
0f4630f3 | 357 | err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0); |
1e4c8842 HS |
358 | if (err) |
359 | return err; | |
b685004f | 360 | |
0f4630f3 LW |
361 | gc->label = bank->label; |
362 | gc->base = bank->base; | |
b685004f | 363 | |
d2b09196 LW |
364 | girq = &gc->irq; |
365 | if (bank->has_irq || bank->has_hierarchical_irq) { | |
2956b5d9 | 366 | gc->set_config = ep93xx_gpio_set_config; |
8b81a7ab NS |
367 | egc->eic = devm_kcalloc(dev, 1, |
368 | sizeof(*egc->eic), | |
369 | GFP_KERNEL); | |
370 | if (!egc->eic) | |
371 | return -ENOMEM; | |
372 | egc->eic->irq_offset = bank->irq; | |
216f3736 | 373 | gpio_irq_chip_set_chip(girq, &gpio_eic_irq_chip); |
d2b09196 LW |
374 | } |
375 | ||
376 | if (bank->has_irq) { | |
377 | int ab_parent_irq = platform_get_irq(pdev, 0); | |
378 | ||
379 | girq->parent_handler = ep93xx_gpio_ab_irq_handler; | |
380 | girq->num_parents = 1; | |
f6b61541 | 381 | girq->parents = devm_kcalloc(dev, girq->num_parents, |
d2b09196 LW |
382 | sizeof(*girq->parents), |
383 | GFP_KERNEL); | |
384 | if (!girq->parents) | |
385 | return -ENOMEM; | |
386 | girq->default_type = IRQ_TYPE_NONE; | |
387 | girq->handler = handle_level_irq; | |
388 | girq->parents[0] = ab_parent_irq; | |
389 | girq->first = bank->irq_base; | |
390 | } | |
391 | ||
392 | /* Only bank F has especially funky IRQ handling */ | |
393 | if (bank->has_hierarchical_irq) { | |
394 | int gpio_irq; | |
395 | int i; | |
396 | ||
397 | /* | |
398 | * FIXME: convert this to use hierarchical IRQ support! | |
78f85c73 | 399 | * this requires fixing the root irqchip to be hierarchical. |
d2b09196 LW |
400 | */ |
401 | girq->parent_handler = ep93xx_gpio_f_irq_handler; | |
402 | girq->num_parents = 8; | |
f6b61541 | 403 | girq->parents = devm_kcalloc(dev, girq->num_parents, |
d2b09196 LW |
404 | sizeof(*girq->parents), |
405 | GFP_KERNEL); | |
406 | if (!girq->parents) | |
407 | return -ENOMEM; | |
408 | /* Pick resources 1..8 for these IRQs */ | |
f6b61541 NS |
409 | for (i = 0; i < girq->num_parents; i++) { |
410 | girq->parents[i] = platform_get_irq(pdev, i + 1); | |
35d9e695 | 411 | gpio_irq = bank->irq_base + i; |
d2b09196 LW |
412 | irq_set_chip_data(gpio_irq, &epg->gc[5]); |
413 | irq_set_chip_and_handler(gpio_irq, | |
28dc10eb | 414 | girq->chip, |
d2b09196 LW |
415 | handle_level_irq); |
416 | irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); | |
417 | } | |
418 | girq->default_type = IRQ_TYPE_NONE; | |
419 | girq->handler = handle_level_irq; | |
35d9e695 | 420 | girq->first = bank->irq_base; |
d2b09196 | 421 | } |
b685004f | 422 | |
991ce74e | 423 | return devm_gpiochip_add_data(dev, gc, epg); |
b685004f RM |
424 | } |
425 | ||
3836309d | 426 | static int ep93xx_gpio_probe(struct platform_device *pdev) |
b685004f | 427 | { |
1d2bb17a | 428 | struct ep93xx_gpio *epg; |
1e4c8842 | 429 | int i; |
b685004f | 430 | |
6bdec6c7 | 431 | epg = devm_kzalloc(&pdev->dev, sizeof(*epg), GFP_KERNEL); |
1d2bb17a | 432 | if (!epg) |
1e4c8842 | 433 | return -ENOMEM; |
b685004f | 434 | |
6bdec6c7 | 435 | epg->base = devm_platform_ioremap_resource(pdev, 0); |
1d2bb17a LW |
436 | if (IS_ERR(epg->base)) |
437 | return PTR_ERR(epg->base); | |
5d046af0 | 438 | |
1e4c8842 | 439 | for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { |
8b81a7ab | 440 | struct ep93xx_gpio_chip *gc = &epg->gc[i]; |
1e4c8842 | 441 | struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; |
5d046af0 | 442 | |
d2b09196 | 443 | if (ep93xx_gpio_add_bank(gc, pdev, epg, bank)) |
1e4c8842 | 444 | dev_warn(&pdev->dev, "Unable to add gpio bank %s\n", |
a419a3d9 | 445 | bank->label); |
b685004f RM |
446 | } |
447 | ||
1e4c8842 | 448 | return 0; |
1e4c8842 | 449 | } |
fd015480 | 450 | |
1e4c8842 HS |
451 | static struct platform_driver ep93xx_gpio_driver = { |
452 | .driver = { | |
453 | .name = "gpio-ep93xx", | |
1e4c8842 HS |
454 | }, |
455 | .probe = ep93xx_gpio_probe, | |
456 | }; | |
457 | ||
458 | static int __init ep93xx_gpio_init(void) | |
459 | { | |
1e4c8842 | 460 | return platform_driver_register(&ep93xx_gpio_driver); |
b685004f | 461 | } |
1e4c8842 HS |
462 | postcore_initcall(ep93xx_gpio_init); |
463 | ||
464 | MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com> " | |
465 | "H Hartley Sweeten <hsweeten@visionengravers.com>"); | |
466 | MODULE_DESCRIPTION("EP93XX GPIO driver"); | |
467 | MODULE_LICENSE("GPL"); |