aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorAndreas Larsson <andreas@gaisler.com>2013-04-17 08:36:51 -0400
committerLinus Walleij <linus.walleij@linaro.org>2013-04-26 02:52:38 -0400
commit08ffb2229fafc2c3a696b325a74bf4198d6b91d7 (patch)
treeac7a847bcb1f312c57762b4c514f971ee275d1bb /drivers/gpio
parentddb27f3bf771b53e0e7aa93d0186ea5c03381e23 (diff)
gpio: grgpio: Add irq support
The drivers sets up an irq domain and hands out unique irqs to irq capable gpio lines regardless of how underlying irq maps to gpio lines. Any gpio line can map to any one or none of the irqs of the core, independently of each other. Signed-off-by: Andreas Larsson <andreas@gaisler.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpio-grgpio.c362
1 files changed, 359 insertions, 3 deletions
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 466a1c757fae..8e08b8647655 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -32,6 +32,9 @@
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <linux/err.h> 33#include <linux/err.h>
34#include <linux/basic_mmio_gpio.h> 34#include <linux/basic_mmio_gpio.h>
35#include <linux/interrupt.h>
36#include <linux/irq.h>
37#include <linux/irqdomain.h>
35 38
36#define GRGPIO_MAX_NGPIO 32 39#define GRGPIO_MAX_NGPIO 32
37 40
@@ -44,10 +47,49 @@
44#define GRGPIO_BYPASS 0x18 47#define GRGPIO_BYPASS 0x18
45#define GRGPIO_IMAP_BASE 0x20 48#define GRGPIO_IMAP_BASE 0x20
46 49
50/* Structure for an irq of the core - called an underlying irq */
51struct grgpio_uirq {
52 u8 refcnt; /* Reference counter to manage requesting/freeing of uirq */
53 u8 uirq; /* Underlying irq of the gpio driver */
54};
55
56/*
57 * Structure for an irq of a gpio line handed out by this driver. The index is
58 * used to map to the corresponding underlying irq.
59 */
60struct grgpio_lirq {
61 s8 index; /* Index into struct grgpio_priv's uirqs, or -1 */
62 u8 irq; /* irq for the gpio line */
63};
64
47struct grgpio_priv { 65struct grgpio_priv {
48 struct bgpio_chip bgc; 66 struct bgpio_chip bgc;
49 void __iomem *regs; 67 void __iomem *regs;
50 struct device *dev; 68 struct device *dev;
69
70 u32 imask; /* irq mask shadow register */
71
72 /*
73 * The grgpio core can have multiple "underlying" irqs. The gpio lines
74 * can be mapped to any one or none of these underlying irqs
75 * independently of each other. This driver sets up an irq domain and
76 * hands out separate irqs to each gpio line
77 */
78 struct irq_domain *domain;
79
80 /*
81 * This array contains information on each underlying irq, each
82 * irq of the grgpio core itself.
83 */
84 struct grgpio_uirq uirqs[GRGPIO_MAX_NGPIO];
85
86 /*
87 * This array contains information for each gpio line on the irqs
88 * obtains from this driver. An index value of -1 for a certain gpio
89 * line indicates that the line has no irq. Otherwise the index connects
90 * the irq to the underlying irq by pointing into the uirqs array.
91 */
92 struct grgpio_lirq lirqs[GRGPIO_MAX_NGPIO];
51}; 93};
52 94
53static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc) 95static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc)
@@ -57,6 +99,246 @@ static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc)
57 return container_of(bgc, struct grgpio_priv, bgc); 99 return container_of(bgc, struct grgpio_priv, bgc);
58} 100}
59 101
102static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset,
103 int val)
104{
105 struct bgpio_chip *bgc = &priv->bgc;
106 unsigned long mask = bgc->pin2mask(bgc, offset);
107 unsigned long flags;
108
109 spin_lock_irqsave(&bgc->lock, flags);
110
111 if (val)
112 priv->imask |= mask;
113 else
114 priv->imask &= ~mask;
115 bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
116
117 spin_unlock_irqrestore(&bgc->lock, flags);
118}
119
120static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset)
121{
122 struct grgpio_priv *priv = grgpio_gc_to_priv(gc);
123
124 if (offset > gc->ngpio)
125 return -ENXIO;
126
127 if (priv->lirqs[offset].index < 0)
128 return -ENXIO;
129
130 return irq_create_mapping(priv->domain, offset);
131}
132
133/* -------------------- IRQ chip functions -------------------- */
134
135static int grgpio_irq_set_type(struct irq_data *d, unsigned int type)
136{
137 struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
138 unsigned long flags;
139 u32 mask = BIT(d->hwirq);
140 u32 ipol;
141 u32 iedge;
142 u32 pol;
143 u32 edge;
144
145 switch (type) {
146 case IRQ_TYPE_LEVEL_LOW:
147 pol = 0;
148 edge = 0;
149 break;
150 case IRQ_TYPE_LEVEL_HIGH:
151 pol = mask;
152 edge = 0;
153 break;
154 case IRQ_TYPE_EDGE_FALLING:
155 pol = 0;
156 edge = mask;
157 break;
158 case IRQ_TYPE_EDGE_RISING:
159 pol = mask;
160 edge = mask;
161 break;
162 default:
163 return -EINVAL;
164 }
165
166 spin_lock_irqsave(&priv->bgc.lock, flags);
167
168 ipol = priv->bgc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask;
169 iedge = priv->bgc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask;
170
171 priv->bgc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol);
172 priv->bgc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge);
173
174 spin_unlock_irqrestore(&priv->bgc.lock, flags);
175
176 return 0;
177}
178
179static void grgpio_irq_mask(struct irq_data *d)
180{
181 struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
182 int offset = d->hwirq;
183
184 grgpio_set_imask(priv, offset, 0);
185}
186
187static void grgpio_irq_unmask(struct irq_data *d)
188{
189 struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
190 int offset = d->hwirq;
191
192 grgpio_set_imask(priv, offset, 1);
193}
194
195static struct irq_chip grgpio_irq_chip = {
196 .name = "grgpio",
197 .irq_mask = grgpio_irq_mask,
198 .irq_unmask = grgpio_irq_unmask,
199 .irq_set_type = grgpio_irq_set_type,
200};
201
202static irqreturn_t grgpio_irq_handler(int irq, void *dev)
203{
204 struct grgpio_priv *priv = dev;
205 int ngpio = priv->bgc.gc.ngpio;
206 unsigned long flags;
207 int i;
208 int match = 0;
209
210 spin_lock_irqsave(&priv->bgc.lock, flags);
211
212 /*
213 * For each gpio line, call its interrupt handler if it its underlying
214 * irq matches the current irq that is handled.
215 */
216 for (i = 0; i < ngpio; i++) {
217 struct grgpio_lirq *lirq = &priv->lirqs[i];
218
219 if (priv->imask & BIT(i) && lirq->index >= 0 &&
220 priv->uirqs[lirq->index].uirq == irq) {
221 generic_handle_irq(lirq->irq);
222 match = 1;
223 }
224 }
225
226 spin_unlock_irqrestore(&priv->bgc.lock, flags);
227
228 if (!match)
229 dev_warn(priv->dev, "No gpio line matched irq %d\n", irq);
230
231 return IRQ_HANDLED;
232}
233
234/*
235 * This function will be called as a consequence of the call to
236 * irq_create_mapping in grgpio_to_irq
237 */
238int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
239 irq_hw_number_t hwirq)
240{
241 struct grgpio_priv *priv = d->host_data;
242 struct grgpio_lirq *lirq;
243 struct grgpio_uirq *uirq;
244 unsigned long flags;
245 int offset = hwirq;
246 int ret = 0;
247
248 if (!priv)
249 return -EINVAL;
250
251 lirq = &priv->lirqs[offset];
252 if (lirq->index < 0)
253 return -EINVAL;
254
255 dev_dbg(priv->dev, "Mapping irq %d for gpio line %d\n",
256 irq, offset);
257
258 spin_lock_irqsave(&priv->bgc.lock, flags);
259
260 /* Request underlying irq if not already requested */
261 lirq->irq = irq;
262 uirq = &priv->uirqs[lirq->index];
263 if (uirq->refcnt == 0) {
264 ret = request_irq(uirq->uirq, grgpio_irq_handler, 0,
265 dev_name(priv->dev), priv);
266 if (ret) {
267 dev_err(priv->dev,
268 "Could not request underlying irq %d\n",
269 uirq->uirq);
270
271 spin_unlock_irqrestore(&priv->bgc.lock, flags);
272
273 return ret;
274 }
275 }
276 uirq->refcnt++;
277
278 spin_unlock_irqrestore(&priv->bgc.lock, flags);
279
280 /* Setup irq */
281 irq_set_chip_data(irq, priv);
282 irq_set_chip_and_handler(irq, &grgpio_irq_chip,
283 handle_simple_irq);
284 irq_clear_status_flags(irq, IRQ_NOREQUEST);
285#ifdef CONFIG_ARM
286 set_irq_flags(irq, IRQF_VALID);
287#else
288 irq_set_noprobe(irq);
289#endif
290
291 return ret;
292}
293
294void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
295{
296 struct grgpio_priv *priv = d->host_data;
297 int index;
298 struct grgpio_lirq *lirq;
299 struct grgpio_uirq *uirq;
300 unsigned long flags;
301 int ngpio = priv->bgc.gc.ngpio;
302 int i;
303
304#ifdef CONFIG_ARM
305 set_irq_flags(irq, 0);
306#endif
307 irq_set_chip_and_handler(irq, NULL, NULL);
308 irq_set_chip_data(irq, NULL);
309
310 spin_lock_irqsave(&priv->bgc.lock, flags);
311
312 /* Free underlying irq if last user unmapped */
313 index = -1;
314 for (i = 0; i < ngpio; i++) {
315 lirq = &priv->lirqs[i];
316 if (lirq->irq == irq) {
317 grgpio_set_imask(priv, i, 0);
318 lirq->irq = 0;
319 index = lirq->index;
320 break;
321 }
322 }
323 WARN_ON(index < 0);
324
325 if (index >= 0) {
326 uirq = &priv->uirqs[lirq->index];
327 uirq->refcnt--;
328 if (uirq->refcnt == 0)
329 free_irq(uirq->uirq, priv);
330 }
331
332 spin_unlock_irqrestore(&priv->bgc.lock, flags);
333}
334
335static struct irq_domain_ops grgpio_irq_domain_ops = {
336 .map = grgpio_irq_map,
337 .unmap = grgpio_irq_unmap,
338};
339
340/* ------------------------------------------------------------ */
341
60static int grgpio_probe(struct platform_device *ofdev) 342static int grgpio_probe(struct platform_device *ofdev)
61{ 343{
62 struct device_node *np = ofdev->dev.of_node; 344 struct device_node *np = ofdev->dev.of_node;
@@ -67,6 +349,9 @@ static int grgpio_probe(struct platform_device *ofdev)
67 struct resource *res; 349 struct resource *res;
68 int err; 350 int err;
69 u32 prop; 351 u32 prop;
352 s32 *irqmap;
353 int size;
354 int i;
70 355
71 priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); 356 priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
72 if (!priv) 357 if (!priv)
@@ -87,11 +372,13 @@ static int grgpio_probe(struct platform_device *ofdev)
87 } 372 }
88 373
89 priv->regs = regs; 374 priv->regs = regs;
375 priv->imask = bgc->read_reg(regs + GRGPIO_IMASK);
90 priv->dev = &ofdev->dev; 376 priv->dev = &ofdev->dev;
91 377
92 gc = &bgc->gc; 378 gc = &bgc->gc;
93 gc->of_node = np; 379 gc->of_node = np;
94 gc->owner = THIS_MODULE; 380 gc->owner = THIS_MODULE;
381 gc->to_irq = grgpio_to_irq;
95 gc->label = np->full_name; 382 gc->label = np->full_name;
96 gc->base = -1; 383 gc->base = -1;
97 384
@@ -104,6 +391,51 @@ static int grgpio_probe(struct platform_device *ofdev)
104 gc->ngpio = prop; 391 gc->ngpio = prop;
105 } 392 }
106 393
394 /*
395 * The irqmap contains the index values indicating which underlying irq,
396 * if anyone, is connected to that line
397 */
398 irqmap = (s32 *)of_get_property(np, "irqmap", &size);
399 if (irqmap) {
400 if (size < gc->ngpio) {
401 dev_err(&ofdev->dev,
402 "irqmap shorter than ngpio (%d < %d)\n",
403 size, gc->ngpio);
404 return -EINVAL;
405 }
406
407 priv->domain = irq_domain_add_linear(np, gc->ngpio,
408 &grgpio_irq_domain_ops,
409 priv);
410 if (!priv->domain) {
411 dev_err(&ofdev->dev, "Could not add irq domain\n");
412 return -EINVAL;
413 }
414
415 for (i = 0; i < gc->ngpio; i++) {
416 struct grgpio_lirq *lirq;
417 int ret;
418
419 lirq = &priv->lirqs[i];
420 lirq->index = irqmap[i];
421
422 if (lirq->index < 0)
423 continue;
424
425 ret = platform_get_irq(ofdev, lirq->index);
426 if (ret <= 0) {
427 /*
428 * Continue without irq functionality for that
429 * gpio line
430 */
431 dev_err(priv->dev,
432 "Failed to get irq for offset %d\n", i);
433 continue;
434 }
435 priv->uirqs[lirq->index].uirq = ret;
436 }
437 }
438
107 platform_set_drvdata(ofdev, priv); 439 platform_set_drvdata(ofdev, priv);
108 440
109 err = gpiochip_add(gc); 441 err = gpiochip_add(gc);
@@ -112,8 +444,8 @@ static int grgpio_probe(struct platform_device *ofdev)
112 return err; 444 return err;
113 } 445 }
114 446
115 dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d\n", 447 dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n",
116 priv->regs, gc->base, gc->ngpio); 448 priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off");
117 449
118 return 0; 450 return 0;
119} 451}
@@ -121,8 +453,32 @@ static int grgpio_probe(struct platform_device *ofdev)
121static int grgpio_remove(struct platform_device *ofdev) 453static int grgpio_remove(struct platform_device *ofdev)
122{ 454{
123 struct grgpio_priv *priv = platform_get_drvdata(ofdev); 455 struct grgpio_priv *priv = platform_get_drvdata(ofdev);
456 unsigned long flags;
457 int i;
458 int ret = 0;
459
460 spin_lock_irqsave(&priv->bgc.lock, flags);
461
462 if (priv->domain) {
463 for (i = 0; i < GRGPIO_MAX_NGPIO; i++) {
464 if (priv->uirqs[i].refcnt != 0) {
465 ret = -EBUSY;
466 goto out;
467 }
468 }
469 }
470
471 ret = gpiochip_remove(&priv->bgc.gc);
472 if (ret)
473 goto out;
474
475 if (priv->domain)
476 irq_domain_remove(priv->domain);
477
478out:
479 spin_unlock_irqrestore(&priv->bgc.lock, flags);
124 480
125 return gpiochip_remove(&priv->bgc.gc); 481 return ret;
126} 482}
127 483
128static struct of_device_id grgpio_match[] = { 484static struct of_device_id grgpio_match[] = {