aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap1/ams-delta-fiq.c
diff options
context:
space:
mode:
authorJanusz Krzysztofik <jkrzyszt@tis.icnet.pl>2010-04-27 21:03:59 -0400
committerTony Lindgren <tony@atomide.com>2010-05-05 14:11:10 -0400
commit11f9562a423896b6ecd449d829a2f34e06594301 (patch)
tree4feece5e9a095c1e109c8845357f89817f24c356 /arch/arm/mach-omap1/ams-delta-fiq.c
parent60c3bf3f1215453a4f30f0b91db7fd301d558693 (diff)
OMAP1: Amstrad Delta: add a handler for processing interruptsgenerated by the FIQ routine
This patch introduces an IRQ handler used for processing interrupts generated by the FIQ handler when it decides there are data ready for processing. The handler further invokes device specific interrupt routines based on interrupt source counters passed from the FIQ handler. The handler setup function is intended to be called from the board provided init_machine() callback. Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> [tony@atomide.com: Updated to include linux/io.h instead of plat/io.h Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap1/ams-delta-fiq.c')
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
new file mode 100644
index 000000000000..6c994e2d8879
--- /dev/null
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -0,0 +1,155 @@
1/*
2 * Amstrad E3 FIQ handling
3 *
4 * Copyright (C) 2009 Janusz Krzysztofik
5 * Copyright (c) 2006 Matt Callow
6 * Copyright (c) 2004 Amstrad Plc
7 * Copyright (C) 2001 RidgeRun, Inc.
8 *
9 * Parts of this code are taken from linux/arch/arm/mach-omap/irq.c
10 * in the MontaVista 2.4 kernel (and the Amstrad changes therein)
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 */
16#include <linux/gpio.h>
17#include <linux/interrupt.h>
18#include <linux/irq.h>
19#include <linux/module.h>
20#include <linux/io.h>
21
22#include <plat/board-ams-delta.h>
23
24#include <asm/fiq.h>
25#include <mach/ams-delta-fiq.h>
26
27static struct fiq_handler fh = {
28 .name = "ams-delta-fiq"
29};
30
31/*
32 * This buffer is shared between FIQ and IRQ contexts.
33 * The FIQ and IRQ isrs can both read and write it.
34 * It is structured as a header section several 32bit slots,
35 * followed by the circular buffer where the FIQ isr stores
36 * keystrokes received from the qwerty keyboard.
37 * See ams-delta-fiq.h for details of offsets.
38 */
39unsigned int fiq_buffer[1024];
40EXPORT_SYMBOL(fiq_buffer);
41
42static unsigned int irq_counter[16];
43
44static irqreturn_t deferred_fiq(int irq, void *dev_id)
45{
46 struct irq_desc *irq_desc;
47 struct irq_chip *irq_chip = NULL;
48 int gpio, irq_num, fiq_count;
49
50 irq_desc = irq_to_desc(IH_GPIO_BASE);
51 if (irq_desc)
52 irq_chip = irq_desc->chip;
53
54 /*
55 * For each handled GPIO interrupt, keep calling its interrupt handler
56 * until the IRQ counter catches the FIQ incremented interrupt counter.
57 */
58 for (gpio = AMS_DELTA_GPIO_PIN_KEYBRD_CLK;
59 gpio <= AMS_DELTA_GPIO_PIN_HOOK_SWITCH; gpio++) {
60 irq_num = gpio_to_irq(gpio);
61 fiq_count = fiq_buffer[FIQ_CNT_INT_00 + gpio];
62
63 while (irq_counter[gpio] < fiq_count) {
64 if (gpio != AMS_DELTA_GPIO_PIN_KEYBRD_CLK) {
65 /*
66 * It looks like handle_edge_irq() that
67 * OMAP GPIO edge interrupts default to,
68 * expects interrupt already unmasked.
69 */
70 if (irq_chip && irq_chip->unmask)
71 irq_chip->unmask(irq_num);
72 }
73 generic_handle_irq(irq_num);
74
75 irq_counter[gpio]++;
76 }
77 }
78 return IRQ_HANDLED;
79}
80
81void __init ams_delta_init_fiq(void)
82{
83 void *fiqhandler_start;
84 unsigned int fiqhandler_length;
85 struct pt_regs FIQ_regs;
86 unsigned long val, offset;
87 int i, retval;
88
89 fiqhandler_start = &qwerty_fiqin_start;
90 fiqhandler_length = &qwerty_fiqin_end - &qwerty_fiqin_start;
91 pr_info("Installing fiq handler from %p, length 0x%x\n",
92 fiqhandler_start, fiqhandler_length);
93
94 retval = claim_fiq(&fh);
95 if (retval) {
96 pr_err("ams_delta_init_fiq(): couldn't claim FIQ, ret=%d\n",
97 retval);
98 return;
99 }
100
101 retval = request_irq(INT_DEFERRED_FIQ, deferred_fiq,
102 IRQ_TYPE_EDGE_RISING, "deferred_fiq", 0);
103 if (retval < 0) {
104 pr_err("Failed to get deferred_fiq IRQ, ret=%d\n", retval);
105 release_fiq(&fh);
106 return;
107 }
108 /*
109 * Since no set_type() method is provided by OMAP irq chip,
110 * switch to edge triggered interrupt type manually.
111 */
112 offset = IRQ_ILR0_REG_OFFSET + INT_DEFERRED_FIQ * 0x4;
113 val = omap_readl(DEFERRED_FIQ_IH_BASE + offset) & ~(1 << 1);
114 omap_writel(val, DEFERRED_FIQ_IH_BASE + offset);
115
116 set_fiq_handler(fiqhandler_start, fiqhandler_length);
117
118 /*
119 * Initialise the buffer which is shared
120 * between FIQ mode and IRQ mode
121 */
122 fiq_buffer[FIQ_GPIO_INT_MASK] = 0;
123 fiq_buffer[FIQ_MASK] = 0;
124 fiq_buffer[FIQ_STATE] = 0;
125 fiq_buffer[FIQ_KEY] = 0;
126 fiq_buffer[FIQ_KEYS_CNT] = 0;
127 fiq_buffer[FIQ_KEYS_HICNT] = 0;
128 fiq_buffer[FIQ_TAIL_OFFSET] = 0;
129 fiq_buffer[FIQ_HEAD_OFFSET] = 0;
130 fiq_buffer[FIQ_BUF_LEN] = 256;
131 fiq_buffer[FIQ_MISSED_KEYS] = 0;
132 fiq_buffer[FIQ_BUFFER_START] =
133 (unsigned int) &fiq_buffer[FIQ_CIRC_BUFF];
134
135 for (i = FIQ_CNT_INT_00; i <= FIQ_CNT_INT_15; i++)
136 fiq_buffer[i] = 0;
137
138 /*
139 * FIQ mode r9 always points to the fiq_buffer, becauses the FIQ isr
140 * will run in an unpredictable context. The fiq_buffer is the FIQ isr's
141 * only means of communication with the IRQ level and other kernel
142 * context code.
143 */
144 FIQ_regs.ARM_r9 = (unsigned int)fiq_buffer;
145 set_fiq_regs(&FIQ_regs);
146
147 pr_info("request_fiq(): fiq_buffer = %p\n", fiq_buffer);
148
149 /*
150 * Redirect GPIO interrupts to FIQ
151 */
152 offset = IRQ_ILR0_REG_OFFSET + INT_GPIO_BANK1 * 0x4;
153 val = omap_readl(OMAP_IH1_BASE + offset) | 1;
154 omap_writel(val, OMAP_IH1_BASE + offset);
155}