diff options
Diffstat (limited to 'arch/sh/cchips/hd6446x/hd64461.c')
| -rw-r--r-- | arch/sh/cchips/hd6446x/hd64461.c | 64 |
1 files changed, 35 insertions, 29 deletions
diff --git a/arch/sh/cchips/hd6446x/hd64461.c b/arch/sh/cchips/hd6446x/hd64461.c index 27ceeb948bb..e9735616bdc 100644 --- a/arch/sh/cchips/hd6446x/hd64461.c +++ b/arch/sh/cchips/hd6446x/hd64461.c @@ -17,8 +17,9 @@ /* This belongs in cpu specific */ #define INTC_ICR1 0xA4140010UL -static void hd64461_mask_irq(unsigned int irq) +static void hd64461_mask_irq(struct irq_data *data) { + unsigned int irq = data->irq; unsigned short nimr; unsigned short mask = 1 << (irq - HD64461_IRQBASE); @@ -27,8 +28,9 @@ static void hd64461_mask_irq(unsigned int irq) __raw_writew(nimr, HD64461_NIMR); } -static void hd64461_unmask_irq(unsigned int irq) +static void hd64461_unmask_irq(struct irq_data *data) { + unsigned int irq = data->irq; unsigned short nimr; unsigned short mask = 1 << (irq - HD64461_IRQBASE); @@ -37,49 +39,45 @@ static void hd64461_unmask_irq(unsigned int irq) __raw_writew(nimr, HD64461_NIMR); } -static void hd64461_mask_and_ack_irq(unsigned int irq) +static void hd64461_mask_and_ack_irq(struct irq_data *data) { - hd64461_mask_irq(irq); + hd64461_mask_irq(data); + #ifdef CONFIG_HD64461_ENABLER - if (irq == HD64461_IRQBASE + 13) + if (data->irq == HD64461_IRQBASE + 13) __raw_writeb(0x00, HD64461_PCC1CSCR); #endif } static struct irq_chip hd64461_irq_chip = { .name = "HD64461-IRQ", - .mask = hd64461_mask_irq, - .mask_ack = hd64461_mask_and_ack_irq, - .unmask = hd64461_unmask_irq, + .irq_mask = hd64461_mask_irq, + .irq_mask_ack = hd64461_mask_and_ack_irq, + .irq_unmask = hd64461_unmask_irq, }; -int hd64461_irq_demux(int irq) +static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc) { - if (irq == CONFIG_HD64461_IRQ) { - unsigned short bit; - unsigned short nirr = inw(HD64461_NIRR); - unsigned short nimr = inw(HD64461_NIMR); - int i; - - nirr &= ~nimr; - for (bit = 1, i = 0; i < 16; bit <<= 1, i++) - if (nirr & bit) - break; - irq = HD64461_IRQBASE + i; + unsigned short intv = __raw_readw(HD64461_NIRR); + unsigned int ext_irq = HD64461_IRQBASE; + + intv &= (1 << HD64461_IRQ_NUM) - 1; + + for (; intv; intv >>= 1, ext_irq++) { + if (!(intv & 1)) + continue; + + generic_handle_irq(ext_irq); } - return irq; } int __init setup_hd64461(void) { - int i; - - if (!MACH_HD64461) - return 0; + int irq_base, i; printk(KERN_INFO "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n", - CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE, + HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE, HD64461_IRQBASE + 15); /* Should be at processor specific part.. */ @@ -88,11 +86,19 @@ int __init setup_hd64461(void) #endif __raw_writew(0xffff, HD64461_NIMR); - /* IRQ 80 -> 95 belongs to HD64461 */ - for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) - set_irq_chip_and_handler(i, &hd64461_irq_chip, + irq_base = irq_alloc_descs(HD64461_IRQBASE, HD64461_IRQBASE, 16, -1); + if (IS_ERR_VALUE(irq_base)) { + pr_err("%s: failed hooking irqs for HD64461\n", __func__); + return irq_base; + } + + for (i = 0; i < 16; i++) + irq_set_chip_and_handler(irq_base + i, &hd64461_irq_chip, handle_level_irq); + irq_set_chained_handler(CONFIG_HD64461_IRQ, hd64461_irq_demux); + irq_set_irq_type(CONFIG_HD64461_IRQ, IRQ_TYPE_LEVEL_LOW); + #ifdef CONFIG_HD64461_ENABLER printk(KERN_INFO "HD64461: enabling PCMCIA devices\n"); __raw_writeb(0x4c, HD64461_PCC1CSCIER); |
