imx31_gpio.c revision 1.1.2.1 1 1.1.2.1 matt /*-
2 1.1.2.1 matt * Copyright (c) 2007 The NetBSD Foundation, Inc.
3 1.1.2.1 matt * All rights reserved.
4 1.1.2.1 matt *
5 1.1.2.1 matt * This code is derived from software contributed to The NetBSD Foundation
6 1.1.2.1 matt * by Matt Thomas
7 1.1.2.1 matt *
8 1.1.2.1 matt * Redistribution and use in source and binary forms, with or without
9 1.1.2.1 matt * modification, are permitted provided that the following conditions
10 1.1.2.1 matt * are met:
11 1.1.2.1 matt * 1. Redistributions of source code must retain the above copyright
12 1.1.2.1 matt * notice, this list of conditions and the following disclaimer.
13 1.1.2.1 matt * 2. Redistributions in binary form must reproduce the above copyright
14 1.1.2.1 matt * notice, this list of conditions and the following disclaimer in the
15 1.1.2.1 matt * documentation and/or other materials provided with the distribution.
16 1.1.2.1 matt * 3. All advertising materials mentioning features or use of this software
17 1.1.2.1 matt * must display the following acknowledgement:
18 1.1.2.1 matt * This product includes software developed by the NetBSD
19 1.1.2.1 matt * Foundation, Inc. and its contributors.
20 1.1.2.1 matt * 4. Neither the name of The NetBSD Foundation nor the names of its
21 1.1.2.1 matt * contributors may be used to endorse or promote products derived
22 1.1.2.1 matt * from this software without specific prior written permission.
23 1.1.2.1 matt *
24 1.1.2.1 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 1.1.2.1 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 1.1.2.1 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 1.1.2.1 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 1.1.2.1 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 1.1.2.1 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 1.1.2.1 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 1.1.2.1 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 1.1.2.1 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 1.1.2.1 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 1.1.2.1 matt * POSSIBILITY OF SUCH DAMAGE.
35 1.1.2.1 matt */
36 1.1.2.1 matt #include <sys/cdefs.h>
37 1.1.2.1 matt __KERNEL_RCSID(0, "$NetBSD: imx31_gpio.c,v 1.1.2.1 2007/08/29 05:24:23 matt Exp $");
38 1.1.2.1 matt
39 1.1.2.1 matt #define _INTR_PRIVATE
40 1.1.2.1 matt
41 1.1.2.1 matt #include <sys/param.h>
42 1.1.2.1 matt #include <sys/evcnt.h>
43 1.1.2.1 matt
44 1.1.2.1 matt #include <uvm/uvm_extern.h>
45 1.1.2.1 matt
46 1.1.2.1 matt #include <machine/intr.h>
47 1.1.2.1 matt
48 1.1.2.1 matt #include <arm/cpu.h>
49 1.1.2.1 matt #include <arm/armreg.h>
50 1.1.2.1 matt #include <arm/cpufunc.h>
51 1.1.2.1 matt
52 1.1.2.1 matt #include <machine/atomic.h>
53 1.1.2.1 matt #include <machine/bus.h>
54 1.1.2.1 matt
55 1.1.2.1 matt #include <arm/imx/imx31reg.h>
56 1.1.2.1 matt
57 1.1.2.1 matt static void gpio_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
58 1.1.2.1 matt static void gpio_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
59 1.1.2.1 matt static int gpio_pic_find_pending_irqs(struct pic_softc *);
60 1.1.2.1 matt static void gpio_pic_establish_irq(struct pic_softc *, int, int, int);
61 1.1.2.1 matt
62 1.1.2.1 matt const struct pic_ops gpio_pic_ops = {
63 1.1.2.1 matt .pic_block_irqs = gpio_pic_block_irqs,
64 1.1.2.1 matt .pic_unblock_irqs = gpio_pic_unblock_irqs,
65 1.1.2.1 matt .pic_find_pending_irqs = gpio_find_pending_irqs,
66 1.1.2.1 matt .pic_establish_irq = establish_irq,
67 1.1.2.1 matt };
68 1.1.2.1 matt
69 1.1.2.1 matt struct gpio_pic_softc {
70 1.1.2.1 matt struct pic_softc gpic_pic;
71 1.1.2.1 matt bus_space_tag_t gpic_memt;
72 1.1.2.1 matt bus_space_handle_t gpic_memh;
73 1.1.2.1 matt uint32_t gpio_enable_mask;
74 1.1.2.1 matt uint32_t gpio_edge_mask;
75 1.1.2.1 matt uint32_t gpio_level_mask;
76 1.1.2.1 matt };
77 1.1.2.1 matt
78 1.1.2.1 matt void
79 1.1.2.1 matt gpio_pic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
80 1.1.2.1 matt {
81 1.1.2.1 matt struct gpic_softc * const gpic = pic
82 1.1.2.1 matt KASSERT(irq_base == 0);
83 1.1.2.1 matt gpic->gpic_enable_mask |= irq_mask;
84 1.1.2.1 matt /*
85 1.1.2.1 matt * If this a level source, ack it now. If it's still asserted
86 1.1.2.1 matt * it'll come back.
87 1.1.2.1 matt */
88 1.1.2.1 matt if (irq_mask & gpic->gpic_level_mask)
89 1.1.2.1 matt GPIO_WRITE(gpic, GPIO_ISR, irq_mask);
90 1.1.2.1 matt GPIO_WRITE(gpic, GPIO_IMR, gpic->gpic_enable_mask);
91 1.1.2.1 matt }
92 1.1.2.1 matt
93 1.1.2.1 matt void
94 1.1.2.1 matt gpio_pic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
95 1.1.2.1 matt {
96 1.1.2.1 matt KASSERT(irq_base == 0);
97 1.1.2.1 matt gpic->gpic_enable_mask &= ~irq_mask;
98 1.1.2.1 matt GPIO_WRITE(gpic, GPIO_IMR, gpic->gpic_enable_mask);
99 1.1.2.1 matt }
100 1.1.2.1 matt
101 1.1.2.1 matt int
102 1.1.2.1 matt gpio_pic_find_pending_irqs(struct pic_softc *pic)
103 1.1.2.1 matt {
104 1.1.2.1 matt struct gpio_pic_softc * const gpic = pic;
105 1.1.2.1 matt uint32_t v;
106 1.1.2.1 matt uint32_t pending;
107 1.1.2.1 matt
108 1.1.2.1 matt v = GPIO_READ(gpic, GPIO_ISR);
109 1.1.2.1 matt pending = (v & gpic->gpic_enabled);
110 1.1.2.1 matt if (pending == 0)
111 1.1.2.1 matt return 0;
112 1.1.2.1 matt
113 1.1.2.1 matt /*
114 1.1.2.1 matt * Disable the pending interrupts.
115 1.1.2.1 matt */
116 1.1.2.1 matt gpic->gpic_enable_mask &= ~pending;
117 1.1.2.1 matt GPIO_WRITE(gpic, GPIO_IMR, gpic->gpic_enable_mask);
118 1.1.2.1 matt
119 1.1.2.1 matt /*
120 1.1.2.1 matt * If any of the sources are edge triggered, ack them now so
121 1.1.2.1 matt * we won't lose them.
122 1.1.2.1 matt */
123 1.1.2.1 matt if (v & gpic->gpic_edge_mask)
124 1.1.2.1 matt GPIO_WRITE(gpic, GPIO_ISR, v & gpic->gpic_edge_mask);
125 1.1.2.1 matt
126 1.1.2.1 matt /*
127 1.1.2.1 matt * Now find all the pending bits and mark them as pending.
128 1.1.2.1 matt */
129 1.1.2.1 matt do {
130 1.1.2.1 matt KASSERT(pending != 0)
131 1.1.2.1 matt irq = 31 - __builtin_clz(pending);
132 1.1.2.1 matt pending &= ~(1 << irq);
133 1.1.2.1 matt pic_mark_pending(gpic->gpic_pic, irq)
134 1.1.2.1 matt } while (pending != 0);
135 1.1.2.1 matt
136 1.1.2.1 matt return 1;
137 1.1.2.1 matt }
138 1.1.2.1 matt
139 1.1.2.1 matt #define GPIO_TYPEMAP \
140 1.1.2.1 matt ((GPIO_TYPE_LEVEL_LOW << (2*IST_LEVEL_LOW)) | \
141 1.1.2.1 matt (GPIO_TYPE_LEVEL_HIGH << (2*IST_LEVEL_HIGH)) | \
142 1.1.2.1 matt (GPIO_TYPE_EDGE_RISING << (2*IST_EDGE_RISING)) | \
143 1.1.2.1 matt (GPIO_TYPE_EDGE_FAILING << (2*IST_EDGE_FAILING)))
144 1.1.2.1 matt
145 1.1.2.1 matt void
146 1.1.2.1 matt gpio_pic_establish_irq(struct pic_softc *pic, int irq, int ipl, int type)
147 1.1.2.1 matt {
148 1.1.2.1 matt struct gpio_pic_softc * const gpic = pic;
149 1.1.2.1 matt KASSERT(irq < 32);
150 1.1.2.1 matt uint32_t irq_mask = BIT(irq);
151 1.1.2.1 matt
152 1.1.2.1 matt /*
153 1.1.2.1 matt * Make sure the irq isn't enabled and not asserting.
154 1.1.2.1 matt */
155 1.1.2.1 matt gpic->gpic_enable_mask &= ~irq_mask;
156 1.1.2.1 matt GPIO_WRITE(gpic, GPIO_IMR, gpic->gpic_enable_mask);
157 1.1.2.1 matt GPIO_WRITE(gpic, GPIO_ISR, irq_mask);
158 1.1.2.1 matt
159 1.1.2.1 matt /*
160 1.1.2.1 matt * Convert the type to a gpio type and figure out which bits in what
161 1.1.2.1 matt * register we have to tweak.
162 1.1.2.1 matt */
163 1.1.2.1 matt gtype = (GPIO_TYPEMASK >> (2 * type)) & 3;
164 1.1.2.1 matt icr_shift = (irq & 0x0f) << 1;
165 1.1.2.1 matt icr_reg = GPIO_ICR + ((irq & 0x10) >> 2);
166 1.1.2.1 matt
167 1.1.2.1 matt /*
168 1.1.2.1 matt * Set the interrupt type.
169 1.1.2.1 matt */
170 1.1.2.1 matt v = GPIO_READ(gpic, icr_reg);
171 1.1.2.1 matt v &= ~(3 << icr_shift);
172 1.1.2.1 matt v |= gtype << icr_shift;
173 1.1.2.1 matt GPIO_WRITE(gpic, icr_reg, v);
174 1.1.2.1 matt
175 1.1.2.1 matt /*
176 1.1.2.1 matt * Mark it as input.
177 1.1.2.1 matt */
178 1.1.2.1 matt v = GPIO_READ(gpic, GPIO_DIR);
179 1.1.2.1 matt v &= ~irq_mask;
180 1.1.2.1 matt GPIO_WRITE(gpic, GPIO_DIR, v);
181 1.1.2.1 matt
182 1.1.2.1 matt /*
183 1.1.2.1 matt * Now record the type of interrupt.
184 1.1.2.1 matt */
185 1.1.2.1 matt if (gtype == GPIO_TYPE_EDGE_RISING || gtype == GPIO_TYPE_EDGE_FAILING) {
186 1.1.2.1 matt gpic->gpic_edge_mask |= irq_mask;
187 1.1.2.1 matt gpic->gpic_level_mask &= ~irq_mask;
188 1.1.2.1 matt } else {
189 1.1.2.1 matt gpic->gpic_edge_mask &= ~irq_mask;
190 1.1.2.1 matt gpic->gpic_level_mask |= irq_mask;
191 1.1.2.1 matt }
192 1.1.2.1 matt }
193 1.1.2.1 matt
194 1.1.2.1 matt static int gpio_match(struct device *, struct cfdata *, void *);
195 1.1.2.1 matt static int gpio_attach(struct device *, struct device *, void *);
196 1.1.2.1 matt
197 1.1.2.1 matt int
198 1.1.2.1 matt gpio_match(struct device *parent, struct cfdata *cfdata, void *aux)
199 1.1.2.1 matt {
200 1.1.2.1 matt struct mainbus_attach_args *mba = aux;
201 1.1.2.1 matt bus_space_handle_t memh;
202 1.1.2.1 matt int error;
203 1.1.2.1 matt
204 1.1.2.1 matt if (mba->mba_addr != GPIO1_BASE
205 1.1.2.1 matt && mba->mba_addr != GPIO2_BASE
206 1.1.2.1 matt && mba->mba_addr != GPIO3_BASE)
207 1.1.2.1 matt return 0;
208 1.1.2.1 matt
209 1.1.2.1 matt if (mba->mba_size == MAINBUSCF_SIZE_DEFAULT)
210 1.1.2.1 matt return 0;
211 1.1.2.1 matt
212 1.1.2.1 matt error = bus_space_map(mba->mba_memt, mba->mba_addr, mba->mba_size,
213 1.1.2.1 matt 0, &memh);
214 1.1.2.1 matt if (error)
215 1.1.2.1 matt return 0;
216 1.1.2.1 matt
217 1.1.2.1 matt bus_space_unmap(mba->mba_memt, memh);
218 1.1.2.1 matt return 1;
219 1.1.2.1 matt }
220 1.1.2.1 matt
221 1.1.2.1 matt int
222 1.1.2.1 matt gpio_attach(struct device *parent, struct device *self, void *aux)
223 1.1.2.1 matt {
224 1.1.2.1 matt struct mainbus_attach_args * const mba = aux;
225 1.1.2.1 matt struct gpio_softc * const gsc = (void *) self;
226 1.1.2.1 matt struct gpio_pic * const gpic = &gsc->gsc_gpic;
227 1.1.2.1 matt int error;
228 1.1.2.1 matt
229 1.1.2.1 matt gsc->gsc_memt = mba->mba_memt;
230 1.1.2.1 matt error = bus_space_map(mba->mba_memt, mba->mba_addr, mba->mba_size,
231 1.1.2.1 matt 0, &gsc->gsc_memh);
232 1.1.2.1 matt
233 1.1.2.1 matt if (error) {
234 1.1.2.1 matt aprint_error(": failed to map register %#x@%#x: %d\n",
235 1.1.2.1 matt mba->mba_size, mba->mba_addr, error);
236 1.1.2.1 matt return;
237 1.1.2.1 matt }
238 1.1.2.1 matt
239 1.1.2.1 matt if (mba->mba_irqbase != MAINBUSCF_IRQBASE_DEFAULT) {
240 1.1.2.1 matt gpic->gpic_pic.pic_ops = &gpio_pic_ops;
241 1.1.2.1 matt strlcpy(gpic->gpic_pic.pic_name, self->dv_xname,
242 1.1.2.1 matt sizeof(gpic->gpic_pic.pic_name));
243 1.1.2.1 matt gpic->gpic_pic.pic_maxsources = 32;
244 1.1.2.1 matt pic_add(&gpic->gpic_pic, mba->mba_irqbase);
245 1.1.2.1 matt }
246 1.1.2.1 matt
247 1.1.2.1 matt }
248