static int giu_get_irq(unsigned int irq) { uint16_t pendl, pendh, maskl, maskh; int i; pendl = giu_read(GIUINTSTATL); pendh = giu_read(GIUINTSTATH); maskl = giu_read(GIUINTENL); maskh = giu_read(GIUINTENH); maskl &= pendl; maskh &= pendh; if (maskl) { for (i = 0; i < 16; i++) { if (maskl & (1 << i)) return GIU_IRQ(i); } } else if (maskh) { for (i = 0; i < 16; i++) { if (maskh & (1 << i)) return GIU_IRQ(i + GIUINT_HIGH_OFFSET); } } printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", maskl, pendl, maskh, pendh); atomic_inc(&irq_err_count); return -EINVAL; }
static inline void vrc4173_icu_init(int cascade_irq) { int i; if (cascade_irq < GIU_IRQ(0) || cascade_irq > GIU_IRQ(15)) return; vrc4173_outw(0, VRC4173_MSYSINT1REG); vr41xx_set_irq_trigger(GIU_IRQ_TO_PIN(cascade_irq), TRIGGER_LEVEL, SIGNAL_THROUGH); vr41xx_set_irq_level(GIU_IRQ_TO_PIN(cascade_irq), LEVEL_LOW); for (i = VRC4173_IRQ_BASE; i <= VRC4173_IRQ_LAST; i++) irq_desc[i].handler = &vrc4173_irq_type; }
void giuint_irq_dispatch(struct pt_regs *regs) { struct vr41xx_giuint_cascade *cascade; unsigned int giuint_irq; int pin; pin = get_irq_pin_number(); if (pin < 0) return; disable_irq(GIUINT_CASCADE_IRQ); cascade = &giuint_cascade[pin]; giuint_irq = GIU_IRQ(pin); if (cascade->flag == GIUINT_CASCADE) { int irq = cascade->get_irq_number(giuint_irq); ack_giuint_irq(pin); if (irq >= 0) do_IRQ(irq, regs); end_giuint_irq(pin); } else { do_IRQ(giuint_irq, regs); } enable_irq(GIUINT_CASCADE_IRQ); }
int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq)) { unsigned int pin; int retval; if (irq < GIU_IRQ(0) || irq > GIU_IRQ(31)) return -EINVAL; if(!get_irq_number) return -EINVAL; pin = irq - GIU_IRQ(0); giuint_cascade[pin].flag = GIUINT_CASCADE; giuint_cascade[pin].get_irq_number = get_irq_number; retval = setup_irq(irq, &giu_cascade); if (retval) { giuint_cascade[pin].flag = GIUINT_NO_CASCADE; giuint_cascade[pin].get_irq_number = no_irq_number; } return retval; }
unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs) { struct vr41xx_giuint_cascade *cascade; unsigned int retval = 0; int giuint_irq, cascade_irq; disable_irq(GIUINT_CASCADE_IRQ); cascade = &giuint_cascade[pin]; giuint_irq = pin + GIU_IRQ(0); if (cascade->flag == GIUINT_CASCADE) { cascade_irq = cascade->get_irq_number(giuint_irq); disable_irq(giuint_irq); if (cascade_irq > 0) retval = do_IRQ(cascade_irq, regs); enable_irq(giuint_irq); } else retval = do_IRQ(giuint_irq, regs); enable_irq(GIUINT_CASCADE_IRQ); return retval; }
void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal) { uint16_t mask; if (pin < GIUINT_HIGH_OFFSET) { mask = 1 << pin; if (trigger != IRQ_TRIGGER_LEVEL) { giu_set(GIUINTTYPL, mask); if (signal == IRQ_SIGNAL_HOLD) giu_set(GIUINTHTSELL, mask); else giu_clear(GIUINTHTSELL, mask); if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { switch (trigger) { case IRQ_TRIGGER_EDGE_FALLING: giu_set(GIUFEDGEINHL, mask); giu_clear(GIUREDGEINHL, mask); break; case IRQ_TRIGGER_EDGE_RISING: giu_clear(GIUFEDGEINHL, mask); giu_set(GIUREDGEINHL, mask); break; default: giu_set(GIUFEDGEINHL, mask); giu_set(GIUREDGEINHL, mask); break; } } set_irq_chip_and_handler(GIU_IRQ(pin), &giuint_low_irq_chip, handle_edge_irq); } else { giu_clear(GIUINTTYPL, mask); giu_clear(GIUINTHTSELL, mask); set_irq_chip_and_handler(GIU_IRQ(pin), &giuint_low_irq_chip, handle_level_irq); } giu_write(GIUINTSTATL, mask); } else if (pin < GIUINT_HIGH_MAX) { mask = 1 << (pin - GIUINT_HIGH_OFFSET); if (trigger != IRQ_TRIGGER_LEVEL) { giu_set(GIUINTTYPH, mask); if (signal == IRQ_SIGNAL_HOLD) giu_set(GIUINTHTSELH, mask); else giu_clear(GIUINTHTSELH, mask); if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { switch (trigger) { case IRQ_TRIGGER_EDGE_FALLING: giu_set(GIUFEDGEINHH, mask); giu_clear(GIUREDGEINHH, mask); break; case IRQ_TRIGGER_EDGE_RISING: giu_clear(GIUFEDGEINHH, mask); giu_set(GIUREDGEINHH, mask); break; default: giu_set(GIUFEDGEINHH, mask); giu_set(GIUREDGEINHH, mask); break; } } set_irq_chip_and_handler(GIU_IRQ(pin), &giuint_high_irq_chip, handle_edge_irq); } else { giu_clear(GIUINTTYPH, mask); giu_clear(GIUINTHTSELH, mask); set_irq_chip_and_handler(GIU_IRQ(pin), &giuint_high_irq_chip, handle_level_irq); } giu_write(GIUINTSTATH, mask); } }
static int __devinit giu_probe(struct platform_device *dev) { unsigned long start, size, flags = 0; unsigned int nr_pins = 0; struct resource *res1, *res2 = NULL; void *base; int retval, i; switch (current_cpu_data.cputype) { case CPU_VR4111: case CPU_VR4121: start = GIU_TYPE1_START; size = GIU_TYPE1_SIZE; flags = GPIO_HAS_PULLUPDOWN_IO; nr_pins = 50; break; case CPU_VR4122: case CPU_VR4131: start = GIU_TYPE2_START; size = GIU_TYPE2_SIZE; nr_pins = 36; break; case CPU_VR4133: start = GIU_TYPE3_START; size = GIU_TYPE3_SIZE; flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; nr_pins = 48; break; default: return -ENODEV; } res1 = request_mem_region(start, size, "GIU"); if (res1 == NULL) return -EBUSY; base = ioremap(start, size); if (base == NULL) { release_resource(res1); return -ENOMEM; } if (flags & GPIO_HAS_PULLUPDOWN_IO) { res2 = request_mem_region(GIU_PULLUPDOWN_START, GIU_PULLUPDOWN_SIZE, "GIU"); if (res2 == NULL) { iounmap(base); release_resource(res1); return -EBUSY; } } retval = register_chrdev(major, "GIU", &gpio_fops); if (retval < 0) { iounmap(base); release_resource(res1); release_resource(res2); return retval; } if (major == 0) { major = retval; printk(KERN_INFO "GIU: major number %d\n", major); } spin_lock_init(&giu_lock); giu_base = base; giu_resource1 = res1; giu_resource2 = res2; giu_flags = flags; giu_nr_pins = nr_pins; giu_write(GIUINTENL, 0); giu_write(GIUINTENH, 0); for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { if (i < GIU_IRQ(GIUINT_HIGH_OFFSET)) irq_desc[i].handler = &giuint_low_irq_type; else irq_desc[i].handler = &giuint_high_irq_type; } return cascade_irq(GIUINT_IRQ, giu_get_irq); }