1/* 2 * linux/arch/arm/mach-w90x900/irq.c 3 * 4 * based on linux/arch/arm/plat-s3c24xx/irq.c by Ben Dooks 5 * 6 * Copyright (c) 2008 Nuvoton technology corporation 7 * All rights reserved. 8 * 9 * Wan ZongShun <mcuos.com@gmail.com> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation;version 2 of the License. 14 * 15 */ 16 17#include <linux/init.h> 18#include <linux/module.h> 19#include <linux/interrupt.h> 20#include <linux/ioport.h> 21#include <linux/ptrace.h> 22#include <linux/device.h> 23#include <linux/io.h> 24 25#include <asm/irq.h> 26#include <asm/mach/irq.h> 27 28#include <mach/hardware.h> 29#include <mach/regs-irq.h> 30 31#include "nuc9xx.h" 32 33struct group_irq { 34 unsigned long gpen; 35 unsigned int enabled; 36 void (*enable)(struct group_irq *, int enable); 37}; 38 39static DEFINE_SPINLOCK(groupirq_lock); 40 41#define DEFINE_GROUP(_name, _ctrlbit, _num) \ 42struct group_irq group_##_name = { \ 43 .enable = nuc900_group_enable, \ 44 .gpen = ((1 << _num) - 1) << _ctrlbit, \ 45 } 46 47static void nuc900_group_enable(struct group_irq *gpirq, int enable); 48 49static DEFINE_GROUP(nirq0, 0, 4); 50static DEFINE_GROUP(nirq1, 4, 4); 51static DEFINE_GROUP(usbh, 8, 2); 52static DEFINE_GROUP(ottimer, 16, 3); 53static DEFINE_GROUP(gdma, 20, 2); 54static DEFINE_GROUP(sc, 24, 2); 55static DEFINE_GROUP(i2c, 26, 2); 56static DEFINE_GROUP(ps2, 28, 2); 57 58static int group_irq_enable(struct group_irq *group_irq) 59{ 60 unsigned long flags; 61 62 spin_lock_irqsave(&groupirq_lock, flags); 63 if (group_irq->enabled++ == 0) 64 (group_irq->enable)(group_irq, 1); 65 spin_unlock_irqrestore(&groupirq_lock, flags); 66 67 return 0; 68} 69 70static void group_irq_disable(struct group_irq *group_irq) 71{ 72 unsigned long flags; 73 74 WARN_ON(group_irq->enabled == 0); 75 76 spin_lock_irqsave(&groupirq_lock, flags); 77 if (--group_irq->enabled == 0) 78 (group_irq->enable)(group_irq, 0); 79 spin_unlock_irqrestore(&groupirq_lock, flags); 80} 81 82static void nuc900_group_enable(struct group_irq *gpirq, int enable) 83{ 84 unsigned int groupen = gpirq->gpen; 85 unsigned long regval; 86 87 regval = __raw_readl(REG_AIC_GEN); 88 89 if (enable) 90 regval |= groupen; 91 else 92 regval &= ~groupen; 93 94 __raw_writel(regval, REG_AIC_GEN); 95} 96 97static void nuc900_irq_mask(struct irq_data *d) 98{ 99 struct group_irq *group_irq; 100 101 group_irq = NULL; 102 103 __raw_writel(1 << d->irq, REG_AIC_MDCR); 104 105 switch (d->irq) { 106 case IRQ_GROUP0: 107 group_irq = &group_nirq0; 108 break; 109 110 case IRQ_GROUP1: 111 group_irq = &group_nirq1; 112 break; 113 114 case IRQ_USBH: 115 group_irq = &group_usbh; 116 break; 117 118 case IRQ_T_INT_GROUP: 119 group_irq = &group_ottimer; 120 break; 121 122 case IRQ_GDMAGROUP: 123 group_irq = &group_gdma; 124 break; 125 126 case IRQ_SCGROUP: 127 group_irq = &group_sc; 128 break; 129 130 case IRQ_I2CGROUP: 131 group_irq = &group_i2c; 132 break; 133 134 case IRQ_P2SGROUP: 135 group_irq = &group_ps2; 136 break; 137 } 138 139 if (group_irq) 140 group_irq_disable(group_irq); 141} 142 143/* 144 * By the w90p910 spec,any irq,only write 1 145 * to REG_AIC_EOSCR for ACK 146 */ 147 148static void nuc900_irq_ack(struct irq_data *d) 149{ 150 __raw_writel(0x01, REG_AIC_EOSCR); 151} 152 153static void nuc900_irq_unmask(struct irq_data *d) 154{ 155 struct group_irq *group_irq; 156 157 group_irq = NULL; 158 159 __raw_writel(1 << d->irq, REG_AIC_MECR); 160 161 switch (d->irq) { 162 case IRQ_GROUP0: 163 group_irq = &group_nirq0; 164 break; 165 166 case IRQ_GROUP1: 167 group_irq = &group_nirq1; 168 break; 169 170 case IRQ_USBH: 171 group_irq = &group_usbh; 172 break; 173 174 case IRQ_T_INT_GROUP: 175 group_irq = &group_ottimer; 176 break; 177 178 case IRQ_GDMAGROUP: 179 group_irq = &group_gdma; 180 break; 181 182 case IRQ_SCGROUP: 183 group_irq = &group_sc; 184 break; 185 186 case IRQ_I2CGROUP: 187 group_irq = &group_i2c; 188 break; 189 190 case IRQ_P2SGROUP: 191 group_irq = &group_ps2; 192 break; 193 } 194 195 if (group_irq) 196 group_irq_enable(group_irq); 197} 198 199static struct irq_chip nuc900_irq_chip = { 200 .irq_ack = nuc900_irq_ack, 201 .irq_mask = nuc900_irq_mask, 202 .irq_unmask = nuc900_irq_unmask, 203}; 204 205void __init nuc900_init_irq(void) 206{ 207 int irqno; 208 209 __raw_writel(0xFFFFFFFE, REG_AIC_MDCR); 210 211 for (irqno = IRQ_WDT; irqno <= IRQ_ADC; irqno++) { 212 irq_set_chip_and_handler(irqno, &nuc900_irq_chip, 213 handle_level_irq); 214 set_irq_flags(irqno, IRQF_VALID); 215 } 216} 217