summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c
new file mode 100644
index 0000000000..a7427f16c0
--- /dev/null
+++ b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c
@@ -0,0 +1,207 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2008 by Michael Sevakis
11 *
12 * IMX31 GPIO event manager
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "system.h"
23#include "avic-imx31.h"
24#include "gpio-imx31.h"
25
26/* UIE vector found in avic-imx31.c */
27extern void UIE_VECTOR(void);
28
29/* Event lists are allocated for the specific target */
30#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
31static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void);
32extern const struct gpio_event_list gpio1_event_list;
33#endif
34
35#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
36static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void);
37extern const struct gpio_event_list gpio2_event_list;
38#endif
39
40#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
41static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void);
42extern const struct gpio_event_list gpio3_event_list;
43#endif
44
45static struct gpio_module_descriptor
46{
47 volatile unsigned long *base; /* Module base address */
48 enum IMX31_INT_LIST ints; /* AVIC int number */
49 void (*handler)(void); /* Interrupt function */
50 const struct gpio_event_list *list; /* Event handler list */
51} gpio_descs[GPIO_NUM_GPIO] =
52{
53#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
54 {
55 .base = (unsigned long *)GPIO1_BASE_ADDR,
56 .ints = GPIO1,
57 .handler = GPIO1_HANDLER,
58 },
59#endif
60#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
61 {
62 .base = (unsigned long *)GPIO2_BASE_ADDR,
63 .ints = GPIO2,
64 .handler = GPIO2_HANDLER,
65 },
66#endif
67#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
68 {
69 .base = (unsigned long *)GPIO3_BASE_ADDR,
70 .ints = GPIO3,
71 .handler = GPIO3_HANDLER,
72 },
73#endif
74};
75
76static void gpio_call_events(enum gpio_module_number gpio)
77{
78 const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
79 const struct gpio_event_list * const list = desc->list;
80 volatile unsigned long * const base = desc->base;
81 unsigned i;
82
83 /* Intersect pending and unmasked bits */
84 unsigned long pending = base[GPIO_ISR_I] & base[GPIO_IMR_I];
85
86 /* Call each event handler in order */
87 for (i = 0; i < list->count; i++)
88 {
89 const struct gpio_event * const event = &list->events[i];
90 unsigned long bit = 1ul << event->line;
91
92 if ((pending & bit) && event->callback())
93 pending &= ~bit;
94 }
95
96 if (pending != 0)
97 {
98 /* Wasn't handled */
99 UIE_VECTOR();
100 }
101}
102
103#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
104static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void)
105{
106 gpio_call_events(GPIO1_NUM);
107}
108#endif
109
110#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
111static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void)
112{
113 gpio_call_events(GPIO2_NUM);
114}
115#endif
116
117#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
118static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void)
119{
120 gpio_call_events(GPIO3_NUM);
121}
122#endif
123
124void gpio_init(void)
125{
126 /* Mask-out GPIO interrupts - enable what's wanted later */
127 GPIO1_IMR = 0;
128 GPIO2_IMR = 0;
129 GPIO3_IMR = 0;
130
131 /* Init the externally-defined event lists for each port */
132#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
133 gpio_descs[GPIO1_NUM].list = &gpio1_event_list;
134#endif
135#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
136 gpio_descs[GPIO2_NUM].list = &gpio2_event_list;
137#endif
138#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
139 gpio_descs[GPIO3_NUM].list = &gpio3_event_list;
140#endif
141}
142
143bool gpio_enable_event(enum gpio_module_number gpio, unsigned id)
144{
145 const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
146 const struct gpio_event * const event = &desc->list->events[id];
147 volatile unsigned long * const base = desc->base;
148 volatile unsigned long * icr;
149 unsigned long mask;
150 unsigned long imr;
151 int shift;
152
153 if (id >= desc->list->count)
154 return false;
155
156 int oldlevel = disable_irq_save();
157
158 imr = base[GPIO_IMR_I];
159
160 if (imr == 0)
161 {
162 /* First enabled interrupt for this GPIO */
163 avic_enable_int(desc->ints, IRQ, desc->list->priority,
164 desc->handler);
165 }
166
167 /* Set the line sense */
168 icr = &base[GPIO_ICR1_I] + event->line / 16;
169 shift = 2*(event->line % 16);
170 mask = GPIO_SENSE_CONFIG_MASK << shift;
171
172 *icr = (*icr & ~mask) | ((event->sense << shift) & mask);
173
174 /* Unmask the line */
175 base[GPIO_IMR_I] = imr | (1ul << event->line);
176
177 restore_irq(oldlevel);
178
179 return true;
180}
181
182void gpio_disable_event(enum gpio_module_number gpio, unsigned id)
183{
184 const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
185 const struct gpio_event * const event = &desc->list->events[id];
186 volatile unsigned long * const base = desc->base;
187 unsigned long imr;
188
189 if (id >= desc->list->count)
190 return;
191
192 int oldlevel = disable_irq_save();
193
194 /* Remove bit from mask */
195 imr = base[GPIO_IMR_I] & ~(1ul << event->line);
196
197 /* Mask the line */
198 base[GPIO_IMR_I] = imr;
199
200 if (imr == 0)
201 {
202 /* No events remain enabled */
203 avic_disable_int(desc->ints);
204 }
205
206 restore_irq(oldlevel);
207}