summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gpio-imx31.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/gpio-imx31.c')
-rw-r--r--firmware/target/arm/imx31/gpio-imx31.c198
1 files changed, 105 insertions, 93 deletions
diff --git a/firmware/target/arm/imx31/gpio-imx31.c b/firmware/target/arm/imx31/gpio-imx31.c
index e368d1ae07..7a7363be88 100644
--- a/firmware/target/arm/imx31/gpio-imx31.c
+++ b/firmware/target/arm/imx31/gpio-imx31.c
@@ -23,7 +23,8 @@
23#include "config.h" 23#include "config.h"
24#include "system.h" 24#include "system.h"
25#include "avic-imx31.h" 25#include "avic-imx31.h"
26#include "gpio-imx31.h" 26#define DEFINE_GPIO_VECTOR_TABLE
27#include "gpio-target.h"
27 28
28/* UIE vector found in avic-imx31.c */ 29/* UIE vector found in avic-imx31.c */
29extern void UIE_VECTOR(void); 30extern void UIE_VECTOR(void);
@@ -31,101 +32,91 @@ extern void UIE_VECTOR(void);
31/* Event lists are allocated for the specific target */ 32/* Event lists are allocated for the specific target */
32#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) 33#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
33static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void); 34static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void);
34extern const struct gpio_event gpio1_events[GPIO1_NUM_EVENTS];
35#endif 35#endif
36 36
37#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) 37#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
38static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void); 38static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void);
39extern const struct gpio_event gpio2_events[GPIO2_NUM_EVENTS];
40#endif 39#endif
41 40
42#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) 41#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
43static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void); 42static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void);
44extern const struct gpio_event gpio3_events[GPIO3_NUM_EVENTS];
45#endif 43#endif
46 44
47#define DR (0x00 / sizeof (unsigned long)) /* 00h */ 45static struct gpio_module_desc
48#define GDIR (0x04 / sizeof (unsigned long)) /* 04h */
49#define PSR (0x08 / sizeof (unsigned long)) /* 08h */
50#define ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */
51#define IMR (0x14 / sizeof (unsigned long)) /* 14h */
52#define ISR (0x18 / sizeof (unsigned long))
53
54static const struct gpio_module_desc
55{ 46{
56 volatile unsigned long * const base; /* Module base address */ 47 volatile unsigned long * const base; /* Module base address */
57 void (* const handler)(void); /* Interrupt function */ 48 void (* const handler)(void); /* Interrupt function */
58 const struct gpio_event * const events; /* Event handler list */ 49 const struct gpio_event *events; /* Event handler list */
50 unsigned long enabled; /* Enabled event mask */
59 const uint8_t ints; /* AVIC int number */ 51 const uint8_t ints; /* AVIC int number */
60 const uint8_t int_priority; /* AVIC int priority */ 52 const uint8_t int_priority; /* AVIC int priority */
61 const uint8_t count; /* Number of events */ 53 uint8_t count; /* Number of events */
62} gpio_descs[GPIO_NUM_GPIO] = 54} * const gpio_descs[] =
63{ 55{
64#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) 56#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
65 { 57 [GPIO1_NUM] = &(struct gpio_module_desc) {
66 .base = (unsigned long *)GPIO1_BASE_ADDR, 58 .base = (unsigned long *)GPIO1_BASE_ADDR,
67 .ints = INT_GPIO1, 59 .ints = INT_GPIO1,
68 .handler = GPIO1_HANDLER, 60 .handler = GPIO1_HANDLER,
69 .events = gpio1_events,
70 .count = GPIO1_NUM_EVENTS,
71 .int_priority = GPIO1_INT_PRIO 61 .int_priority = GPIO1_INT_PRIO
72 }, 62 },
73#endif 63#endif
74#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) 64#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
75 { 65 [GPIO2_NUM] = &(struct gpio_module_desc) {
76 .base = (unsigned long *)GPIO2_BASE_ADDR, 66 .base = (unsigned long *)GPIO2_BASE_ADDR,
77 .ints = INT_GPIO2, 67 .ints = INT_GPIO2,
78 .handler = GPIO2_HANDLER, 68 .handler = GPIO2_HANDLER,
79 .events = gpio2_events,
80 .count = GPIO2_NUM_EVENTS,
81 .int_priority = GPIO2_INT_PRIO 69 .int_priority = GPIO2_INT_PRIO
82 }, 70 },
83#endif 71#endif
84#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) 72#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
85 { 73 [GPIO3_NUM] = &(struct gpio_module_desc) {
86 .base = (unsigned long *)GPIO3_BASE_ADDR, 74 .base = (unsigned long *)GPIO3_BASE_ADDR,
87 .ints = INT_GPIO3, 75 .ints = INT_GPIO3,
88 .handler = GPIO3_HANDLER, 76 .handler = GPIO3_HANDLER,
89 .events = gpio3_events,
90 .count = GPIO3_NUM_EVENTS,
91 .int_priority = GPIO3_INT_PRIO, 77 .int_priority = GPIO3_INT_PRIO,
92 }, 78 },
93#endif 79#endif
94}; 80};
95 81
82#define GPIO_MODULE_CNT ARRAYLEN(gpio_descs)
83
84static const struct gpio_event * event_from_id(
85 const struct gpio_module_desc *desc, enum gpio_id id)
86{
87 const struct gpio_event *events = desc->events;
88 for (unsigned int i = 0; i < desc->count; i++)
89 {
90 if (events[i].id == id)
91 return &events[i];
92 }
93
94 return NULL;
95}
96
96static void gpio_call_events(enum gpio_module_number gpio) 97static void gpio_call_events(enum gpio_module_number gpio)
97{ 98{
98 const struct gpio_module_desc * const desc = &gpio_descs[gpio]; 99 const struct gpio_module_desc * const desc = gpio_descs[gpio];
99 volatile unsigned long * const base = desc->base; 100 volatile unsigned long * const base = desc->base;
100 const struct gpio_event * event, *event_last;
101 101
102 event = desc->events; 102 /* Send only events that are not masked */
103 event_last = event + desc->count; 103 unsigned long pnd = base[GPIO_ISR] & base[GPIO_IMR];
104 104
105 /* Intersect pending and unmasked bits */ 105 if (pnd & ~desc->enabled)
106 unsigned long pnd = base[ISR] & base[IMR]; 106 UIE_VECTOR(); /* One or more aren't handled properly */
107 107
108 /* Call each event handler in order */ 108 const struct gpio_event *event = desc->events;
109 /* .count is surely expected to be > 0 */
110 do
111 {
112 unsigned long mask = event->mask;
113 109
110 while (pnd)
111 {
112 unsigned long mask = 1ul << (event->id % 32);
114 if (pnd & mask) 113 if (pnd & mask)
115 { 114 {
116 event->callback(); 115 event->callback();
117 pnd &= ~mask; 116 pnd &= ~mask;
118 } 117 }
119 118
120 if (pnd == 0) 119 event++;
121 break; /* Teminate early if nothing more to service */
122 }
123 while (++event < event_last);
124
125 if (pnd != 0)
126 {
127 /* One or more weren't handled */
128 UIE_VECTOR();
129 } 120 }
130} 121}
131 122
@@ -152,69 +143,90 @@ static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void)
152 143
153void INIT_ATTR gpio_init(void) 144void INIT_ATTR gpio_init(void)
154{ 145{
155 /* Mask-out GPIO interrupts - enable what's wanted later */ 146 for (unsigned int mod = 0; mod < GPIO_MODULE_CNT; mod++)
156 int i; 147 {
157 for (i = 0; i < GPIO_NUM_GPIO; i++) 148 struct gpio_module_desc * const desc = gpio_descs[mod];
158 gpio_descs[i].base[IMR] = 0; 149 if (!desc)
150 continue;
151
152 /* Parse the event table per module. First contiguous run seen for a
153 * module is used. */
154 const struct gpio_event *event = gpio_event_vector_tbl;
155 for (unsigned int i = 0; i < gpio_event_vector_tbl_len; i++, event++)
156 {
157 if (event->id / 32 == mod)
158 {
159 desc->events = event;
160 while (++desc->count < 32 && (++event)->id / 32 == mod);
161 break;
162 }
163 }
164
165 /* Mask-out GPIO interrupts - enable what's wanted later */
166 desc->base[GPIO_IMR] = 0;
167 }
159} 168}
160 169
161bool gpio_enable_event(enum gpio_event_ids id) 170bool gpio_enable_event(enum gpio_id id, bool enable)
162{ 171{
163 const struct gpio_module_desc * const desc = &gpio_descs[id >> 5]; 172 unsigned int mod = id / 32;
164 const struct gpio_event * const event = &desc->events[id & 31];
165 volatile unsigned long * const base = desc->base;
166 volatile unsigned long *icr;
167 unsigned long mask, line;
168 unsigned long imr;
169 int shift;
170 173
171 int oldlevel = disable_irq_save(); 174 struct gpio_module_desc * const desc = gpio_descs[mod];
172 175
173 imr = base[IMR]; 176 if (mod >= GPIO_MODULE_CNT || desc == NULL)
177 return false;
174 178
175 if (imr == 0) 179 const struct gpio_event * const event = event_from_id(desc, id);
176 { 180 if (!event)
177 /* First enabled interrupt for this GPIO */ 181 return false;
178 avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
179 desc->handler);
180 }
181
182 /* Set the line sense */
183 line = find_first_set_bit(event->mask);
184 icr = &base[ICR + (line >> 4)];
185 shift = 2*(line & 15);
186 mask = GPIO_SENSE_CONFIG_MASK << shift;
187 182
188 *icr = (*icr & ~mask) | ((event->sense << shift) & mask); 183 volatile unsigned long * const base = desc->base;
184 unsigned long num = id % 32;
185 unsigned long mask = 1ul << num;
189 186
190 /* Unmask the line */ 187 unsigned long cpsr = disable_irq_save();
191 base[IMR] = imr | event->mask;
192 188
193 restore_irq(oldlevel); 189 unsigned long imr = base[GPIO_IMR];
194 190
195 return true; 191 if (enable)
196} 192 {
193 if (desc->enabled == 0)
194 {
195 /* First enabled interrupt for this GPIO */
196 avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
197 desc->handler);
198 }
197 199
198void gpio_disable_event(enum gpio_event_ids id) 200 /* Set the line sense */
199{ 201 if (event->sense == GPIO_SENSE_EDGE_SEL)
200 const struct gpio_module_desc * const desc = &gpio_descs[id >> 5]; 202 {
201 const struct gpio_event * const event = &desc->events[id & 31]; 203 /* Interrupt configuration register is ignored */
202 volatile unsigned long * const base = desc->base; 204 base[GPIO_EDGE_SEL] |= mask;
203 unsigned long imr; 205 }
206 else
207 {
208 volatile unsigned long *icrp = &base[GPIO_ICR + num / 16];
209 unsigned int shift = 2*(num % 16);
210 bitmod32(icrp, event->sense << shift, 0x3 << shift);
211 base[GPIO_EDGE_SEL] &= ~mask;
212 }
204 213
205 int oldlevel = disable_irq_save(); 214 /* Unmask the line */
215 desc->enabled |= mask;
216 imr |= mask;
217 }
218 else
219 {
220 imr &= ~mask;
221 desc->enabled &= ~mask;
206 222
207 /* Remove bit from mask */ 223 if (desc->enabled == 0)
208 imr = base[IMR] & ~event->mask; 224 avic_disable_int(desc->ints); /* No events remain enabled */
225 }
209 226
210 /* Mask the line */ 227 base[GPIO_IMR] = imr;
211 base[IMR] = imr;
212 228
213 if (imr == 0) 229 restore_irq(cpsr);
214 {
215 /* No events remain enabled */
216 avic_disable_int(desc->ints);
217 }
218 230
219 restore_irq(oldlevel); 231 return true;
220} 232}