diff options
Diffstat (limited to 'arch/arm/plat-orion/gpio.c')
-rw-r--r-- | arch/arm/plat-orion/gpio.c | 112 |
1 files changed, 36 insertions, 76 deletions
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index a431a138f402..5b4fffab1eb4 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c | |||
@@ -321,59 +321,16 @@ EXPORT_SYMBOL(orion_gpio_set_blink); | |||
321 | * polarity LEVEL mask | 321 | * polarity LEVEL mask |
322 | * | 322 | * |
323 | ****************************************************************************/ | 323 | ****************************************************************************/ |
324 | static void gpio_irq_ack(struct irq_data *d) | ||
325 | { | ||
326 | struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); | ||
327 | int type = irqd_get_trigger_type(d); | ||
328 | |||
329 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { | ||
330 | int pin = d->irq - ochip->secondary_irq_base; | ||
331 | |||
332 | writel(~(1 << pin), GPIO_EDGE_CAUSE(ochip)); | ||
333 | } | ||
334 | } | ||
335 | |||
336 | static void gpio_irq_mask(struct irq_data *d) | ||
337 | { | ||
338 | struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); | ||
339 | int type = irqd_get_trigger_type(d); | ||
340 | void __iomem *reg; | ||
341 | int pin; | ||
342 | |||
343 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) | ||
344 | reg = GPIO_EDGE_MASK(ochip); | ||
345 | else | ||
346 | reg = GPIO_LEVEL_MASK(ochip); | ||
347 | |||
348 | pin = d->irq - ochip->secondary_irq_base; | ||
349 | |||
350 | writel(readl(reg) & ~(1 << pin), reg); | ||
351 | } | ||
352 | |||
353 | static void gpio_irq_unmask(struct irq_data *d) | ||
354 | { | ||
355 | struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); | ||
356 | int type = irqd_get_trigger_type(d); | ||
357 | void __iomem *reg; | ||
358 | int pin; | ||
359 | |||
360 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) | ||
361 | reg = GPIO_EDGE_MASK(ochip); | ||
362 | else | ||
363 | reg = GPIO_LEVEL_MASK(ochip); | ||
364 | |||
365 | pin = d->irq - ochip->secondary_irq_base; | ||
366 | |||
367 | writel(readl(reg) | (1 << pin), reg); | ||
368 | } | ||
369 | 324 | ||
370 | static int gpio_irq_set_type(struct irq_data *d, u32 type) | 325 | static int gpio_irq_set_type(struct irq_data *d, u32 type) |
371 | { | 326 | { |
372 | struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); | 327 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); |
328 | struct irq_chip_type *ct = irq_data_get_chip_type(d); | ||
329 | struct orion_gpio_chip *ochip = gc->private; | ||
373 | int pin; | 330 | int pin; |
374 | u32 u; | 331 | u32 u; |
375 | 332 | ||
376 | pin = d->irq - ochip->secondary_irq_base; | 333 | pin = d->irq - gc->irq_base; |
377 | 334 | ||
378 | u = readl(GPIO_IO_CONF(ochip)) & (1 << pin); | 335 | u = readl(GPIO_IO_CONF(ochip)) & (1 << pin); |
379 | if (!u) { | 336 | if (!u) { |
@@ -382,18 +339,14 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type) | |||
382 | return -EINVAL; | 339 | return -EINVAL; |
383 | } | 340 | } |
384 | 341 | ||
385 | /* | 342 | type &= IRQ_TYPE_SENSE_MASK; |
386 | * Set edge/level type. | 343 | if (type == IRQ_TYPE_NONE) |
387 | */ | ||
388 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { | ||
389 | __irq_set_handler_locked(d->irq, handle_edge_irq); | ||
390 | } else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { | ||
391 | __irq_set_handler_locked(d->irq, handle_level_irq); | ||
392 | } else { | ||
393 | printk(KERN_ERR "failed to set irq=%d (type=%d)\n", | ||
394 | d->irq, type); | ||
395 | return -EINVAL; | 344 | return -EINVAL; |
396 | } | 345 | |
346 | /* Check if we need to change chip and handler */ | ||
347 | if (!(ct->type & type)) | ||
348 | if (irq_setup_alt_chip(d, type)) | ||
349 | return -EINVAL; | ||
397 | 350 | ||
398 | /* | 351 | /* |
399 | * Configure interrupt polarity. | 352 | * Configure interrupt polarity. |
@@ -425,19 +378,12 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type) | |||
425 | return 0; | 378 | return 0; |
426 | } | 379 | } |
427 | 380 | ||
428 | struct irq_chip orion_gpio_irq_chip = { | ||
429 | .name = "orion_gpio_irq", | ||
430 | .irq_ack = gpio_irq_ack, | ||
431 | .irq_mask = gpio_irq_mask, | ||
432 | .irq_unmask = gpio_irq_unmask, | ||
433 | .irq_set_type = gpio_irq_set_type, | ||
434 | }; | ||
435 | |||
436 | void __init orion_gpio_init(int gpio_base, int ngpio, | 381 | void __init orion_gpio_init(int gpio_base, int ngpio, |
437 | u32 base, int mask_offset, int secondary_irq_base) | 382 | u32 base, int mask_offset, int secondary_irq_base) |
438 | { | 383 | { |
439 | struct orion_gpio_chip *ochip; | 384 | struct orion_gpio_chip *ochip; |
440 | int i; | 385 | struct irq_chip_generic *gc; |
386 | struct irq_chip_type *ct; | ||
441 | 387 | ||
442 | if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips)) | 388 | if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips)) |
443 | return; | 389 | return; |
@@ -471,15 +417,29 @@ void __init orion_gpio_init(int gpio_base, int ngpio, | |||
471 | writel(0, GPIO_EDGE_MASK(ochip)); | 417 | writel(0, GPIO_EDGE_MASK(ochip)); |
472 | writel(0, GPIO_LEVEL_MASK(ochip)); | 418 | writel(0, GPIO_LEVEL_MASK(ochip)); |
473 | 419 | ||
474 | for (i = 0; i < ngpio; i++) { | 420 | gc = irq_alloc_generic_chip("orion_gpio_irq", 2, secondary_irq_base, |
475 | unsigned int irq = secondary_irq_base + i; | 421 | ochip->base, handle_level_irq); |
476 | 422 | gc->private = ochip; | |
477 | irq_set_chip_and_handler(irq, &orion_gpio_irq_chip, | 423 | |
478 | handle_level_irq); | 424 | ct = gc->chip_types; |
479 | irq_set_chip_data(irq, ochip); | 425 | ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; |
480 | irq_set_status_flags(irq, IRQ_LEVEL); | 426 | ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; |
481 | set_irq_flags(irq, IRQF_VALID); | 427 | ct->chip.irq_mask = irq_gc_mask_clr_bit; |
482 | } | 428 | ct->chip.irq_unmask = irq_gc_mask_set_bit; |
429 | ct->chip.irq_set_type = gpio_irq_set_type; | ||
430 | |||
431 | ct++; | ||
432 | ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF; | ||
433 | ct->regs.ack = GPIO_EDGE_CAUSE_OFF; | ||
434 | ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | ||
435 | ct->chip.irq_ack = irq_gc_ack; | ||
436 | ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||
437 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||
438 | ct->chip.irq_set_type = gpio_irq_set_type; | ||
439 | ct->handler = handle_edge_irq; | ||
440 | |||
441 | irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE, | ||
442 | IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); | ||
483 | } | 443 | } |
484 | 444 | ||
485 | void orion_gpio_irq_handler(int pinoff) | 445 | void orion_gpio_irq_handler(int pinoff) |