xref: /netbsd-src/sys/arch/arm/imx/imxgpio.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /*	$NetBSD: imxgpio.c,v 1.2 2011/07/01 20:27:50 dyoung 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.2 2011/07/01 20:27:50 dyoung 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 <sys/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