Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

unicore32 core architecture: interrupts ang gpio handling

This patch implements interrupts and gpio handling.
UniCore32 has 9 gpio interrupt sources.
And gpio device operations are also here.

Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>

+811
+103
arch/unicore32/include/asm/gpio.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/gpio.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #ifndef __UNICORE_GPIO_H__ 14 + #define __UNICORE_GPIO_H__ 15 + 16 + #include <asm/irq.h> 17 + #include <mach/hardware.h> 18 + #include <asm-generic/gpio.h> 19 + 20 + #define GPI_OTP_INT 0 21 + #define GPI_PCI_INTA 1 22 + #define GPI_PCI_INTB 2 23 + #define GPI_PCI_INTC 3 24 + #define GPI_PCI_INTD 4 25 + #define GPI_BAT_DET 5 26 + #define GPI_SD_CD 6 27 + #define GPI_SOFF_REQ 7 28 + #define GPI_SD_WP 8 29 + #define GPI_LCD_CASE_OFF 9 30 + #define GPO_WIFI_EN 10 31 + #define GPO_HDD_LED 11 32 + #define GPO_VGA_EN 12 33 + #define GPO_LCD_EN 13 34 + #define GPO_LED_DATA 14 35 + #define GPO_LED_CLK 15 36 + #define GPO_CAM_PWR_EN 16 37 + #define GPO_LCD_VCC_EN 17 38 + #define GPO_SOFT_OFF 18 39 + #define GPO_BT_EN 19 40 + #define GPO_FAN_ON 20 41 + #define GPO_SPKR 21 42 + #define GPO_SET_V1 23 43 + #define GPO_SET_V2 24 44 + #define GPO_CPU_HEALTH 25 45 + #define GPO_LAN_SEL 26 46 + 47 + #ifdef CONFIG_PUV3_NB0916 48 + #define GPI_BTN_TOUCH 14 49 + #define GPIO_IN 0x000043ff /* 1 for input */ 50 + #define GPIO_OUT 0x0fffbc00 /* 1 for output */ 51 + #endif /* CONFIG_PUV3_NB0916 */ 52 + 53 + #ifdef CONFIG_PUV3_SMW0919 54 + #define GPIO_IN 0x000003ff /* 1 for input */ 55 + #define GPIO_OUT 0x0ffffc00 /* 1 for output */ 56 + #endif /* CONFIG_PUV3_SMW0919 */ 57 + 58 + #ifdef CONFIG_PUV3_DB0913 59 + #define GPIO_IN 0x000001df /* 1 for input */ 60 + #define GPIO_OUT 0x03fee800 /* 1 for output */ 61 + #endif /* CONFIG_PUV3_DB0913 */ 62 + 63 + #define GPIO_DIR (~((GPIO_IN) | 0xf0000000)) 64 + /* 0 input, 1 output */ 65 + 66 + static inline int gpio_get_value(unsigned gpio) 67 + { 68 + if (__builtin_constant_p(gpio) && (gpio <= GPIO_MAX)) 69 + return GPIO_GPLR & GPIO_GPIO(gpio); 70 + else 71 + return __gpio_get_value(gpio); 72 + } 73 + 74 + static inline void gpio_set_value(unsigned gpio, int value) 75 + { 76 + if (__builtin_constant_p(gpio) && (gpio <= GPIO_MAX)) 77 + if (value) 78 + GPIO_GPSR = GPIO_GPIO(gpio); 79 + else 80 + GPIO_GPCR = GPIO_GPIO(gpio); 81 + else 82 + __gpio_set_value(gpio, value); 83 + } 84 + 85 + #define gpio_cansleep __gpio_cansleep 86 + 87 + static inline unsigned gpio_to_irq(unsigned gpio) 88 + { 89 + if ((gpio < IRQ_GPIOHIGH) && (FIELD(1, 1, gpio) & GPIO_GPIR)) 90 + return IRQ_GPIOLOW0 + gpio; 91 + else 92 + return IRQ_GPIO0 + gpio; 93 + } 94 + 95 + static inline unsigned irq_to_gpio(unsigned irq) 96 + { 97 + if (irq < IRQ_GPIOHIGH) 98 + return irq - IRQ_GPIOLOW0; 99 + else 100 + return irq - IRQ_GPIO0; 101 + } 102 + 103 + #endif /* __UNICORE_GPIO_H__ */
+107
arch/unicore32/include/asm/irq.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/irq.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #ifndef __UNICORE_IRQ_H__ 13 + #define __UNICORE_IRQ_H__ 14 + 15 + #include <asm-generic/irq.h> 16 + 17 + #define IRQ_GPIOLOW0 0x00 18 + #define IRQ_GPIOLOW1 0x01 19 + #define IRQ_GPIOLOW2 0x02 20 + #define IRQ_GPIOLOW3 0x03 21 + #define IRQ_GPIOLOW4 0x04 22 + #define IRQ_GPIOLOW5 0x05 23 + #define IRQ_GPIOLOW6 0x06 24 + #define IRQ_GPIOLOW7 0x07 25 + #define IRQ_GPIOHIGH 0x08 26 + #define IRQ_USB 0x09 27 + #define IRQ_SDC 0x0a 28 + #define IRQ_AC97 0x0b 29 + #define IRQ_SATA 0x0c 30 + #define IRQ_MME 0x0d 31 + #define IRQ_PCI_BRIDGE 0x0e 32 + #define IRQ_DDR 0x0f 33 + #define IRQ_SPI 0x10 34 + #define IRQ_UNIGFX 0x11 35 + #define IRQ_I2C 0x11 36 + #define IRQ_UART1 0x12 37 + #define IRQ_UART0 0x13 38 + #define IRQ_UMAL 0x14 39 + #define IRQ_NAND 0x15 40 + #define IRQ_PS2_KBD 0x16 41 + #define IRQ_PS2_AUX 0x17 42 + #define IRQ_DMA 0x18 43 + #define IRQ_DMAERR 0x19 44 + #define IRQ_TIMER0 0x1a 45 + #define IRQ_TIMER1 0x1b 46 + #define IRQ_TIMER2 0x1c 47 + #define IRQ_TIMER3 0x1d 48 + #define IRQ_RTC 0x1e 49 + #define IRQ_RTCAlarm 0x1f 50 + 51 + #define IRQ_GPIO0 0x20 52 + #define IRQ_GPIO1 0x21 53 + #define IRQ_GPIO2 0x22 54 + #define IRQ_GPIO3 0x23 55 + #define IRQ_GPIO4 0x24 56 + #define IRQ_GPIO5 0x25 57 + #define IRQ_GPIO6 0x26 58 + #define IRQ_GPIO7 0x27 59 + #define IRQ_GPIO8 0x28 60 + #define IRQ_GPIO9 0x29 61 + #define IRQ_GPIO10 0x2a 62 + #define IRQ_GPIO11 0x2b 63 + #define IRQ_GPIO12 0x2c 64 + #define IRQ_GPIO13 0x2d 65 + #define IRQ_GPIO14 0x2e 66 + #define IRQ_GPIO15 0x2f 67 + #define IRQ_GPIO16 0x30 68 + #define IRQ_GPIO17 0x31 69 + #define IRQ_GPIO18 0x32 70 + #define IRQ_GPIO19 0x33 71 + #define IRQ_GPIO20 0x34 72 + #define IRQ_GPIO21 0x35 73 + #define IRQ_GPIO22 0x36 74 + #define IRQ_GPIO23 0x37 75 + #define IRQ_GPIO24 0x38 76 + #define IRQ_GPIO25 0x39 77 + #define IRQ_GPIO26 0x3a 78 + #define IRQ_GPIO27 0x3b 79 + 80 + #ifdef CONFIG_ARCH_FPGA 81 + #define IRQ_PCIINTA IRQ_GPIOLOW2 82 + #define IRQ_PCIINTB IRQ_GPIOLOW1 83 + #define IRQ_PCIINTC IRQ_GPIOLOW0 84 + #define IRQ_PCIINTD IRQ_GPIOLOW6 85 + #endif 86 + 87 + #if defined(CONFIG_PUV3_DB0913) || defined(CONFIG_PUV3_NB0916) \ 88 + || defined(CONFIG_PUV3_SMW0919) 89 + #define IRQ_PCIINTA IRQ_GPIOLOW1 90 + #define IRQ_PCIINTB IRQ_GPIOLOW2 91 + #define IRQ_PCIINTC IRQ_GPIOLOW3 92 + #define IRQ_PCIINTD IRQ_GPIOLOW4 93 + #endif 94 + 95 + #define IRQ_SD_CD IRQ_GPIO6 /* falling or rising trigger */ 96 + 97 + #ifndef __ASSEMBLY__ 98 + struct irqaction; 99 + struct pt_regs; 100 + extern void migrate_irqs(void); 101 + 102 + extern void asm_do_IRQ(unsigned int, struct pt_regs *); 103 + 104 + #endif 105 + 106 + #endif 107 +
+53
arch/unicore32/include/asm/irqflags.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/irqflags.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #ifndef __UNICORE_IRQFLAGS_H__ 13 + #define __UNICORE_IRQFLAGS_H__ 14 + 15 + #ifdef __KERNEL__ 16 + 17 + #include <asm/ptrace.h> 18 + 19 + #define ARCH_IRQ_DISABLED (PRIV_MODE | PSR_I_BIT) 20 + #define ARCH_IRQ_ENABLED (PRIV_MODE) 21 + 22 + /* 23 + * Save the current interrupt enable state. 24 + */ 25 + static inline unsigned long arch_local_save_flags(void) 26 + { 27 + unsigned long temp; 28 + 29 + asm volatile("mov %0, asr" : "=r" (temp) : : "memory", "cc"); 30 + 31 + return temp & PSR_c; 32 + } 33 + 34 + /* 35 + * restore saved IRQ state 36 + */ 37 + static inline void arch_local_irq_restore(unsigned long flags) 38 + { 39 + unsigned long temp; 40 + 41 + asm volatile( 42 + "mov %0, asr\n" 43 + "mov.a asr, %1\n" 44 + "mov.f asr, %0" 45 + : "=&r" (temp) 46 + : "r" (flags) 47 + : "memory", "cc"); 48 + } 49 + 50 + #include <asm-generic/irqflags.h> 51 + 52 + #endif 53 + #endif
+122
arch/unicore32/kernel/gpio.c
··· 1 + /* 2 + * linux/arch/unicore32/kernel/gpio.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> 7 + * Copyright (C) 2001-2010 Guan Xuetao 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License version 2 as 11 + * published by the Free Software Foundation. 12 + */ 13 + /* in FPGA, no GPIO support */ 14 + 15 + #include <linux/init.h> 16 + #include <linux/module.h> 17 + #include <linux/gpio.h> 18 + #include <mach/hardware.h> 19 + 20 + #ifdef CONFIG_LEDS 21 + #include <linux/leds.h> 22 + #include <linux/platform_device.h> 23 + 24 + static const struct gpio_led puv3_gpio_leds[] = { 25 + { .name = "cpuhealth", .gpio = GPO_CPU_HEALTH, .active_low = 0, 26 + .default_trigger = "heartbeat", }, 27 + { .name = "hdd_led", .gpio = GPO_HDD_LED, .active_low = 1, 28 + .default_trigger = "ide-disk", }, 29 + }; 30 + 31 + static const struct gpio_led_platform_data puv3_gpio_led_data = { 32 + .num_leds = ARRAY_SIZE(puv3_gpio_leds), 33 + .leds = (void *) puv3_gpio_leds, 34 + }; 35 + 36 + static struct platform_device puv3_gpio_gpio_leds = { 37 + .name = "leds-gpio", 38 + .id = -1, 39 + .dev = { 40 + .platform_data = (void *) &puv3_gpio_led_data, 41 + } 42 + }; 43 + 44 + static int __init puv3_gpio_leds_init(void) 45 + { 46 + platform_device_register(&puv3_gpio_gpio_leds); 47 + return 0; 48 + } 49 + 50 + device_initcall(puv3_gpio_leds_init); 51 + #endif 52 + 53 + static int puv3_gpio_get(struct gpio_chip *chip, unsigned offset) 54 + { 55 + return GPIO_GPLR & GPIO_GPIO(offset); 56 + } 57 + 58 + static void puv3_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 59 + { 60 + if (value) 61 + GPIO_GPSR = GPIO_GPIO(offset); 62 + else 63 + GPIO_GPCR = GPIO_GPIO(offset); 64 + } 65 + 66 + static int puv3_direction_input(struct gpio_chip *chip, unsigned offset) 67 + { 68 + unsigned long flags; 69 + 70 + local_irq_save(flags); 71 + GPIO_GPDR &= ~GPIO_GPIO(offset); 72 + local_irq_restore(flags); 73 + return 0; 74 + } 75 + 76 + static int puv3_direction_output(struct gpio_chip *chip, unsigned offset, 77 + int value) 78 + { 79 + unsigned long flags; 80 + 81 + local_irq_save(flags); 82 + puv3_gpio_set(chip, offset, value); 83 + GPIO_GPDR |= GPIO_GPIO(offset); 84 + local_irq_restore(flags); 85 + return 0; 86 + } 87 + 88 + static struct gpio_chip puv3_gpio_chip = { 89 + .label = "gpio", 90 + .direction_input = puv3_direction_input, 91 + .direction_output = puv3_direction_output, 92 + .set = puv3_gpio_set, 93 + .get = puv3_gpio_get, 94 + .base = 0, 95 + .ngpio = GPIO_MAX + 1, 96 + }; 97 + 98 + void __init puv3_init_gpio(void) 99 + { 100 + GPIO_GPDR = GPIO_DIR; 101 + #if defined(CONFIG_PUV3_NB0916) || defined(CONFIG_PUV3_SMW0919) \ 102 + || defined(CONFIG_PUV3_DB0913) 103 + gpio_set_value(GPO_WIFI_EN, 1); 104 + gpio_set_value(GPO_HDD_LED, 1); 105 + gpio_set_value(GPO_VGA_EN, 1); 106 + gpio_set_value(GPO_LCD_EN, 1); 107 + gpio_set_value(GPO_CAM_PWR_EN, 0); 108 + gpio_set_value(GPO_LCD_VCC_EN, 1); 109 + gpio_set_value(GPO_SOFT_OFF, 1); 110 + gpio_set_value(GPO_BT_EN, 1); 111 + gpio_set_value(GPO_FAN_ON, 0); 112 + gpio_set_value(GPO_SPKR, 0); 113 + gpio_set_value(GPO_CPU_HEALTH, 1); 114 + gpio_set_value(GPO_LAN_SEL, 1); 115 + /* 116 + * DO NOT modify the GPO_SET_V1 and GPO_SET_V2 in kernel 117 + * gpio_set_value(GPO_SET_V1, 1); 118 + * gpio_set_value(GPO_SET_V2, 1); 119 + */ 120 + #endif 121 + gpiochip_add(&puv3_gpio_chip); 122 + }
+426
arch/unicore32/kernel/irq.c
··· 1 + /* 2 + * linux/arch/unicore32/kernel/irq.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <linux/kernel_stat.h> 13 + #include <linux/module.h> 14 + #include <linux/signal.h> 15 + #include <linux/ioport.h> 16 + #include <linux/interrupt.h> 17 + #include <linux/irq.h> 18 + #include <linux/random.h> 19 + #include <linux/smp.h> 20 + #include <linux/init.h> 21 + #include <linux/seq_file.h> 22 + #include <linux/errno.h> 23 + #include <linux/list.h> 24 + #include <linux/kallsyms.h> 25 + #include <linux/proc_fs.h> 26 + #include <linux/sysdev.h> 27 + #include <linux/gpio.h> 28 + 29 + #include <asm/system.h> 30 + #include <mach/hardware.h> 31 + 32 + #include "setup.h" 33 + 34 + /* 35 + * PKUnity GPIO edge detection for IRQs: 36 + * IRQs are generated on Falling-Edge, Rising-Edge, or both. 37 + * Use this instead of directly setting GRER/GFER. 38 + */ 39 + static int GPIO_IRQ_rising_edge; 40 + static int GPIO_IRQ_falling_edge; 41 + static int GPIO_IRQ_mask = 0; 42 + 43 + #define GPIO_MASK(irq) (1 << (irq - IRQ_GPIO0)) 44 + 45 + static int puv3_gpio_type(unsigned int irq, unsigned int type) 46 + { 47 + unsigned int mask; 48 + 49 + if (irq < IRQ_GPIOHIGH) 50 + mask = 1 << irq; 51 + else 52 + mask = GPIO_MASK(irq); 53 + 54 + if (type == IRQ_TYPE_PROBE) { 55 + if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) 56 + return 0; 57 + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; 58 + } 59 + 60 + if (type & IRQ_TYPE_EDGE_RISING) 61 + GPIO_IRQ_rising_edge |= mask; 62 + else 63 + GPIO_IRQ_rising_edge &= ~mask; 64 + if (type & IRQ_TYPE_EDGE_FALLING) 65 + GPIO_IRQ_falling_edge |= mask; 66 + else 67 + GPIO_IRQ_falling_edge &= ~mask; 68 + 69 + GPIO_GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; 70 + GPIO_GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; 71 + 72 + return 0; 73 + } 74 + 75 + /* 76 + * GPIO IRQs must be acknowledged. This is for IRQs from 0 to 7. 77 + */ 78 + static void puv3_low_gpio_ack(unsigned int irq) 79 + { 80 + GPIO_GEDR = (1 << irq); 81 + } 82 + 83 + static void puv3_low_gpio_mask(unsigned int irq) 84 + { 85 + INTC_ICMR &= ~(1 << irq); 86 + } 87 + 88 + static void puv3_low_gpio_unmask(unsigned int irq) 89 + { 90 + INTC_ICMR |= 1 << irq; 91 + } 92 + 93 + static int puv3_low_gpio_wake(unsigned int irq, unsigned int on) 94 + { 95 + if (on) 96 + PM_PWER |= 1 << irq; 97 + else 98 + PM_PWER &= ~(1 << irq); 99 + return 0; 100 + } 101 + 102 + static struct irq_chip puv3_low_gpio_chip = { 103 + .name = "GPIO-low", 104 + .ack = puv3_low_gpio_ack, 105 + .mask = puv3_low_gpio_mask, 106 + .unmask = puv3_low_gpio_unmask, 107 + .set_type = puv3_gpio_type, 108 + .set_wake = puv3_low_gpio_wake, 109 + }; 110 + 111 + /* 112 + * IRQ8 (GPIO0 through 27) handler. We enter here with the 113 + * irq_controller_lock held, and IRQs disabled. Decode the IRQ 114 + * and call the handler. 115 + */ 116 + static void 117 + puv3_gpio_handler(unsigned int irq, struct irq_desc *desc) 118 + { 119 + unsigned int mask; 120 + 121 + mask = GPIO_GEDR; 122 + do { 123 + /* 124 + * clear down all currently active IRQ sources. 125 + * We will be processing them all. 126 + */ 127 + GPIO_GEDR = mask; 128 + 129 + irq = IRQ_GPIO0; 130 + do { 131 + if (mask & 1) 132 + generic_handle_irq(irq); 133 + mask >>= 1; 134 + irq++; 135 + } while (mask); 136 + mask = GPIO_GEDR; 137 + } while (mask); 138 + } 139 + 140 + /* 141 + * GPIO0-27 edge IRQs need to be handled specially. 142 + * In addition, the IRQs are all collected up into one bit in the 143 + * interrupt controller registers. 144 + */ 145 + static void puv3_high_gpio_ack(unsigned int irq) 146 + { 147 + unsigned int mask = GPIO_MASK(irq); 148 + 149 + GPIO_GEDR = mask; 150 + } 151 + 152 + static void puv3_high_gpio_mask(unsigned int irq) 153 + { 154 + unsigned int mask = GPIO_MASK(irq); 155 + 156 + GPIO_IRQ_mask &= ~mask; 157 + 158 + GPIO_GRER &= ~mask; 159 + GPIO_GFER &= ~mask; 160 + } 161 + 162 + static void puv3_high_gpio_unmask(unsigned int irq) 163 + { 164 + unsigned int mask = GPIO_MASK(irq); 165 + 166 + GPIO_IRQ_mask |= mask; 167 + 168 + GPIO_GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; 169 + GPIO_GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; 170 + } 171 + 172 + static int puv3_high_gpio_wake(unsigned int irq, unsigned int on) 173 + { 174 + if (on) 175 + PM_PWER |= PM_PWER_GPIOHIGH; 176 + else 177 + PM_PWER &= ~PM_PWER_GPIOHIGH; 178 + return 0; 179 + } 180 + 181 + static struct irq_chip puv3_high_gpio_chip = { 182 + .name = "GPIO-high", 183 + .ack = puv3_high_gpio_ack, 184 + .mask = puv3_high_gpio_mask, 185 + .unmask = puv3_high_gpio_unmask, 186 + .set_type = puv3_gpio_type, 187 + .set_wake = puv3_high_gpio_wake, 188 + }; 189 + 190 + /* 191 + * We don't need to ACK IRQs on the PKUnity unless they're GPIOs 192 + * this is for internal IRQs i.e. from 8 to 31. 193 + */ 194 + static void puv3_mask_irq(unsigned int irq) 195 + { 196 + INTC_ICMR &= ~(1 << irq); 197 + } 198 + 199 + static void puv3_unmask_irq(unsigned int irq) 200 + { 201 + INTC_ICMR |= (1 << irq); 202 + } 203 + 204 + /* 205 + * Apart form GPIOs, only the RTC alarm can be a wakeup event. 206 + */ 207 + static int puv3_set_wake(unsigned int irq, unsigned int on) 208 + { 209 + if (irq == IRQ_RTCAlarm) { 210 + if (on) 211 + PM_PWER |= PM_PWER_RTC; 212 + else 213 + PM_PWER &= ~PM_PWER_RTC; 214 + return 0; 215 + } 216 + return -EINVAL; 217 + } 218 + 219 + static struct irq_chip puv3_normal_chip = { 220 + .name = "PKUnity-v3", 221 + .ack = puv3_mask_irq, 222 + .mask = puv3_mask_irq, 223 + .unmask = puv3_unmask_irq, 224 + .set_wake = puv3_set_wake, 225 + }; 226 + 227 + static struct resource irq_resource = { 228 + .name = "irqs", 229 + .start = PKUNITY_INTC_BASE, 230 + .end = PKUNITY_INTC_BASE + 0xFFFFF, 231 + }; 232 + 233 + static struct puv3_irq_state { 234 + unsigned int saved; 235 + unsigned int icmr; 236 + unsigned int iclr; 237 + unsigned int iccr; 238 + } puv3_irq_state; 239 + 240 + static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state) 241 + { 242 + struct puv3_irq_state *st = &puv3_irq_state; 243 + 244 + st->saved = 1; 245 + st->icmr = INTC_ICMR; 246 + st->iclr = INTC_ICLR; 247 + st->iccr = INTC_ICCR; 248 + 249 + /* 250 + * Disable all GPIO-based interrupts. 251 + */ 252 + INTC_ICMR &= ~(0x1ff); 253 + 254 + /* 255 + * Set the appropriate edges for wakeup. 256 + */ 257 + GPIO_GRER = PM_PWER & GPIO_IRQ_rising_edge; 258 + GPIO_GFER = PM_PWER & GPIO_IRQ_falling_edge; 259 + 260 + /* 261 + * Clear any pending GPIO interrupts. 262 + */ 263 + GPIO_GEDR = GPIO_GEDR; 264 + 265 + return 0; 266 + } 267 + 268 + static int puv3_irq_resume(struct sys_device *dev) 269 + { 270 + struct puv3_irq_state *st = &puv3_irq_state; 271 + 272 + if (st->saved) { 273 + INTC_ICCR = st->iccr; 274 + INTC_ICLR = st->iclr; 275 + 276 + GPIO_GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; 277 + GPIO_GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; 278 + 279 + INTC_ICMR = st->icmr; 280 + } 281 + return 0; 282 + } 283 + 284 + static struct sysdev_class puv3_irq_sysclass = { 285 + .name = "pkunity-irq", 286 + .suspend = puv3_irq_suspend, 287 + .resume = puv3_irq_resume, 288 + }; 289 + 290 + static struct sys_device puv3_irq_device = { 291 + .id = 0, 292 + .cls = &puv3_irq_sysclass, 293 + }; 294 + 295 + static int __init puv3_irq_init_devicefs(void) 296 + { 297 + sysdev_class_register(&puv3_irq_sysclass); 298 + return sysdev_register(&puv3_irq_device); 299 + } 300 + 301 + device_initcall(puv3_irq_init_devicefs); 302 + 303 + void __init init_IRQ(void) 304 + { 305 + unsigned int irq; 306 + 307 + request_resource(&iomem_resource, &irq_resource); 308 + 309 + /* disable all IRQs */ 310 + INTC_ICMR = 0; 311 + 312 + /* all IRQs are IRQ, not REAL */ 313 + INTC_ICLR = 0; 314 + 315 + /* clear all GPIO edge detects */ 316 + GPIO_GPIR = FMASK(8, 0) & ~FIELD(1, 1, GPI_SOFF_REQ); 317 + GPIO_GFER = 0; 318 + GPIO_GRER = 0; 319 + GPIO_GEDR = 0x0FFFFFFF; 320 + 321 + INTC_ICCR = 1; 322 + 323 + for (irq = 0; irq < IRQ_GPIOHIGH; irq++) { 324 + set_irq_chip(irq, &puv3_low_gpio_chip); 325 + set_irq_handler(irq, handle_edge_irq); 326 + irq_modify_status(irq, 327 + IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN, 328 + 0); 329 + } 330 + 331 + for (irq = IRQ_GPIOHIGH + 1; irq < IRQ_GPIO0; irq++) { 332 + set_irq_chip(irq, &puv3_normal_chip); 333 + set_irq_handler(irq, handle_level_irq); 334 + irq_modify_status(irq, 335 + IRQ_NOREQUEST | IRQ_NOAUTOEN, 336 + IRQ_NOPROBE); 337 + } 338 + 339 + for (irq = IRQ_GPIO0; irq <= IRQ_GPIO27; irq++) { 340 + set_irq_chip(irq, &puv3_high_gpio_chip); 341 + set_irq_handler(irq, handle_edge_irq); 342 + irq_modify_status(irq, 343 + IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN, 344 + 0); 345 + } 346 + 347 + /* 348 + * Install handler for GPIO 0-27 edge detect interrupts 349 + */ 350 + set_irq_chip(IRQ_GPIOHIGH, &puv3_normal_chip); 351 + set_irq_chained_handler(IRQ_GPIOHIGH, puv3_gpio_handler); 352 + 353 + #ifdef CONFIG_PUV3_GPIO 354 + puv3_init_gpio(); 355 + #endif 356 + } 357 + 358 + int show_interrupts(struct seq_file *p, void *v) 359 + { 360 + int i = *(loff_t *) v, cpu; 361 + struct irq_desc *desc; 362 + struct irqaction *action; 363 + unsigned long flags; 364 + 365 + if (i == 0) { 366 + char cpuname[12]; 367 + 368 + seq_printf(p, " "); 369 + for_each_present_cpu(cpu) { 370 + sprintf(cpuname, "CPU%d", cpu); 371 + seq_printf(p, " %10s", cpuname); 372 + } 373 + seq_putc(p, '\n'); 374 + } 375 + 376 + if (i < nr_irqs) { 377 + desc = irq_to_desc(i); 378 + raw_spin_lock_irqsave(&desc->lock, flags); 379 + action = desc->action; 380 + if (!action) 381 + goto unlock; 382 + 383 + seq_printf(p, "%3d: ", i); 384 + for_each_present_cpu(cpu) 385 + seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); 386 + seq_printf(p, " %10s", desc->chip->name ? : "-"); 387 + seq_printf(p, " %s", action->name); 388 + for (action = action->next; action; action = action->next) 389 + seq_printf(p, ", %s", action->name); 390 + 391 + seq_putc(p, '\n'); 392 + unlock: 393 + raw_spin_unlock_irqrestore(&desc->lock, flags); 394 + } else if (i == nr_irqs) { 395 + seq_printf(p, "Error in interrupt!\n"); 396 + } 397 + return 0; 398 + } 399 + 400 + /* 401 + * do_IRQ handles all hardware IRQ's. Decoded IRQs should not 402 + * come via this function. Instead, they should provide their 403 + * own 'handler' 404 + */ 405 + asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) 406 + { 407 + struct pt_regs *old_regs = set_irq_regs(regs); 408 + 409 + irq_enter(); 410 + 411 + /* 412 + * Some hardware gives randomly wrong interrupts. Rather 413 + * than crashing, do something sensible. 414 + */ 415 + if (unlikely(irq >= nr_irqs)) { 416 + if (printk_ratelimit()) 417 + printk(KERN_WARNING "Bad IRQ%u\n", irq); 418 + ack_bad_irq(irq); 419 + } else { 420 + generic_handle_irq(irq); 421 + } 422 + 423 + irq_exit(); 424 + set_irq_regs(old_regs); 425 + } 426 +