Commit bd20ff5793b4ece4fa3e9e0fcf8e6bbd93526215

Authored by Lennert Buytenhek
Committed by Russell King
1 parent 36c64af4e0

[ARM] 3374/1: ep93xx: gpio interrupt support

Patch from Lennert Buytenhek

Add GPIO interrupt support for the first 16 GPIO lines (port A
and B.)

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Showing 3 changed files with 146 additions and 1 deletions Side-by-side Diff

arch/arm/mach-ep93xx/core.c
... ... @@ -150,6 +150,26 @@
150 150 /*************************************************************************
151 151 * GPIO handling for EP93xx
152 152 *************************************************************************/
  153 +static unsigned char gpio_int_enable[2];
  154 +static unsigned char gpio_int_type1[2];
  155 +static unsigned char gpio_int_type2[2];
  156 +
  157 +static void update_gpio_ab_int_params(int port)
  158 +{
  159 + if (port == 0) {
  160 + __raw_writeb(0, EP93XX_GPIO_A_INT_ENABLE);
  161 + __raw_writeb(gpio_int_type2[0], EP93XX_GPIO_A_INT_TYPE2);
  162 + __raw_writeb(gpio_int_type1[0], EP93XX_GPIO_A_INT_TYPE1);
  163 + __raw_writeb(gpio_int_enable[0], EP93XX_GPIO_A_INT_ENABLE);
  164 + } else if (port == 1) {
  165 + __raw_writeb(0, EP93XX_GPIO_B_INT_ENABLE);
  166 + __raw_writeb(gpio_int_type2[1], EP93XX_GPIO_B_INT_TYPE2);
  167 + __raw_writeb(gpio_int_type1[1], EP93XX_GPIO_B_INT_TYPE1);
  168 + __raw_writeb(gpio_int_enable[1], EP93XX_GPIO_B_INT_ENABLE);
  169 + }
  170 +}
  171 +
  172 +
153 173 static unsigned char data_register_offset[8] = {
154 174 0x00, 0x04, 0x08, 0x0c, 0x20, 0x30, 0x38, 0x40,
155 175 };
... ... @@ -169,6 +189,11 @@
169 189  
170 190 local_irq_save(flags);
171 191 if (direction == GPIO_OUT) {
  192 + if (line >= 0 && line < 16) {
  193 + gpio_int_enable[line >> 3] &= ~(1 << (line & 7));
  194 + update_gpio_ab_int_params(line >> 3);
  195 + }
  196 +
172 197 v = __raw_readb(data_direction_register);
173 198 v |= 1 << (line & 7);
174 199 __raw_writeb(v, data_direction_register);
175 200  
176 201  
... ... @@ -217,10 +242,118 @@
217 242 /*************************************************************************
218 243 * EP93xx IRQ handling
219 244 *************************************************************************/
  245 +static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
  246 + struct irqdesc *desc, struct pt_regs *regs)
  247 +{
  248 + unsigned char status;
  249 + int i;
  250 +
  251 + status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
  252 + for (i = 0; i < 8; i++) {
  253 + if (status & (1 << i)) {
  254 + desc = irq_desc + IRQ_EP93XX_GPIO(0) + i;
  255 + desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc, regs);
  256 + }
  257 + }
  258 +
  259 + status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
  260 + for (i = 0; i < 8; i++) {
  261 + if (status & (1 << i)) {
  262 + desc = irq_desc + IRQ_EP93XX_GPIO(8) + i;
  263 + desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc, regs);
  264 + }
  265 + }
  266 +}
  267 +
  268 +static void ep93xx_gpio_ab_irq_mask_ack(unsigned int irq)
  269 +{
  270 + int line = irq - IRQ_EP93XX_GPIO(0);
  271 + int port = line >> 3;
  272 +
  273 + gpio_int_enable[port] &= ~(1 << (line & 7));
  274 + update_gpio_ab_int_params(port);
  275 +
  276 + if (line >> 3) {
  277 + __raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK);
  278 + } else {
  279 + __raw_writel(1 << (line & 7), EP93XX_GPIO_A_INT_ACK);
  280 + }
  281 +}
  282 +
  283 +static void ep93xx_gpio_ab_irq_mask(unsigned int irq)
  284 +{
  285 + int line = irq - IRQ_EP93XX_GPIO(0);
  286 + int port = line >> 3;
  287 +
  288 + gpio_int_enable[port] &= ~(1 << (line & 7));
  289 + update_gpio_ab_int_params(port);
  290 +}
  291 +
  292 +static void ep93xx_gpio_ab_irq_unmask(unsigned int irq)
  293 +{
  294 + int line = irq - IRQ_EP93XX_GPIO(0);
  295 + int port = line >> 3;
  296 +
  297 + gpio_int_enable[port] |= 1 << (line & 7);
  298 + update_gpio_ab_int_params(port);
  299 +}
  300 +
  301 +
  302 +/*
  303 + * gpio_int_type1 controls whether the interrupt is level (0) or
  304 + * edge (1) triggered, while gpio_int_type2 controls whether it
  305 + * triggers on low/falling (0) or high/rising (1).
  306 + */
  307 +static int ep93xx_gpio_ab_irq_type(unsigned int irq, unsigned int type)
  308 +{
  309 + int port;
  310 + int line;
  311 +
  312 + line = irq - IRQ_EP93XX_GPIO(0);
  313 + gpio_line_config(line, GPIO_IN);
  314 +
  315 + port = line >> 3;
  316 + line &= 7;
  317 +
  318 + if (type & IRQT_RISING) {
  319 + gpio_int_type1[port] |= 1 << line;
  320 + gpio_int_type2[port] |= 1 << line;
  321 + } else if (type & IRQT_FALLING) {
  322 + gpio_int_type1[port] |= 1 << line;
  323 + gpio_int_type2[port] &= ~(1 << line);
  324 + } else if (type & IRQT_HIGH) {
  325 + gpio_int_type1[port] &= ~(1 << line);
  326 + gpio_int_type2[port] |= 1 << line;
  327 + } else if (type & IRQT_LOW) {
  328 + gpio_int_type1[port] &= ~(1 << line);
  329 + gpio_int_type2[port] &= ~(1 << line);
  330 + }
  331 + update_gpio_ab_int_params(port);
  332 +
  333 + return 0;
  334 +}
  335 +
  336 +static struct irqchip ep93xx_gpio_ab_irq_chip = {
  337 + .ack = ep93xx_gpio_ab_irq_mask_ack,
  338 + .mask = ep93xx_gpio_ab_irq_mask,
  339 + .unmask = ep93xx_gpio_ab_irq_unmask,
  340 + .set_type = ep93xx_gpio_ab_irq_type,
  341 +};
  342 +
  343 +
