19dd0b194SLennert Buytenhek /* 29dd0b194SLennert Buytenhek * arch/arm/mach-orion5x/irq.c 39dd0b194SLennert Buytenhek * 49dd0b194SLennert Buytenhek * Core IRQ functions for Marvell Orion System On Chip 59dd0b194SLennert Buytenhek * 69dd0b194SLennert Buytenhek * Maintainer: Tzachi Perelstein <tzachi@marvell.com> 79dd0b194SLennert Buytenhek * 89dd0b194SLennert Buytenhek * This file is licensed under the terms of the GNU General Public 99dd0b194SLennert Buytenhek * License version 2. This program is licensed "as is" without any 109dd0b194SLennert Buytenhek * warranty of any kind, whether express or implied. 119dd0b194SLennert Buytenhek */ 129dd0b194SLennert Buytenhek 139dd0b194SLennert Buytenhek #include <linux/kernel.h> 149dd0b194SLennert Buytenhek #include <linux/init.h> 159dd0b194SLennert Buytenhek #include <linux/irq.h> 169dd0b194SLennert Buytenhek #include <asm/gpio.h> 179dd0b194SLennert Buytenhek #include <asm/io.h> 189dd0b194SLennert Buytenhek #include <asm/arch/orion5x.h> 199dd0b194SLennert Buytenhek #include <asm/plat-orion/irq.h> 209dd0b194SLennert Buytenhek #include "common.h" 219dd0b194SLennert Buytenhek 229dd0b194SLennert Buytenhek /***************************************************************************** 239dd0b194SLennert Buytenhek * Orion GPIO IRQ 249dd0b194SLennert Buytenhek * 259dd0b194SLennert Buytenhek * GPIO_IN_POL register controlls whether GPIO_DATA_IN will hold the same 269dd0b194SLennert Buytenhek * value of the line or the opposite value. 279dd0b194SLennert Buytenhek * 289dd0b194SLennert Buytenhek * Level IRQ handlers: DATA_IN is used directly as cause register. 299dd0b194SLennert Buytenhek * Interrupt are masked by LEVEL_MASK registers. 309dd0b194SLennert Buytenhek * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. 319dd0b194SLennert Buytenhek * Interrupt are masked by EDGE_MASK registers. 329dd0b194SLennert Buytenhek * Both-edge handlers: Similar to regular Edge handlers, but also swaps 339dd0b194SLennert Buytenhek * the polarity to catch the next line transaction. 349dd0b194SLennert Buytenhek * This is a race condition that might not perfectly 359dd0b194SLennert Buytenhek * work on some use cases. 369dd0b194SLennert Buytenhek * 379dd0b194SLennert Buytenhek * Every eight GPIO lines are grouped (OR'ed) before going up to main 389dd0b194SLennert Buytenhek * cause register. 399dd0b194SLennert Buytenhek * 409dd0b194SLennert Buytenhek * EDGE cause mask 419dd0b194SLennert Buytenhek * data-in /--------| |-----| |----\ 429dd0b194SLennert Buytenhek * -----| |----- ---- to main cause reg 439dd0b194SLennert Buytenhek * X \----------------| |----/ 449dd0b194SLennert Buytenhek * polarity LEVEL mask 459dd0b194SLennert Buytenhek * 469dd0b194SLennert Buytenhek ****************************************************************************/ 479dd0b194SLennert Buytenhek static void orion5x_gpio_irq_ack(u32 irq) 489dd0b194SLennert Buytenhek { 499dd0b194SLennert Buytenhek int pin = irq_to_gpio(irq); 509dd0b194SLennert Buytenhek if (irq_desc[irq].status & IRQ_LEVEL) 519dd0b194SLennert Buytenhek /* 529dd0b194SLennert Buytenhek * Mask bit for level interrupt 539dd0b194SLennert Buytenhek */ 549dd0b194SLennert Buytenhek orion5x_clrbits(GPIO_LEVEL_MASK, 1 << pin); 559dd0b194SLennert Buytenhek else 569dd0b194SLennert Buytenhek /* 579dd0b194SLennert Buytenhek * Clear casue bit for egde interrupt 589dd0b194SLennert Buytenhek */ 599dd0b194SLennert Buytenhek orion5x_clrbits(GPIO_EDGE_CAUSE, 1 << pin); 609dd0b194SLennert Buytenhek } 619dd0b194SLennert Buytenhek 629dd0b194SLennert Buytenhek static void orion5x_gpio_irq_mask(u32 irq) 639dd0b194SLennert Buytenhek { 649dd0b194SLennert Buytenhek int pin = irq_to_gpio(irq); 659dd0b194SLennert Buytenhek if (irq_desc[irq].status & IRQ_LEVEL) 669dd0b194SLennert Buytenhek orion5x_clrbits(GPIO_LEVEL_MASK, 1 << pin); 679dd0b194SLennert Buytenhek else 689dd0b194SLennert Buytenhek orion5x_clrbits(GPIO_EDGE_MASK, 1 << pin); 699dd0b194SLennert Buytenhek } 709dd0b194SLennert Buytenhek 719dd0b194SLennert Buytenhek static void orion5x_gpio_irq_unmask(u32 irq) 729dd0b194SLennert Buytenhek { 739dd0b194SLennert Buytenhek int pin = irq_to_gpio(irq); 749dd0b194SLennert Buytenhek if (irq_desc[irq].status & IRQ_LEVEL) 759dd0b194SLennert Buytenhek orion5x_setbits(GPIO_LEVEL_MASK, 1 << pin); 769dd0b194SLennert Buytenhek else 779dd0b194SLennert Buytenhek orion5x_setbits(GPIO_EDGE_MASK, 1 << pin); 789dd0b194SLennert Buytenhek } 799dd0b194SLennert Buytenhek 809dd0b194SLennert Buytenhek static int orion5x_gpio_set_irq_type(u32 irq, u32 type) 819dd0b194SLennert Buytenhek { 829dd0b194SLennert Buytenhek int pin = irq_to_gpio(irq); 839dd0b194SLennert Buytenhek struct irq_desc *desc; 849dd0b194SLennert Buytenhek 8579e90dd5SLennert Buytenhek if ((readl(GPIO_IO_CONF) & (1 << pin)) == 0) { 869dd0b194SLennert Buytenhek printk(KERN_ERR "orion5x_gpio_set_irq_type failed " 879dd0b194SLennert Buytenhek "(irq %d, pin %d).\n", irq, pin); 889dd0b194SLennert Buytenhek return -EINVAL; 899dd0b194SLennert Buytenhek } 909dd0b194SLennert Buytenhek 919dd0b194SLennert Buytenhek desc = irq_desc + irq; 929dd0b194SLennert Buytenhek 939dd0b194SLennert Buytenhek switch (type) { 949dd0b194SLennert Buytenhek case IRQT_HIGH: 959dd0b194SLennert Buytenhek desc->handle_irq = handle_level_irq; 969dd0b194SLennert Buytenhek desc->status |= IRQ_LEVEL; 979dd0b194SLennert Buytenhek orion5x_clrbits(GPIO_IN_POL, (1 << pin)); 989dd0b194SLennert Buytenhek break; 999dd0b194SLennert Buytenhek case IRQT_LOW: 1009dd0b194SLennert Buytenhek desc->handle_irq = handle_level_irq; 1019dd0b194SLennert Buytenhek desc->status |= IRQ_LEVEL; 1029dd0b194SLennert Buytenhek orion5x_setbits(GPIO_IN_POL, (1 << pin)); 1039dd0b194SLennert Buytenhek break; 1049dd0b194SLennert Buytenhek case IRQT_RISING: 1059dd0b194SLennert Buytenhek desc->handle_irq = handle_edge_irq; 1069dd0b194SLennert Buytenhek desc->status &= ~IRQ_LEVEL; 1079dd0b194SLennert Buytenhek orion5x_clrbits(GPIO_IN_POL, (1 << pin)); 1089dd0b194SLennert Buytenhek break; 1099dd0b194SLennert Buytenhek case IRQT_FALLING: 1109dd0b194SLennert Buytenhek desc->handle_irq = handle_edge_irq; 1119dd0b194SLennert Buytenhek desc->status &= ~IRQ_LEVEL; 1129dd0b194SLennert Buytenhek orion5x_setbits(GPIO_IN_POL, (1 << pin)); 1139dd0b194SLennert Buytenhek break; 1149dd0b194SLennert Buytenhek case IRQT_BOTHEDGE: 1159dd0b194SLennert Buytenhek desc->handle_irq = handle_edge_irq; 1169dd0b194SLennert Buytenhek desc->status &= ~IRQ_LEVEL; 1179dd0b194SLennert Buytenhek /* 1189dd0b194SLennert Buytenhek * set initial polarity based on current input level 1199dd0b194SLennert Buytenhek */ 12079e90dd5SLennert Buytenhek if ((readl(GPIO_IN_POL) ^ readl(GPIO_DATA_IN)) 1219dd0b194SLennert Buytenhek & (1 << pin)) 1229dd0b194SLennert Buytenhek orion5x_setbits(GPIO_IN_POL, (1 << pin)); /* falling */ 1239dd0b194SLennert Buytenhek else 1249dd0b194SLennert Buytenhek orion5x_clrbits(GPIO_IN_POL, (1 << pin)); /* rising */ 1259dd0b194SLennert Buytenhek 1269dd0b194SLennert Buytenhek break; 1279dd0b194SLennert Buytenhek default: 1289dd0b194SLennert Buytenhek printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type); 1299dd0b194SLennert Buytenhek return -EINVAL; 1309dd0b194SLennert Buytenhek } 1319dd0b194SLennert Buytenhek 1329dd0b194SLennert Buytenhek desc->status &= ~IRQ_TYPE_SENSE_MASK; 1339dd0b194SLennert Buytenhek desc->status |= type & IRQ_TYPE_SENSE_MASK; 1349dd0b194SLennert Buytenhek 1359dd0b194SLennert Buytenhek return 0; 1369dd0b194SLennert Buytenhek } 1379dd0b194SLennert Buytenhek 1389dd0b194SLennert Buytenhek static struct irq_chip orion5x_gpio_irq_chip = { 1399dd0b194SLennert Buytenhek .name = "Orion-IRQ-GPIO", 1409dd0b194SLennert Buytenhek .ack = orion5x_gpio_irq_ack, 1419dd0b194SLennert Buytenhek .mask = orion5x_gpio_irq_mask, 1429dd0b194SLennert Buytenhek .unmask = orion5x_gpio_irq_unmask, 1439dd0b194SLennert Buytenhek .set_type = orion5x_gpio_set_irq_type, 1449dd0b194SLennert Buytenhek }; 1459dd0b194SLennert Buytenhek 1469dd0b194SLennert Buytenhek static void orion5x_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) 1479dd0b194SLennert Buytenhek { 1489dd0b194SLennert Buytenhek u32 cause, offs, pin; 1499dd0b194SLennert Buytenhek 1509dd0b194SLennert Buytenhek BUG_ON(irq < IRQ_ORION5X_GPIO_0_7 || irq > IRQ_ORION5X_GPIO_24_31); 1519dd0b194SLennert Buytenhek offs = (irq - IRQ_ORION5X_GPIO_0_7) * 8; 15279e90dd5SLennert Buytenhek cause = (readl(GPIO_DATA_IN) & readl(GPIO_LEVEL_MASK)) | 15379e90dd5SLennert Buytenhek (readl(GPIO_EDGE_CAUSE) & readl(GPIO_EDGE_MASK)); 1549dd0b194SLennert Buytenhek 1559dd0b194SLennert Buytenhek for (pin = offs; pin < offs + 8; pin++) { 1569dd0b194SLennert Buytenhek if (cause & (1 << pin)) { 1579dd0b194SLennert Buytenhek irq = gpio_to_irq(pin); 1589dd0b194SLennert Buytenhek desc = irq_desc + irq; 1599dd0b194SLennert Buytenhek if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) { 1609dd0b194SLennert Buytenhek /* Swap polarity (race with GPIO line) */ 16179e90dd5SLennert Buytenhek u32 polarity = readl(GPIO_IN_POL); 1629dd0b194SLennert Buytenhek polarity ^= 1 << pin; 16379e90dd5SLennert Buytenhek writel(polarity, GPIO_IN_POL); 1649dd0b194SLennert Buytenhek } 1659dd0b194SLennert Buytenhek desc_handle_irq(irq, desc); 1669dd0b194SLennert Buytenhek } 1679dd0b194SLennert Buytenhek } 1689dd0b194SLennert Buytenhek } 1699dd0b194SLennert Buytenhek 1709dd0b194SLennert Buytenhek static void __init orion5x_init_gpio_irq(void) 1719dd0b194SLennert Buytenhek { 1729dd0b194SLennert Buytenhek int i; 1739dd0b194SLennert Buytenhek struct irq_desc *desc; 1749dd0b194SLennert Buytenhek 1759dd0b194SLennert Buytenhek /* 1769dd0b194SLennert Buytenhek * Mask and clear GPIO IRQ interrupts 1779dd0b194SLennert Buytenhek */ 17879e90dd5SLennert Buytenhek writel(0x0, GPIO_LEVEL_MASK); 17979e90dd5SLennert Buytenhek writel(0x0, GPIO_EDGE_MASK); 18079e90dd5SLennert Buytenhek writel(0x0, GPIO_EDGE_CAUSE); 1819dd0b194SLennert Buytenhek 1829dd0b194SLennert Buytenhek /* 1839dd0b194SLennert Buytenhek * Register chained level handlers for GPIO IRQs by default. 1849dd0b194SLennert Buytenhek * User can use set_type() if he wants to use edge types handlers. 1859dd0b194SLennert Buytenhek */ 1869dd0b194SLennert Buytenhek for (i = IRQ_ORION5X_GPIO_START; i < NR_IRQS; i++) { 1879dd0b194SLennert Buytenhek set_irq_chip(i, &orion5x_gpio_irq_chip); 1889dd0b194SLennert Buytenhek set_irq_handler(i, handle_level_irq); 1899dd0b194SLennert Buytenhek desc = irq_desc + i; 1909dd0b194SLennert Buytenhek desc->status |= IRQ_LEVEL; 1919dd0b194SLennert Buytenhek set_irq_flags(i, IRQF_VALID); 1929dd0b194SLennert Buytenhek } 1939dd0b194SLennert Buytenhek set_irq_chained_handler(IRQ_ORION5X_GPIO_0_7, orion5x_gpio_irq_handler); 1949dd0b194SLennert Buytenhek set_irq_chained_handler(IRQ_ORION5X_GPIO_8_15, orion5x_gpio_irq_handler); 1959dd0b194SLennert Buytenhek set_irq_chained_handler(IRQ_ORION5X_GPIO_16_23, orion5x_gpio_irq_handler); 1969dd0b194SLennert Buytenhek set_irq_chained_handler(IRQ_ORION5X_GPIO_24_31, orion5x_gpio_irq_handler); 1979dd0b194SLennert Buytenhek } 1989dd0b194SLennert Buytenhek 1999dd0b194SLennert Buytenhek /***************************************************************************** 2009dd0b194SLennert Buytenhek * Orion Main IRQ 2019dd0b194SLennert Buytenhek ****************************************************************************/ 2029dd0b194SLennert Buytenhek static void __init orion5x_init_main_irq(void) 2039dd0b194SLennert Buytenhek { 2049dd0b194SLennert Buytenhek orion_irq_init(0, (void __iomem *)MAIN_IRQ_MASK); 2059dd0b194SLennert Buytenhek } 2069dd0b194SLennert Buytenhek 2079dd0b194SLennert Buytenhek void __init orion5x_init_irq(void) 2089dd0b194SLennert Buytenhek { 2099dd0b194SLennert Buytenhek orion5x_init_main_irq(); 2109dd0b194SLennert Buytenhek orion5x_init_gpio_irq(); 2119dd0b194SLennert Buytenhek } 212