diff options
author | Arnd Bergmann <arnd@arndb.de> | 2015-05-07 12:23:00 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2015-05-07 12:23:00 -0400 |
commit | 1be518bd0bf77eedf9bbda5d5b25466f615813b2 (patch) | |
tree | 76e6c608757db247f1106c387e618295f5541626 /arch | |
parent | c92b83a81ad09267619ccd077ddd2a5e321d8a61 (diff) | |
parent | fc9e38c0f4d38bfc68b405cf48365d65f7b6319e (diff) |
Merge tag 'fixes-for-v4.1-rc2' of https://github.com/rjarzmik/linux into fixes
Merged "ARM: pxa: fixes for v4.1-rc2" from Robert Jarzmik:
These fixes reenable the lubbock(pxa25x) and mainstone(pxa27x)
platforms, which were broken since the gpio handling was
converted to a driver, and the interrupt ordering broke the
external interrupts of these systems.
* tag 'fixes-for-v4.1-rc2' of https://github.com/rjarzmik/linux:
ARM: pxa: lubbock: use new pxa_cplds driver
ARM: pxa: mainstone: use new pxa_cplds driver
ARM: pxa: pxa_cplds: add lubbock and mainstone IO
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-pxa/Kconfig | 9 | ||||
-rw-r--r-- | arch/arm/mach-pxa/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-pxa/include/mach/lubbock.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-pxa/include/mach/mainstone.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-pxa/lubbock.c | 108 | ||||
-rw-r--r-- | arch/arm/mach-pxa/mainstone.c | 115 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa_cplds_irqs.c | 200 |
7 files changed, 274 insertions, 172 deletions
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 8896e71586f5..f09683687963 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig | |||
@@ -691,4 +691,13 @@ config SHARPSL_PM_MAX1111 | |||
691 | config PXA310_ULPI | 691 | config PXA310_ULPI |
692 | bool | 692 | bool |
693 | 693 | ||
694 | config PXA_SYSTEMS_CPLDS | ||
695 | tristate "Motherboard cplds" | ||
696 | default ARCH_LUBBOCK || MACH_MAINSTONE | ||
697 | help | ||
698 | This driver supports the Lubbock and Mainstone multifunction chip | ||
699 | found on the pxa25x development platform system (Lubbock) and pxa27x | ||
700 | development platform system (Mainstone). This IO board supports the | ||
701 | interrupts handling, ethernet controller, flash chips, etc ... | ||
702 | |||
694 | endif | 703 | endif |
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index eb0bf7678a99..4087d334ecdf 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile | |||
@@ -90,4 +90,5 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o | |||
90 | obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o | 90 | obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o |
91 | obj-$(CONFIG_MACH_ZIPIT2) += z2.o | 91 | obj-$(CONFIG_MACH_ZIPIT2) += z2.o |
92 | 92 | ||
93 | obj-$(CONFIG_PXA_SYSTEMS_CPLDS) += pxa_cplds_irqs.o | ||
93 | obj-$(CONFIG_TOSA_BT) += tosa-bt.o | 94 | obj-$(CONFIG_TOSA_BT) += tosa-bt.o |
diff --git a/arch/arm/mach-pxa/include/mach/lubbock.h b/arch/arm/mach-pxa/include/mach/lubbock.h index 958cd6af9384..1eecf794acd2 100644 --- a/arch/arm/mach-pxa/include/mach/lubbock.h +++ b/arch/arm/mach-pxa/include/mach/lubbock.h | |||
@@ -37,7 +37,9 @@ | |||
37 | #define LUB_GP __LUB_REG(LUBBOCK_FPGA_PHYS + 0x100) | 37 | #define LUB_GP __LUB_REG(LUBBOCK_FPGA_PHYS + 0x100) |
38 | 38 | ||
39 | /* Board specific IRQs */ | 39 | /* Board specific IRQs */ |
40 | #define LUBBOCK_IRQ(x) (IRQ_BOARD_START + (x)) | 40 | #define LUBBOCK_NR_IRQS IRQ_BOARD_START |
41 | |||
42 | #define LUBBOCK_IRQ(x) (LUBBOCK_NR_IRQS + (x)) | ||
41 | #define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0) | 43 | #define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0) |
42 | #define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1) | 44 | #define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1) |
43 | #define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2) /* usb connect */ | 45 | #define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2) /* usb connect */ |
@@ -47,8 +49,7 @@ | |||
47 | #define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */ | 49 | #define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */ |
48 | #define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6) | 50 | #define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6) |
49 | 51 | ||
50 | #define LUBBOCK_SA1111_IRQ_BASE (IRQ_BOARD_START + 16) | 52 | #define LUBBOCK_SA1111_IRQ_BASE (LUBBOCK_NR_IRQS + 32) |
51 | #define LUBBOCK_NR_IRQS (IRQ_BOARD_START + 16 + 55) | ||
52 | 53 | ||
53 | #ifndef __ASSEMBLY__ | 54 | #ifndef __ASSEMBLY__ |
54 | extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set); | 55 | extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set); |
diff --git a/arch/arm/mach-pxa/include/mach/mainstone.h b/arch/arm/mach-pxa/include/mach/mainstone.h index 1bfc4e822a41..e82a7d31104e 100644 --- a/arch/arm/mach-pxa/include/mach/mainstone.h +++ b/arch/arm/mach-pxa/include/mach/mainstone.h | |||
@@ -120,7 +120,9 @@ | |||
120 | #define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */ | 120 | #define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */ |
121 | 121 | ||
122 | /* board specific IRQs */ | 122 | /* board specific IRQs */ |
123 | #define MAINSTONE_IRQ(x) (IRQ_BOARD_START + (x)) | 123 | #define MAINSTONE_NR_IRQS IRQ_BOARD_START |
124 | |||
125 | #define MAINSTONE_IRQ(x) (MAINSTONE_NR_IRQS + (x)) | ||
124 | #define MAINSTONE_MMC_IRQ MAINSTONE_IRQ(0) | 126 | #define MAINSTONE_MMC_IRQ MAINSTONE_IRQ(0) |
125 | #define MAINSTONE_USIM_IRQ MAINSTONE_IRQ(1) | 127 | #define MAINSTONE_USIM_IRQ MAINSTONE_IRQ(1) |
126 | #define MAINSTONE_USBC_IRQ MAINSTONE_IRQ(2) | 128 | #define MAINSTONE_USBC_IRQ MAINSTONE_IRQ(2) |
@@ -136,6 +138,4 @@ | |||
136 | #define MAINSTONE_S1_STSCHG_IRQ MAINSTONE_IRQ(14) | 138 | #define MAINSTONE_S1_STSCHG_IRQ MAINSTONE_IRQ(14) |
137 | #define MAINSTONE_S1_IRQ MAINSTONE_IRQ(15) | 139 | #define MAINSTONE_S1_IRQ MAINSTONE_IRQ(15) |
138 | 140 | ||
139 | #define MAINSTONE_NR_IRQS (IRQ_BOARD_START + 16) | ||
140 | |||
141 | #endif | 141 | #endif |
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index d8a1be619f21..4ac9ab80d24b 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
15 | #include <linux/gpio/machine.h> | ||
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | 18 | #include <linux/init.h> |
@@ -123,84 +124,6 @@ void lubbock_set_misc_wr(unsigned int mask, unsigned int set) | |||
123 | } | 124 | } |
124 | EXPORT_SYMBOL(lubbock_set_misc_wr); | 125 | EXPORT_SYMBOL(lubbock_set_misc_wr); |
125 | 126 | ||
126 | static unsigned long lubbock_irq_enabled; | ||
127 | |||
128 | static void lubbock_mask_irq(struct irq_data *d) | ||
129 | { | ||
130 | int lubbock_irq = (d->irq - LUBBOCK_IRQ(0)); | ||
131 | LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq)); | ||
132 | } | ||
133 | |||
134 | static void lubbock_unmask_irq(struct irq_data *d) | ||
135 | { | ||
136 | int lubbock_irq = (d->irq - LUBBOCK_IRQ(0)); | ||
137 | /* the irq can be acknowledged only if deasserted, so it's done here */ | ||
138 | LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq); | ||
139 | LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq)); | ||
140 | } | ||
141 | |||
142 | static struct irq_chip lubbock_irq_chip = { | ||
143 | .name = "FPGA", | ||
144 | .irq_ack = lubbock_mask_irq, | ||
145 | .irq_mask = lubbock_mask_irq, | ||
146 | .irq_unmask = lubbock_unmask_irq, | ||
147 | }; | ||
148 | |||
149 | static void lubbock_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
150 | { | ||
151 | unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; | ||
152 | do { | ||
153 | /* clear our parent irq */ | ||
154 | desc->irq_data.chip->irq_ack(&desc->irq_data); | ||
155 | if (likely(pending)) { | ||
156 | irq = LUBBOCK_IRQ(0) + __ffs(pending); | ||
157 | generic_handle_irq(irq); | ||
158 | } | ||
159 | pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; | ||
160 | } while (pending); | ||
161 | } | ||
162 | |||
163 | static void __init lubbock_init_irq(void) | ||
164 | { | ||
165 | int irq; | ||
166 | |||
167 | pxa25x_init_irq(); | ||
168 | |||
169 | /* setup extra lubbock irqs */ | ||
170 | for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { | ||
171 | irq_set_chip_and_handler(irq, &lubbock_irq_chip, | ||
172 | handle_level_irq); | ||
173 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
174 | } | ||
175 | |||
176 | irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), lubbock_irq_handler); | ||
177 | irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING); | ||
178 | } | ||
179 | |||
180 | #ifdef CONFIG_PM | ||
181 | |||
182 | static void lubbock_irq_resume(void) | ||
183 | { | ||
184 | LUB_IRQ_MASK_EN = lubbock_irq_enabled; | ||
185 | } | ||
186 | |||
187 | static struct syscore_ops lubbock_irq_syscore_ops = { | ||
188 | .resume = lubbock_irq_resume, | ||
189 | }; | ||
190 | |||
191 | static int __init lubbock_irq_device_init(void) | ||
192 | { | ||
193 | if (machine_is_lubbock()) { | ||
194 | register_syscore_ops(&lubbock_irq_syscore_ops); | ||
195 | return 0; | ||
196 | } | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | |||
200 | device_initcall(lubbock_irq_device_init); | ||
201 | |||
202 | #endif | ||
203 | |||
204 | static int lubbock_udc_is_connected(void) | 127 | static int lubbock_udc_is_connected(void) |
205 | { | 128 | { |
206 | return (LUB_MISC_RD & (1 << 9)) == 0; | 129 | return (LUB_MISC_RD & (1 << 9)) == 0; |
@@ -383,11 +306,38 @@ static struct platform_device lubbock_flash_device[2] = { | |||
383 | }, | 306 | }, |
384 | }; | 307 | }; |
385 | 308 | ||
309 | static struct resource lubbock_cplds_resources[] = { | ||
310 | [0] = { | ||
311 | .start = LUBBOCK_FPGA_PHYS + 0xc0, | ||
312 | .end = LUBBOCK_FPGA_PHYS + 0xe0 - 1, | ||
313 | .flags = IORESOURCE_MEM, | ||
314 | }, | ||
315 | [1] = { | ||
316 | .start = PXA_GPIO_TO_IRQ(0), | ||
317 | .end = PXA_GPIO_TO_IRQ(0), | ||
318 | .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, | ||
319 | }, | ||
320 | [2] = { | ||
321 | .start = LUBBOCK_IRQ(0), | ||
322 | .end = LUBBOCK_IRQ(6), | ||
323 | .flags = IORESOURCE_IRQ, | ||
324 | }, | ||
325 | }; | ||
326 | |||
327 | static struct platform_device lubbock_cplds_device = { | ||
328 | .name = "pxa_cplds_irqs", | ||
329 | .id = -1, | ||
330 | .resource = &lubbock_cplds_resources[0], | ||
331 | .num_resources = 3, | ||
332 | }; | ||
333 | |||
334 | |||
386 | static struct platform_device *devices[] __initdata = { | 335 | static struct platform_device *devices[] __initdata = { |
387 | &sa1111_device, | 336 | &sa1111_device, |
388 | &smc91x_device, | 337 | &smc91x_device, |
389 | &lubbock_flash_device[0], | 338 | &lubbock_flash_device[0], |
390 | &lubbock_flash_device[1], | 339 | &lubbock_flash_device[1], |
340 | &lubbock_cplds_device, | ||
391 | }; | 341 | }; |
392 | 342 | ||
393 | static struct pxafb_mode_info sharp_lm8v31_mode = { | 343 | static struct pxafb_mode_info sharp_lm8v31_mode = { |
@@ -648,7 +598,7 @@ MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)") | |||
648 | /* Maintainer: MontaVista Software Inc. */ | 598 | /* Maintainer: MontaVista Software Inc. */ |
649 | .map_io = lubbock_map_io, | 599 | .map_io = lubbock_map_io, |
650 | .nr_irqs = LUBBOCK_NR_IRQS, | 600 | .nr_irqs = LUBBOCK_NR_IRQS, |
651 | .init_irq = lubbock_init_irq, | 601 | .init_irq = pxa25x_init_irq, |
652 | .handle_irq = pxa25x_handle_irq, | 602 | .handle_irq = pxa25x_handle_irq, |
653 | .init_time = pxa_timer_init, | 603 | .init_time = pxa_timer_init, |
654 | .init_machine = lubbock_init, | 604 | .init_machine = lubbock_init, |
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 78b84c0dfc79..2c0658cf6be2 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c | |||
@@ -13,6 +13,7 @@ | |||
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | */ | 14 | */ |
15 | #include <linux/gpio.h> | 15 | #include <linux/gpio.h> |
16 | #include <linux/gpio/machine.h> | ||
16 | #include <linux/init.h> | 17 | #include <linux/init.h> |
17 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
18 | #include <linux/syscore_ops.h> | 19 | #include <linux/syscore_ops.h> |
@@ -122,92 +123,6 @@ static unsigned long mainstone_pin_config[] = { | |||
122 | GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH, | 123 | GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH, |
123 | }; | 124 | }; |
124 | 125 | ||
125 | static unsigned long mainstone_irq_enabled; | ||
126 | |||
127 | static void mainstone_mask_irq(struct irq_data *d) | ||
128 | { | ||
129 | int mainstone_irq = (d->irq - MAINSTONE_IRQ(0)); | ||
130 | MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq)); | ||
131 | } | ||
132 | |||
133 | static void mainstone_unmask_irq(struct irq_data *d) | ||
134 | { | ||
135 | int mainstone_irq = (d->irq - MAINSTONE_IRQ(0)); | ||
136 | /* the irq can be acknowledged only if deasserted, so it's done here */ | ||
137 | MST_INTSETCLR &= ~(1 << mainstone_irq); | ||
138 | MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq)); | ||
139 | } | ||
140 | |||
141 | static struct irq_chip mainstone_irq_chip = { | ||
142 | .name = "FPGA", | ||
143 | .irq_ack = mainstone_mask_irq, | ||
144 | .irq_mask = mainstone_mask_irq, | ||
145 | .irq_unmask = mainstone_unmask_irq, | ||
146 | }; | ||
147 | |||
148 | static void mainstone_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
149 | { | ||
150 | unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled; | ||
151 | do { | ||
152 | /* clear useless edge notification */ | ||
153 | desc->irq_data.chip->irq_ack(&desc->irq_data); | ||
154 | if (likely(pending)) { | ||
155 | irq = MAINSTONE_IRQ(0) + __ffs(pending); | ||
156 | generic_handle_irq(irq); | ||
157 | } | ||
158 | pending = MST_INTSETCLR & mainstone_irq_enabled; | ||
159 | } while (pending); | ||
160 | } | ||
161 | |||
162 | static void __init mainstone_init_irq(void) | ||
163 | { | ||
164 | int irq; | ||
165 | |||
166 | pxa27x_init_irq(); | ||
167 | |||
168 | /* setup extra Mainstone irqs */ | ||
169 | for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) { | ||
170 | irq_set_chip_and_handler(irq, &mainstone_irq_chip, | ||
171 | handle_level_irq); | ||
172 | if (irq == MAINSTONE_IRQ(10) || irq == MAINSTONE_IRQ(14)) | ||
173 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE | IRQF_NOAUTOEN); | ||
174 | else | ||
175 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
176 | } | ||
177 | set_irq_flags(MAINSTONE_IRQ(8), 0); | ||
178 | set_irq_flags(MAINSTONE_IRQ(12), 0); | ||
179 | |||
180 | MST_INTMSKENA = 0; | ||
181 | MST_INTSETCLR = 0; | ||
182 | |||
183 | irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), mainstone_irq_handler); | ||
184 | irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING); | ||
185 | } | ||
186 | |||
187 | #ifdef CONFIG_PM | ||
188 | |||
189 | static void mainstone_irq_resume(void) | ||
190 | { | ||
191 | MST_INTMSKENA = mainstone_irq_enabled; | ||
192 | } | ||
193 | |||
194 | static struct syscore_ops mainstone_irq_syscore_ops = { | ||
195 | .resume = mainstone_irq_resume, | ||
196 | }; | ||
197 | |||
198 | static int __init mainstone_irq_device_init(void) | ||
199 | { | ||
200 | if (machine_is_mainstone()) | ||
201 | register_syscore_ops(&mainstone_irq_syscore_ops); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | device_initcall(mainstone_irq_device_init); | ||
207 | |||
208 | #endif | ||
209 | |||
210 | |||
211 | static struct resource smc91x_resources[] = { | 126 | static struct resource smc91x_resources[] = { |
212 | [0] = { | 127 | [0] = { |
213 | .start = (MST_ETH_PHYS + 0x300), | 128 | .start = (MST_ETH_PHYS + 0x300), |
@@ -487,11 +402,37 @@ static struct platform_device mst_gpio_keys_device = { | |||
487 | }, | 402 | }, |
488 | }; | 403 | }; |
489 | 404 | ||
405 | static struct resource mst_cplds_resources[] = { | ||
406 | [0] = { | ||
407 | .start = MST_FPGA_PHYS + 0xc0, | ||
408 | .end = MST_FPGA_PHYS + 0xe0 - 1, | ||
409 | .flags = IORESOURCE_MEM, | ||
410 | }, | ||
411 | [1] = { | ||
412 | .start = PXA_GPIO_TO_IRQ(0), | ||
413 | .end = PXA_GPIO_TO_IRQ(0), | ||
414 | .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, | ||
415 | }, | ||
416 | [2] = { | ||
417 | .start = MAINSTONE_IRQ(0), | ||
418 | .end = MAINSTONE_IRQ(15), | ||
419 | .flags = IORESOURCE_IRQ, | ||
420 | }, | ||
421 | }; | ||
422 | |||
423 | static struct platform_device mst_cplds_device = { | ||
424 | .name = "pxa_cplds_irqs", | ||
425 | .id = -1, | ||
426 | .resource = &mst_cplds_resources[0], | ||
427 | .num_resources = 3, | ||
428 | }; | ||
429 | |||
490 | static struct platform_device *platform_devices[] __initdata = { | 430 | static struct platform_device *platform_devices[] __initdata = { |
491 | &smc91x_device, | 431 | &smc91x_device, |
492 | &mst_flash_device[0], | 432 | &mst_flash_device[0], |
493 | &mst_flash_device[1], | 433 | &mst_flash_device[1], |
494 | &mst_gpio_keys_device, | 434 | &mst_gpio_keys_device, |
435 | &mst_cplds_device, | ||
495 | }; | 436 | }; |
496 | 437 | ||
497 | static struct pxaohci_platform_data mainstone_ohci_platform_data = { | 438 | static struct pxaohci_platform_data mainstone_ohci_platform_data = { |
@@ -718,7 +659,7 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") | |||
718 | .atag_offset = 0x100, /* BLOB boot parameter setting */ | 659 | .atag_offset = 0x100, /* BLOB boot parameter setting */ |
719 | .map_io = mainstone_map_io, | 660 | .map_io = mainstone_map_io, |
720 | .nr_irqs = MAINSTONE_NR_IRQS, | 661 | .nr_irqs = MAINSTONE_NR_IRQS, |
721 | .init_irq = mainstone_init_irq, | 662 | .init_irq = pxa27x_init_irq, |
722 | .handle_irq = pxa27x_handle_irq, | 663 | .handle_irq = pxa27x_handle_irq, |
723 | .init_time = pxa_timer_init, | 664 | .init_time = pxa_timer_init, |
724 | .init_machine = mainstone_init, | 665 | .init_machine = mainstone_init, |
diff --git a/arch/arm/mach-pxa/pxa_cplds_irqs.c b/arch/arm/mach-pxa/pxa_cplds_irqs.c new file mode 100644 index 000000000000..f1aeb54fabe3 --- /dev/null +++ b/arch/arm/mach-pxa/pxa_cplds_irqs.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * Intel Reference Systems cplds | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * Cplds motherboard driver, supporting lubbock and mainstone SoC board. | ||
12 | */ | ||
13 | |||
14 | #include <linux/bitops.h> | ||
15 | #include <linux/gpio.h> | ||
16 | #include <linux/gpio/consumer.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/irqdomain.h> | ||
21 | #include <linux/mfd/core.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of_platform.h> | ||
24 | |||
25 | #define FPGA_IRQ_MASK_EN 0x0 | ||
26 | #define FPGA_IRQ_SET_CLR 0x10 | ||
27 | |||
28 | #define CPLDS_NB_IRQ 32 | ||
29 | |||
30 | struct cplds { | ||
31 | void __iomem *base; | ||
32 | int irq; | ||
33 | unsigned int irq_mask; | ||
34 | struct gpio_desc *gpio0; | ||
35 | struct irq_domain *irqdomain; | ||
36 | }; | ||
37 | |||
38 | static irqreturn_t cplds_irq_handler(int in_irq, void *d) | ||
39 | { | ||
40 | struct cplds *fpga = d; | ||
41 | unsigned long pending; | ||
42 | unsigned int bit; | ||
43 | |||
44 | pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask; | ||
45 | for_each_set_bit(bit, &pending, CPLDS_NB_IRQ) | ||
46 | generic_handle_irq(irq_find_mapping(fpga->irqdomain, bit)); | ||
47 | |||
48 | return IRQ_HANDLED; | ||
49 | } | ||
50 | |||
51 | static void cplds_irq_mask_ack(struct irq_data *d) | ||
52 | { | ||
53 | struct cplds *fpga = irq_data_get_irq_chip_data(d); | ||
54 | unsigned int cplds_irq = irqd_to_hwirq(d); | ||
55 | unsigned int set, bit = BIT(cplds_irq); | ||
56 | |||
57 | fpga->irq_mask &= ~bit; | ||
58 | writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN); | ||
59 | set = readl(fpga->base + FPGA_IRQ_SET_CLR); | ||
60 | writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR); | ||
61 | } | ||
62 | |||
63 | static void cplds_irq_unmask(struct irq_data *d) | ||
64 | { | ||
65 | struct cplds *fpga = irq_data_get_irq_chip_data(d); | ||
66 | unsigned int cplds_irq = irqd_to_hwirq(d); | ||
67 | unsigned int bit = BIT(cplds_irq); | ||
68 | |||
69 | fpga->irq_mask |= bit; | ||
70 | writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN); | ||
71 | } | ||
72 | |||
73 | static struct irq_chip cplds_irq_chip = { | ||
74 | .name = "pxa_cplds", | ||
75 | .irq_mask_ack = cplds_irq_mask_ack, | ||
76 | .irq_unmask = cplds_irq_unmask, | ||
77 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, | ||
78 | }; | ||
79 | |||
80 | static int cplds_irq_domain_map(struct irq_domain *d, unsigned int irq, | ||
81 | irq_hw_number_t hwirq) | ||
82 | { | ||
83 | struct cplds *fpga = d->host_data; | ||
84 | |||
85 | irq_set_chip_and_handler(irq, &cplds_irq_chip, handle_level_irq); | ||
86 | irq_set_chip_data(irq, fpga); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static const struct irq_domain_ops cplds_irq_domain_ops = { | ||
92 | .xlate = irq_domain_xlate_twocell, | ||
93 | .map = cplds_irq_domain_map, | ||
94 | }; | ||
95 | |||
96 | static int cplds_resume(struct platform_device *pdev) | ||
97 | { | ||
98 | struct cplds *fpga = platform_get_drvdata(pdev); | ||
99 | |||
100 | writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int cplds_probe(struct platform_device *pdev) | ||
106 | { | ||
107 | struct resource *res; | ||
108 | struct cplds *fpga; | ||
109 | int ret; | ||
110 | unsigned int base_irq = 0; | ||
111 | unsigned long irqflags = 0; | ||
112 | |||
113 | fpga = devm_kzalloc(&pdev->dev, sizeof(*fpga), GFP_KERNEL); | ||
114 | if (!fpga) | ||
115 | return -ENOMEM; | ||
116 | |||
117 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
118 | if (res) { | ||
119 | fpga->irq = (unsigned int)res->start; | ||
120 | irqflags = res->flags; | ||
121 | } | ||
122 | if (!fpga->irq) | ||
123 | return -ENODEV; | ||
124 | |||
125 | base_irq = platform_get_irq(pdev, 1); | ||
126 | if (base_irq < 0) | ||
127 | base_irq = 0; | ||
128 | |||
129 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
130 | fpga->base = devm_ioremap_resource(&pdev->dev, res); | ||
131 | if (IS_ERR(fpga->base)) | ||
132 | return PTR_ERR(fpga->base); | ||
133 | |||
134 | platform_set_drvdata(pdev, fpga); | ||
135 | |||
136 | writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN); | ||
137 | writel(0, fpga->base + FPGA_IRQ_SET_CLR); | ||
138 | |||
139 | ret = devm_request_irq(&pdev->dev, fpga->irq, cplds_irq_handler, | ||
140 | irqflags, dev_name(&pdev->dev), fpga); | ||
141 | if (ret == -ENOSYS) | ||
142 | return -EPROBE_DEFER; | ||
143 | |||
144 | if (ret) { | ||
145 | dev_err(&pdev->dev, "couldn't request main irq%d: %d\n", | ||
146 | fpga->irq, ret); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | irq_set_irq_wake(fpga->irq, 1); | ||
151 | fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node, | ||
152 | CPLDS_NB_IRQ, | ||
153 | &cplds_irq_domain_ops, fpga); | ||
154 | if (!fpga->irqdomain) | ||
155 | return -ENODEV; | ||
156 | |||
157 | if (base_irq) { | ||
158 | ret = irq_create_strict_mappings(fpga->irqdomain, base_irq, 0, | ||
159 | CPLDS_NB_IRQ); | ||
160 | if (ret) { | ||
161 | dev_err(&pdev->dev, "couldn't create the irq mapping %d..%d\n", | ||
162 | base_irq, base_irq + CPLDS_NB_IRQ); | ||
163 | return ret; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int cplds_remove(struct platform_device *pdev) | ||
171 | { | ||
172 | struct cplds *fpga = platform_get_drvdata(pdev); | ||
173 | |||
174 | irq_set_chip_and_handler(fpga->irq, NULL, NULL); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static const struct of_device_id cplds_id_table[] = { | ||
180 | { .compatible = "intel,lubbock-cplds-irqs", }, | ||
181 | { .compatible = "intel,mainstone-cplds-irqs", }, | ||
182 | { } | ||
183 | }; | ||
184 | MODULE_DEVICE_TABLE(of, cplds_id_table); | ||
185 | |||
186 | static struct platform_driver cplds_driver = { | ||
187 | .driver = { | ||
188 | .name = "pxa_cplds_irqs", | ||
189 | .of_match_table = of_match_ptr(cplds_id_table), | ||
190 | }, | ||
191 | .probe = cplds_probe, | ||
192 | .remove = cplds_remove, | ||
193 | .resume = cplds_resume, | ||
194 | }; | ||
195 | |||
196 | module_platform_driver(cplds_driver); | ||
197 | |||
198 | MODULE_DESCRIPTION("PXA Cplds interrupts driver"); | ||
199 | MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>"); | ||
200 | MODULE_LICENSE("GPL"); | ||