220 344 void __init ep93xx_init_irq(void)
221 345 {
  346 + int irq;
  347 +
222 348 vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
223 349 vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK);
  350 +
  351 + for (irq = IRQ_EP93XX_GPIO(0) ; irq <= IRQ_EP93XX_GPIO(15); irq++) {
  352 + set_irq_chip(irq, &ep93xx_gpio_ab_irq_chip);
  353 + set_irq_handler(irq, do_level_IRQ);
  354 + set_irq_flags(irq, IRQF_VALID);
  355 + }
  356 + set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
224 357 }
225 358  
226 359  
include/asm-arm/arch-ep93xx/ep93xx-regs.h
... ... @@ -72,6 +72,16 @@
72 72  
73 73 #define EP93XX_GPIO_BASE (EP93XX_APB_VIRT_BASE + 0x00040000)
74 74 #define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x))
  75 +#define EP93XX_GPIO_A_INT_TYPE1 EP93XX_GPIO_REG(0x90)
  76 +#define EP93XX_GPIO_A_INT_TYPE2 EP93XX_GPIO_REG(0x94)
  77 +#define EP93XX_GPIO_A_INT_ACK EP93XX_GPIO_REG(0x98)
  78 +#define EP93XX_GPIO_A_INT_ENABLE EP93XX_GPIO_REG(0x9c)
  79 +#define EP93XX_GPIO_A_INT_STATUS EP93XX_GPIO_REG(0xa0)
  80 +#define EP93XX_GPIO_B_INT_TYPE1 EP93XX_GPIO_REG(0xac)
  81 +#define EP93XX_GPIO_B_INT_TYPE2 EP93XX_GPIO_REG(0xb0)
  82 +#define EP93XX_GPIO_B_INT_ACK EP93XX_GPIO_REG(0xb4)
  83 +#define EP93XX_GPIO_B_INT_ENABLE EP93XX_GPIO_REG(0xb8)
  84 +#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc)
75 85  
76 86 #define EP93XX_AAC_BASE (EP93XX_APB_VIRT_BASE + 0x00080000)
77 87  
include/asm-arm/arch-ep93xx/irqs.h
... ... @@ -67,7 +67,9 @@
67 67 #define IRQ_EP93XX_SAI 60
68 68 #define EP93XX_VIC2_VALID_IRQ_MASK 0x1fffffff
69 69  
70   -#define NR_EP93XX_IRQS 64
  70 +#define IRQ_EP93XX_GPIO(x) (64 + (x))
  71 +
  72 +#define NR_EP93XX_IRQS IRQ_EP93XX_GPIO(16)
71 73  
72 74 #define EP93XX_BOARD_IRQ(x) (NR_EP93XX_IRQS + (x))
73 75 #define EP93XX_BOARD_IRQS 32