diff options
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c')
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c | 207 |
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 */ | ||
27 | extern void UIE_VECTOR(void); | ||
28 | |||
29 | /* Event lists are allocated for the specific target */ | ||
30 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | ||
31 | static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void); | ||
32 | extern const struct gpio_event_list gpio1_event_list; | ||
33 | #endif | ||
34 | |||
35 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | ||
36 | static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void); | ||
37 | extern const struct gpio_event_list gpio2_event_list; | ||
38 | #endif | ||
39 | |||
40 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | ||
41 | static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void); | ||
42 | extern const struct gpio_event_list gpio3_event_list; | ||
43 | #endif | ||
44 | |||
45 | static 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 | |||
76 | static 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) | ||
104 | static __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) | ||
111 | static __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) | ||
118 | static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void) | ||
119 | { | ||
120 | gpio_call_events(GPIO3_NUM); | ||
121 | } | ||
122 | #endif | ||
123 | |||
124 | void 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 | |||
143 | bool 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 | |||
182 | void 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 | } | ||