imxgpio.c revision 1.1 1 /* $NetBSD: imxgpio.c,v 1.1 2010/11/30 13:05:27 bsh Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: imxgpio.c,v 1.1 2010/11/30 13:05:27 bsh Exp $");
33
34 #define _INTR_PRIVATE
35
36 #include "locators.h"
37 #include "gpio.h"
38
39 #include <sys/param.h>
40 #include <sys/evcnt.h>
41 #include <sys/atomic.h>
42
43 #include <uvm/uvm_extern.h>
44
45 #include <machine/intr.h>
46
47 #include <arm/cpu.h>
48 #include <arm/armreg.h>
49 #include <arm/cpufunc.h>
50
51 #include <machine/bus.h>
52
53 #include <arm/imx/imx31reg.h>
54 #include <arm/imx/imx31var.h>
55 #include <arm/imx/imxgpioreg.h>
56 #include <arm/pic/picvar.h>
57
58 #include <arm/imx/imxgpioreg.h>
59 #include <arm/imx/imxgpiovar.h>
60
61 #if NGPIO > 0
62 /* GPIO access from userland */
63 #include <sys/gpio.h>
64 #include <dev/gpio/gpiovar.h>
65 #endif
66
67 #define MAX_NGROUP 4
68
69 static void gpio_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
70 static void gpio_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
71 static int gpio_pic_find_pending_irqs(struct pic_softc *);
72 static void gpio_pic_establish_irq(struct pic_softc *, struct intrsource *);
73
74 const struct pic_ops gpio_pic_ops = {
75 .pic_unblock_irqs = gpio_pic_unblock_irqs,
76 .pic_block_irqs = gpio_pic_block_irqs,
77 .pic_find_pending_irqs = gpio_pic_find_pending_irqs,
78 .pic_establish_irq = gpio_pic_establish_irq,
79 .pic_source_name = NULL
80 };
81
82 struct gpio_softc {
83 device_t gpio_dev;
84 struct pic_softc gpio_pic;
85 struct intrsource *gpio_is;
86 bus_space_tag_t gpio_memt;
87 bus_space_handle_t gpio_memh;
88 uint32_t gpio_enable_mask;
89 uint32_t gpio_edge_mask;
90 uint32_t gpio_level_mask;
91 #if NGPIO > 0
92 struct gpio_chipset_tag gpio_chipset;
93 gpio_pin_t gpio_pins[32];
94 #endif
95 };
96
97 static struct {
98 bus_space_tag_t iot;
99 struct {
100 bus_space_handle_t ioh;
101 struct gpio_softc *softc;
102 } unit[MAX_NGROUP];
103 } gpio_handles;
104
105 extern struct cfdriver imxgpio_cd;
106
107 CFATTACH_DECL_NEW(imxgpio,
108 sizeof(struct gpio_softc),
109 imxgpio_match, imxgpio_attach,
110 NULL, NULL);
111
112
113 #define PIC_TO_SOFTC(pic) \
114 ((struct gpio_softc *)((char *)(pic) - \
115 offsetof(struct gpio_softc, gpio_pic)))
116
117 #define GPIO_READ(gpio, reg) \
118 bus_space_read_4((gpio)->gpio_memt, (gpio)->gpio_memh, (reg))
119 #define GPIO_WRITE(gpio, reg, val) \
120 bus_space_write_4((gpio)->gpio_memt, (gpio)->gpio_memh, (reg), (val))
121
122 void
123 gpio_pic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
124 {
125 struct gpio_softc * const gpio = PIC_TO_SOFTC(pic);
126 KASSERT(irq_base == 0);
127
128 gpio->gpio_enable_mask |= irq_mask;
129
130 GPIO_WRITE(gpio, GPIO_ISR, irq_mask);
131 GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
132 }
133
134 void
135 gpio_pic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
136 {
137 struct gpio_softc * const gpio = PIC_TO_SOFTC(pic);
138 KASSERT(irq_base == 0);
139
140 gpio->gpio_enable_mask &= ~irq_mask;
141 GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
142 }
143
144 int
145 gpio_pic_find_pending_irqs(struct pic_softc *pic)
146 {
147 struct gpio_softc * const gpio = PIC_TO_SOFTC(pic);
148 uint32_t v;
149 uint32_t pending;
150
151 v = GPIO_READ(gpio, GPIO_ISR);
152 pending = (v & gpio->gpio_enable_mask);
153 if (pending == 0)
154 return 0;
155
156 /*
157 * Disable the pending interrupts.
158 */
159 gpio->gpio_enable_mask &= ~pending;
160 GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
161
162 /*
163 * If any of the sources are edge triggered, ack them now so
164 * we won't lose them.
165 */
166 if (v & gpio->gpio_edge_mask)
167 GPIO_WRITE(gpio, GPIO_ISR, v & gpio->gpio_edge_mask);
168
169 /*
170 * Now find all the pending bits and mark them as pending.
171 */
172 do {
173 int irq;
174 KASSERT(pending != 0);
175 irq = 31 - __builtin_clz(pending);
176 pending &= ~__BIT(irq);
177 pic_mark_pending(&gpio->gpio_pic, irq);
178 } while (pending != 0);
179
180 return 1;
181 }
182
183 #define GPIO_TYPEMAP \
184 ((GPIO_ICR_LEVEL_LOW << (2*IST_LEVEL_LOW)) | \
185 (GPIO_ICR_LEVEL_HIGH << (2*IST_LEVEL_HIGH)) | \
186 (GPIO_ICR_EDGE_RISING << (2*IST_EDGE_RISING)) | \
187 (GPIO_ICR_EDGE_FALLING << (2*IST_EDGE_FALLING)))
188
189 void
190 gpio_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
191 {
192 struct gpio_softc * const gpio = PIC_TO_SOFTC(pic);
193 KASSERT(is->is_irq < 32);
194 uint32_t irq_mask = __BIT(is->is_irq);
195 uint32_t v;
196 unsigned int icr_shift, icr_reg;
197 unsigned int gtype;
198
199 /*
200 * Make sure the irq isn't enabled and not asserting.
201 */
202 gpio->gpio_enable_mask &= ~irq_mask;
203 GPIO_WRITE(gpio, GPIO_ISR, irq_mask);
204 GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
205 /*
206 * Convert the type to a gpio type and figure out which bits in what
207 * register we have to tweak.
208 */
209 gtype = (GPIO_TYPEMAP >> (2 * is->is_type)) & 3;
210 icr_shift = (is->is_irq & 0x0f) << 1;
211 icr_reg = GPIO_ICR1 + ((is->is_irq & 0x10) >> 2);
212
213 /*
214 * Set the interrupt type.
215 */
216 v = GPIO_READ(gpio, icr_reg);
217 v &= ~(3 << icr_shift);
218 v |= gtype << icr_shift;
219 GPIO_WRITE(gpio, icr_reg, v);
220
221 /*
222 * Mark it as input.
223 */
224 v = GPIO_READ(gpio, GPIO_DIR);
225 v &= ~irq_mask;
226 GPIO_WRITE(gpio, GPIO_DIR, v);
227
228 /*
229 * Now record the type of interrupt.
230 */
231 if (gtype == GPIO_ICR_EDGE_RISING || gtype == GPIO_ICR_EDGE_FALLING) {
232 gpio->gpio_edge_mask |= irq_mask;
233 gpio->gpio_level_mask &= ~irq_mask;
234 } else {
235 gpio->gpio_edge_mask &= ~irq_mask;
236 gpio->gpio_level_mask |= irq_mask;
237 }
238 }
239
240 #if NGPIO > 0
241
242 static int
243 imxgpio_pin_read(void *arg, int pin)
244 {
245 struct gpio_softc * const gpio = arg;
246
247 return (GPIO_READ(gpio, GPIO_DR) >> pin) & 1;
248 }
249
250 static void
251 imxgpio_pin_write(void *arg, int pin, int value)
252 {
253 struct gpio_softc * const gpio = arg;
254 uint32_t mask = 1 << pin;
255 uint32_t old, new;
256
257 old = GPIO_READ(gpio, GPIO_DR);
258 if (value)
259 new = old | mask;
260 else
261 new = old & ~mask;
262
263 if (old != new)
264 GPIO_WRITE(gpio, GPIO_DR, new);
265 }
266
267 static void
268 imxgpio_pin_ctl(void *arg, int pin, int flags)
269 {
270 struct gpio_softc * const gpio = arg;
271 uint32_t mask = 1 << pin;
272 uint32_t old, new;
273
274 old = GPIO_READ(gpio, GPIO_DIR);
275 new = old;
276 switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
277 case GPIO_PIN_INPUT: new &= ~mask; break;
278 case GPIO_PIN_OUTPUT: new |= mask; break;
279 default: return;
280 }
281 if (old != new)
282 GPIO_WRITE(gpio, GPIO_DIR, new);
283 }
284
285 static void
286 gpio_defer(device_t self)
287 {
288 struct gpio_softc * const gpio = (void *) self;
289 struct gpio_chipset_tag * const gp = &gpio->gpio_chipset;
290 struct gpiobus_attach_args gba;
291 gpio_pin_t *pins;
292 uint32_t mask, dir, value;
293 int pin;
294
295 gp->gp_cookie = gpio;
296 gp->gp_pin_read = imxgpio_pin_read;
297 gp->gp_pin_write = imxgpio_pin_write;
298 gp->gp_pin_ctl = imxgpio_pin_ctl;
299
300 gba.gba_gc = gp;
301 gba.gba_pins = gpio->gpio_pins;
302 gba.gba_npins = __arraycount(gpio->gpio_pins);
303
304 dir = GPIO_READ(gpio, GPIO_DIR);
305 value = GPIO_READ(gpio, GPIO_DR);
306 for (pin = 0, mask = 1, pins = gpio->gpio_pins;
307 pin < 32; pin++, mask <<= 1, pins++) {
308 pins->pin_num = pin;
309 if ((gpio->gpio_edge_mask|gpio->gpio_level_mask) & mask)
310 pins->pin_caps = GPIO_PIN_INPUT;
311 else
312 pins->pin_caps = GPIO_PIN_INPUT|GPIO_PIN_OUTPUT;
313 pins->pin_flags =
314 (dir & mask) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
315 pins->pin_state =
316 (value & mask) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
317 }
318
319 config_found_ia(self, "gpiobus", &gba, gpiobus_print);
320 }
321 #endif /* NGPIO > 0 */
322
323 void
324 imxgpio_attach_common(device_t self, bus_space_tag_t iot,
325 bus_space_handle_t ioh, int index, int intr, int irqbase)
326 {
327 struct gpio_softc * const gpio = device_private(self);
328
329 gpio->gpio_dev = self;
330 gpio->gpio_memt = iot;
331 gpio->gpio_memh = ioh;
332
333 if (irqbase > 0) {
334 gpio->gpio_pic.pic_ops = &gpio_pic_ops;
335 strlcpy(gpio->gpio_pic.pic_name, self->dv_xname,
336 sizeof(gpio->gpio_pic.pic_name));
337 gpio->gpio_pic.pic_maxsources = 32;
338
339 pic_add(&gpio->gpio_pic, irqbase);
340
341 aprint_normal(": interrupts %d..%d",
342 irqbase, irqbase + GPIO_NPINS - 1);
343
344 gpio->gpio_is = intr_establish(intr,
345 IPL_NET, IST_LEVEL, pic_handle_intr, &gpio->gpio_pic);
346 KASSERT( gpio->gpio_is != NULL );
347 }
348 aprint_normal("\n");
349
350
351 gpio_handles.iot = iot;
352 gpio_handles.unit[index].softc = gpio;
353 gpio_handles.unit[index].ioh = ioh;
354
355 #if NGPIO > 0
356 config_interrupts(self, gpio_defer);
357 #endif
358 }
359
360 #define GPIO_GROUP_READ(index,offset) \
361 bus_space_read_4(gpio_handles.iot, gpio_handles.unit[index].ioh, \
362 (offset))
363 #define GPIO_GROUP_WRITE(index,offset,value) \
364 bus_space_write_4(gpio_handles.iot, gpio_handles.unit[index].ioh, \
365 (offset), (value))
366
367 void
368 gpio_set_direction(u_int gpio, u_int dir)
369 {
370 int index = gpio / GPIO_NPINS;
371 int bit = gpio % GPIO_NPINS;
372 uint32_t reg;
373
374 KDASSERT(index < imxgpio_ngroups);
375
376 /* XXX lock */
377
378
379 reg = GPIO_GROUP_READ(index, GPIO_DIR);
380 if (dir == GPIO_DIR_OUT)
381 reg |= __BIT(bit);
382 else
383 reg &= ~__BIT(bit);
384 GPIO_GROUP_WRITE(index, GPIO_DIR, reg);
385
386 /* XXX unlock */
387 }
388
389
390 void
391 gpio_data_write(u_int gpio, u_int value)
392 {
393 int index = gpio / GPIO_NPINS;
394 int bit = gpio % GPIO_NPINS;
395 uint32_t reg;
396
397 KDASSERT(index < imxgpio_ngroups);
398
399 /* XXX lock */
400 reg = GPIO_GROUP_READ(index, GPIO_DR);
401 if (value)
402 reg |= __BIT(bit);
403 else
404 reg &= ~__BIT(bit);
405 GPIO_GROUP_WRITE(index, GPIO_DR, reg);
406
407 /* XXX unlock */
408 }
409
410 bool
411 gpio_data_read(u_int gpio)
412 {
413 int index = gpio / GPIO_NPINS;
414 int bit = gpio % GPIO_NPINS;
415 uint32_t reg;
416
417 KDASSERT(index < imxgpio_ngroups);
418
419 reg = GPIO_GROUP_READ(index, GPIO_DR);
420
421 return reg & __BIT(bit) ? true : false;
422 }
423