summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-04-12 16:56:45 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-04-12 16:56:45 +0000
commita7af9e4a7f25f5a32306c74e95a677e6c85f399e (patch)
tree5df60e8382b69cf943840852269ea9387d42ea46 /firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c
parentddfd787c54d78104dac4ed144ff6cb6df8617a0e (diff)
downloadrockbox-a7af9e4a7f25f5a32306c74e95a677e6c85f399e.tar.gz
rockbox-a7af9e4a7f25f5a32306c74e95a677e6c85f399e.zip
Add GPIO manager. Get the PMIC interrupt handling working (along with power button and HP detect). Add some reg field defined instead of using raw numbers. Add PMIC info to debug ports screen. Refine PMIC driver ops a little bit.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17086 a1c6a512-1295-4272-9138-f99709370657
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}