diff options
author | Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org> | 2008-09-09 04:19:42 -0400 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2008-09-09 04:19:42 -0400 |
commit | d7568f79d5c289d0d7859680be7b5afdcea0c9b2 (patch) | |
tree | dcf8e83c1fe917f08eb454a7b2bd9fe1edf02e8d /arch/arm/mach-mx3 | |
parent | 0741794c0d4192c45193d5e7f8e87a7bfb79ae0a (diff) |
i.MX31ADS: Add CPLD interrupts demultiplexing (take 3).
Needed for 8250 serial port and CS89x0 ethernet interface.
Signed-off-by: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-mx3')
-rw-r--r-- | arch/arm/mach-mx3/mx31ads.c | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c index 3b48d1ae3a87..0803fc6c0217 100644 --- a/arch/arm/mach-mx3/mx31ads.c +++ b/arch/arm/mach-mx3/mx31ads.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
24 | #include <linux/serial_8250.h> | 24 | #include <linux/serial_8250.h> |
25 | #include <linux/irq.h> | ||
25 | 26 | ||
26 | #include <mach/hardware.h> | 27 | #include <mach/hardware.h> |
27 | #include <asm/mach-types.h> | 28 | #include <asm/mach-types.h> |
@@ -106,6 +107,88 @@ static inline void mxc_init_imx_uart(void) | |||
106 | } | 107 | } |
107 | #endif /* !SERIAL_IMX */ | 108 | #endif /* !SERIAL_IMX */ |
108 | 109 | ||
110 | static void mx31ads_expio_irq_handler(u32 irq, struct irq_desc *desc) | ||
111 | { | ||
112 | u32 imr_val; | ||
113 | u32 int_valid; | ||
114 | u32 expio_irq; | ||
115 | |||
116 | imr_val = __raw_readw(PBC_INTMASK_SET_REG); | ||
117 | int_valid = __raw_readw(PBC_INTSTATUS_REG) & imr_val; | ||
118 | |||
119 | expio_irq = MXC_EXP_IO_BASE; | ||
120 | for (; int_valid != 0; int_valid >>= 1, expio_irq++) { | ||
121 | if ((int_valid & 1) == 0) | ||
122 | continue; | ||
123 | |||
124 | generic_handle_irq(expio_irq); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * Disable an expio pin's interrupt by setting the bit in the imr. | ||
130 | * @param irq an expio virtual irq number | ||
131 | */ | ||
132 | static void expio_mask_irq(u32 irq) | ||
133 | { | ||
134 | u32 expio = MXC_IRQ_TO_EXPIO(irq); | ||
135 | /* mask the interrupt */ | ||
136 | __raw_writew(1 << expio, PBC_INTMASK_CLEAR_REG); | ||
137 | __raw_readw(PBC_INTMASK_CLEAR_REG); | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr. | ||
142 | * @param irq an expanded io virtual irq number | ||
143 | */ | ||
144 | static void expio_ack_irq(u32 irq) | ||
145 | { | ||
146 | u32 expio = MXC_IRQ_TO_EXPIO(irq); | ||
147 | /* clear the interrupt status */ | ||
148 | __raw_writew(1 << expio, PBC_INTSTATUS_REG); | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Enable a expio pin's interrupt by clearing the bit in the imr. | ||
153 | * @param irq a expio virtual irq number | ||
154 | */ | ||
155 | static void expio_unmask_irq(u32 irq) | ||
156 | { | ||
157 | u32 expio = MXC_IRQ_TO_EXPIO(irq); | ||
158 | /* unmask the interrupt */ | ||
159 | __raw_writew(1 << expio, PBC_INTMASK_SET_REG); | ||
160 | } | ||
161 | |||
162 | static struct irq_chip expio_irq_chip = { | ||
163 | .ack = expio_ack_irq, | ||
164 | .mask = expio_mask_irq, | ||
165 | .unmask = expio_unmask_irq, | ||
166 | }; | ||
167 | |||
168 | static void __init mx31ads_init_expio(void) | ||
169 | { | ||
170 | int i; | ||
171 | |||
172 | printk(KERN_INFO "MX31ADS EXPIO(CPLD) hardware\n"); | ||
173 | |||
174 | /* | ||
175 | * Configure INT line as GPIO input | ||
176 | */ | ||
177 | mxc_iomux_mode(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO)); | ||
178 | |||
179 | /* disable the interrupt and clear the status */ | ||
180 | __raw_writew(0xFFFF, PBC_INTMASK_CLEAR_REG); | ||
181 | __raw_writew(0xFFFF, PBC_INTSTATUS_REG); | ||
182 | for (i = MXC_EXP_IO_BASE; i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES); | ||
183 | i++) { | ||
184 | set_irq_chip(i, &expio_irq_chip); | ||
185 | set_irq_handler(i, handle_level_irq); | ||
186 | set_irq_flags(i, IRQF_VALID); | ||
187 | } | ||
188 | set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_HIGH); | ||
189 | set_irq_chained_handler(EXPIO_PARENT_INT, mx31ads_expio_irq_handler); | ||
190 | } | ||
191 | |||
109 | /*! | 192 | /*! |
110 | * This structure defines static mappings for the i.MX31ADS board. | 193 | * This structure defines static mappings for the i.MX31ADS board. |
111 | */ | 194 | */ |
@@ -142,6 +225,12 @@ void __init mx31ads_map_io(void) | |||
142 | iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc)); | 225 | iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc)); |
143 | } | 226 | } |
144 | 227 | ||
228 | void __init mx31ads_init_irq(void) | ||
229 | { | ||
230 | mxc_init_irq(); | ||
231 | mx31ads_init_expio(); | ||
232 | } | ||
233 | |||
145 | /*! | 234 | /*! |
146 | * Board specific initialization. | 235 | * Board specific initialization. |
147 | */ | 236 | */ |
@@ -171,7 +260,7 @@ MACHINE_START(MX31ADS, "Freescale MX31ADS") | |||
171 | .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, | 260 | .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, |
172 | .boot_params = PHYS_OFFSET + 0x100, | 261 | .boot_params = PHYS_OFFSET + 0x100, |
173 | .map_io = mx31ads_map_io, | 262 | .map_io = mx31ads_map_io, |
174 | .init_irq = mxc_init_irq, | 263 | .init_irq = mx31ads_init_irq, |
175 | .init_machine = mxc_board_init, | 264 | .init_machine = mxc_board_init, |
176 | .timer = &mx31ads_timer, | 265 | .timer = &mx31ads_timer, |
177 | MACHINE_END | 266 | MACHINE_END |