aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGuanXuetao <gxt@mprc.pku.edu.cn>2011-01-15 05:19:35 -0500
committerGuanXuetao <gxt@mprc.pku.edu.cn>2011-03-16 21:19:10 -0400
commit752bcb4d02ccfd5e7a8d810424154169b4cca8ae (patch)
treed435061fe9405f70d51aef55392062460515ca30 /arch
parent02b2ee16cc31df2b23d6f6c68a597d947f6c10e8 (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/unicore32/include/asm/gpio.h103
-rw-r--r--arch/unicore32/include/asm/irq.h107
-rw-r--r--arch/unicore32/include/asm/irqflags.h53
-rw-r--r--arch/unicore32/kernel/gpio.c122
-rw-r--r--arch/unicore32/kernel/irq.c426
5 files changed, 811 insertions, 0 deletions
diff --git a/arch/unicore32/include/asm/gpio.h b/arch/unicore32/include/asm/gpio.h
new file mode 100644
index 000000000000..3aaa41e9e413
--- /dev/null
+++ b/arch/unicore32/include/asm/gpio.h
@@ -0,0 +1,103 @@
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
66static 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
74static 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
87static 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
95static 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__ */
diff --git a/arch/unicore32/include/asm/irq.h b/arch/unicore32/include/asm/irq.h
new file mode 100644
index 000000000000..ade8bb87111d
--- /dev/null
+++ b/arch/unicore32/include/asm/irq.h
@@ -0,0 +1,107 @@
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__
98struct irqaction;
99struct pt_regs;
100extern void migrate_irqs(void);
101
102extern void asm_do_IRQ(unsigned int, struct pt_regs *);
103
104#endif
105
106#endif
107
diff --git a/arch/unicore32/include/asm/irqflags.h b/arch/unicore32/include/asm/irqflags.h
new file mode 100644
index 000000000000..6d8a28dfdbae
--- /dev/null
+++ b/arch/unicore32/include/asm/irqflags.h
@@ -0,0 +1,53 @@
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 */
25static 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 */
37static 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
diff --git a/arch/unicore32/kernel/gpio.c b/arch/unicore32/kernel/gpio.c
new file mode 100644
index 000000000000..4cb28308bb5f
--- /dev/null
+++ b/arch/unicore32/kernel/gpio.c
@@ -0,0 +1,122 @@
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
24static 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
31static 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
36static 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
44static int __init puv3_gpio_leds_init(void)
45{
46 platform_device_register(&puv3_gpio_gpio_leds);
47 return 0;
48}
49
50device_initcall(puv3_gpio_leds_init);
51#endif
52
53static int puv3_gpio_get(struct gpio_chip *chip, unsigned offset)
54{
55 return GPIO_GPLR & GPIO_GPIO(offset);
56}
57
58static 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
66static 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
76static 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
88static 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
98void __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}
diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c
new file mode 100644
index 000000000000..7c211f597833
--- /dev/null
+++ b/arch/unicore32/kernel/irq.c
@@ -0,0 +1,426 @@
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 */
39static int GPIO_IRQ_rising_edge;
40static int GPIO_IRQ_falling_edge;
41static int GPIO_IRQ_mask = 0;
42
43#define GPIO_MASK(irq) (1 << (irq - IRQ_GPIO0))
44
45static 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 */
78static void puv3_low_gpio_ack(unsigned int irq)
79{
80 GPIO_GEDR = (1 << irq);
81}
82
83static void puv3_low_gpio_mask(unsigned int irq)
84{
85 INTC_ICMR &= ~(1 << irq);
86}
87
88static void puv3_low_gpio_unmask(unsigned int irq)
89{
90 INTC_ICMR |= 1 << irq;
91}
92
93static 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
102static 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 */
116static void
117puv3_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 */
145static void puv3_high_gpio_ack(unsigned int irq)
146{
147 unsigned int mask = GPIO_MASK(irq);
148
149 GPIO_GEDR = mask;
150}
151
152static 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
162static 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
172static 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
181static 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 */
194static void puv3_mask_irq(unsigned int irq)
195{
196 INTC_ICMR &= ~(1 << irq);
197}
198
199static 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 */
207static 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
219static 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
227static struct resource irq_resource = {
228 .name = "irqs",
229 .start = PKUNITY_INTC_BASE,
230 .end = PKUNITY_INTC_BASE + 0xFFFFF,
231};
232
233static 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
240static 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
268static 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
284static struct sysdev_class puv3_irq_sysclass = {
285 .name = "pkunity-irq",
286 .suspend = puv3_irq_suspend,
287 .resume = puv3_irq_resume,
288};
289
290static struct sys_device puv3_irq_device = {
291 .id = 0,
292 .cls = &puv3_irq_sysclass,
293};
294
295static int __init puv3_irq_init_devicefs(void)
296{
297 sysdev_class_register(&puv3_irq_sysclass);
298 return sysdev_register(&puv3_irq_device);
299}
300
301device_initcall(puv3_irq_init_devicefs);
302
303void __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
358int 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');
392unlock:
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 */
405asmlinkage 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