^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2000 YAEGASHI Takeshi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Hitachi HD64461 companion chip support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/param.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/hd64461.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /* This belongs in cpu specific */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define INTC_ICR1 0xA4140010UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static void hd64461_mask_irq(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned int irq = data->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) unsigned short nimr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned short mask = 1 << (irq - HD64461_IRQBASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) nimr = __raw_readw(HD64461_NIMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) nimr |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) __raw_writew(nimr, HD64461_NIMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static void hd64461_unmask_irq(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned int irq = data->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned short nimr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned short mask = 1 << (irq - HD64461_IRQBASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) nimr = __raw_readw(HD64461_NIMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) nimr &= ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) __raw_writew(nimr, HD64461_NIMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static void hd64461_mask_and_ack_irq(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) hd64461_mask_irq(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #ifdef CONFIG_HD64461_ENABLER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (data->irq == HD64461_IRQBASE + 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) __raw_writeb(0x00, HD64461_PCC1CSCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static struct irq_chip hd64461_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .name = "HD64461-IRQ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .irq_mask = hd64461_mask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .irq_mask_ack = hd64461_mask_and_ack_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .irq_unmask = hd64461_unmask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static void hd64461_irq_demux(struct irq_desc *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unsigned short intv = __raw_readw(HD64461_NIRR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned int ext_irq = HD64461_IRQBASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) intv &= (1 << HD64461_IRQ_NUM) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) for (; intv; intv >>= 1, ext_irq++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (!(intv & 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) generic_handle_irq(ext_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) int __init setup_hd64461(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int irq_base, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) HD64461_IRQBASE + 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* Should be at processor specific part.. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #if defined(CONFIG_CPU_SUBTYPE_SH7709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) __raw_writew(0x2240, INTC_ICR1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) __raw_writew(0xffff, HD64461_NIMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) irq_base = irq_alloc_descs(HD64461_IRQBASE, HD64461_IRQBASE, 16, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (IS_ERR_VALUE(irq_base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) pr_err("%s: failed hooking irqs for HD64461\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return irq_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) for (i = 0; i < 16; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) irq_set_chip_and_handler(irq_base + i, &hd64461_irq_chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) handle_level_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) irq_set_chained_handler(CONFIG_HD64461_IRQ, hd64461_irq_demux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) irq_set_irq_type(CONFIG_HD64461_IRQ, IRQ_TYPE_LEVEL_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #ifdef CONFIG_HD64461_ENABLER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) printk(KERN_INFO "HD64461: enabling PCMCIA devices\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) __raw_writeb(0x4c, HD64461_PCC1CSCIER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) __raw_writeb(0x00, HD64461_PCC1CSCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) module_init(setup_hd64461);