/* -------------------------------------------------------------------- */ /* setup_voyagergx.c: */ /* -------------------------------------------------------------------- */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Copyright 2003 (c) Lineo uSolutions,Inc. */ #include #include #include #include #include static void disable_voyagergx_irq(unsigned int irq) { unsigned long val; unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); val = readl((void __iomem *)VOYAGER_INT_MASK); val &= ~mask; writel(val, (void __iomem *)VOYAGER_INT_MASK); } static void enable_voyagergx_irq(unsigned int irq) { unsigned long val; unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); val = readl((void __iomem *)VOYAGER_INT_MASK); val |= mask; writel(val, (void __iomem *)VOYAGER_INT_MASK); } static void mask_and_ack_voyagergx(unsigned int irq) { disable_voyagergx_irq(irq); } static void end_voyagergx_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_voyagergx_irq(irq); } static unsigned int startup_voyagergx_irq(unsigned int irq) { enable_voyagergx_irq(irq); return 0; } static void shutdown_voyagergx_irq(unsigned int irq) { disable_voyagergx_irq(irq); } static struct hw_interrupt_type voyagergx_irq_type = { .typename = "VOYAGERGX-IRQ", .startup = startup_voyagergx_irq, .shutdown = shutdown_voyagergx_irq, .enable = enable_voyagergx_irq, .disable = disable_voyagergx_irq, .ack = mask_and_ack_voyagergx, .end = end_voyagergx_irq, }; static irqreturn_t voyagergx_interrupt(int irq, void *dev_id) { printk(KERN_INFO "VoyagerGX: spurious interrupt, status: 0x%x\n", (unsigned int)readl((void __iomem *)INT_STATUS)); return IRQ_HANDLED; } static struct { int (*func)(int, void *); void *dev; } voyagergx_demux[VOYAGER_IRQ_NUM]; void voyagergx_register_irq_demux(int irq, int (*demux)(int irq, void *dev), void *dev) { voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux; voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev; } void voyagergx_unregister_irq_demux(int irq) { voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0; } int voyagergx_irq_demux(int irq) { if (irq == IRQ_VOYAGER ) { unsigned long i = 0, bit __attribute__ ((unused)); unsigned long val = readl((void __iomem *)INT_STATUS); if (val & (1 << 1)) i = 1; else if (val & (1 << 2)) i = 2; else if (val & (1 << 6)) i = 6; else if (val & (1 << 10)) i = 10; else if (val & (1 << 11)) i = 11; else if (val & (1 << 12)) i = 12; else if (val & (1 << 17)) i = 17; else printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val); pr_debug("voyagergx_irq_demux %ld \n", i); if (i < VOYAGER_IRQ_NUM) { irq = VOYAGER_IRQ_BASE + i; if (voyagergx_demux[i].func != 0) irq = voyagergx_demux[i].func(irq, voyagergx_demux[i].dev); } } return irq; } static struct irqaction irq0 = { .name = "voyagergx", .handler = voyagergx_interrupt, .flags = IRQF_DISABLED, .mask = CPU_MASK_NONE, }; void __init setup_voyagergx_irq(void) { int i, flag; printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n", VOYAGER_BASE, IRQ_VOYAGER, VOYAGER_IRQ_BASE, VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1); for (i=0; i