xref: /netbsd-src/sys/arch/arm/imx/imxgpio.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: imxgpio.c,v 1.11 2021/08/07 16:18:44 thorpej Exp $ */
2c1719a03Sbsh 
3c1719a03Sbsh /*-
4cf660908Sad  * Copyright (c) 2007, 2020 The NetBSD Foundation, Inc.
5c1719a03Sbsh  * All rights reserved.
6c1719a03Sbsh  *
7c1719a03Sbsh  * This code is derived from software contributed to The NetBSD Foundation
8c1719a03Sbsh  * by Matt Thomas
9c1719a03Sbsh  *
10c1719a03Sbsh  * Redistribution and use in source and binary forms, with or without
11c1719a03Sbsh  * modification, are permitted provided that the following conditions
12c1719a03Sbsh  * are met:
13c1719a03Sbsh  * 1. Redistributions of source code must retain the above copyright
14c1719a03Sbsh  *    notice, this list of conditions and the following disclaimer.
15c1719a03Sbsh  * 2. Redistributions in binary form must reproduce the above copyright
16c1719a03Sbsh  *    notice, this list of conditions and the following disclaimer in the
17c1719a03Sbsh  *    documentation and/or other materials provided with the distribution.
18c1719a03Sbsh  *
19c1719a03Sbsh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20c1719a03Sbsh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21c1719a03Sbsh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22c1719a03Sbsh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23c1719a03Sbsh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24c1719a03Sbsh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25c1719a03Sbsh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26c1719a03Sbsh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27c1719a03Sbsh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28c1719a03Sbsh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29c1719a03Sbsh  * POSSIBILITY OF SUCH DAMAGE.
30c1719a03Sbsh  */
31c1719a03Sbsh #include <sys/cdefs.h>
32*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: imxgpio.c,v 1.11 2021/08/07 16:18:44 thorpej Exp $");
33c1719a03Sbsh 
34c1719a03Sbsh #define	_INTR_PRIVATE
35c1719a03Sbsh 
36c1719a03Sbsh #include "locators.h"
37c1719a03Sbsh #include "gpio.h"
38c1719a03Sbsh 
39c1719a03Sbsh #include <sys/param.h>
40c1719a03Sbsh #include <sys/evcnt.h>
41c1719a03Sbsh #include <sys/atomic.h>
42001dea06Shkenken #include <sys/bus.h>
43cf660908Sad #include <sys/cpu.h>
44cf660908Sad #include <sys/intr.h>
45c1719a03Sbsh 
46c1719a03Sbsh #include <arm/cpu.h>
47c1719a03Sbsh #include <arm/armreg.h>
48c1719a03Sbsh #include <arm/cpufunc.h>
49c1719a03Sbsh 
50c1719a03Sbsh #include <arm/imx/imxgpioreg.h>
51c1719a03Sbsh #include <arm/imx/imxgpiovar.h>
52c1719a03Sbsh 
53c1719a03Sbsh #if NGPIO > 0
54c1719a03Sbsh /* GPIO access from userland */
55c1719a03Sbsh #include <sys/gpio.h>
56c1719a03Sbsh #include <dev/gpio/gpiovar.h>
57c1719a03Sbsh #endif
58c1719a03Sbsh 
59a4103ccdSryo #define	MAX_NGROUP	8
60c1719a03Sbsh 
61001dea06Shkenken static void imxgpio_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
62001dea06Shkenken static void imxgpio_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
63001dea06Shkenken static int imxgpio_pic_find_pending_irqs(struct pic_softc *);
64001dea06Shkenken static void imxgpio_pic_establish_irq(struct pic_softc *, struct intrsource *);
65c1719a03Sbsh 
66001dea06Shkenken const struct pic_ops imxgpio_pic_ops = {
67001dea06Shkenken 	.pic_unblock_irqs = imxgpio_pic_unblock_irqs,
68001dea06Shkenken 	.pic_block_irqs = imxgpio_pic_block_irqs,
69001dea06Shkenken 	.pic_find_pending_irqs = imxgpio_pic_find_pending_irqs,
70001dea06Shkenken 	.pic_establish_irq = imxgpio_pic_establish_irq,
71c1719a03Sbsh 	.pic_source_name = NULL
72c1719a03Sbsh };
73c1719a03Sbsh 
74001dea06Shkenken static struct imxgpio_softc *imxgpio_handles[MAX_NGROUP];
75c1719a03Sbsh 
76001dea06Shkenken CFATTACH_DECL_NEW(imxgpio, sizeof(struct imxgpio_softc),
77001dea06Shkenken     imxgpio_match, imxgpio_attach, NULL, NULL);
78c1719a03Sbsh 
79c1719a03Sbsh #define	PIC_TO_SOFTC(pic)						      \
80001dea06Shkenken 	((struct imxgpio_softc *)((char *)(pic) -			      \
81001dea06Shkenken 	    offsetof(struct imxgpio_softc, gpio_pic)))
82c1719a03Sbsh 
83c1719a03Sbsh #define	GPIO_READ(gpio, reg)						      \
84c1719a03Sbsh 	bus_space_read_4((gpio)->gpio_memt, (gpio)->gpio_memh, (reg))
85c1719a03Sbsh #define	GPIO_WRITE(gpio, reg, val)					      \
86c1719a03Sbsh 	bus_space_write_4((gpio)->gpio_memt, (gpio)->gpio_memh, (reg), (val))
87c1719a03Sbsh 
88c1719a03Sbsh void
imxgpio_pic_unblock_irqs(struct pic_softc * pic,size_t irq_base,uint32_t irq_mask)89001dea06Shkenken imxgpio_pic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
90c1719a03Sbsh {
91001dea06Shkenken 	struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic);
92c1719a03Sbsh 	KASSERT(irq_base == 0);
93c1719a03Sbsh 
94c1719a03Sbsh 	gpio->gpio_enable_mask |= irq_mask;
95c1719a03Sbsh 
96c1719a03Sbsh 	GPIO_WRITE(gpio, GPIO_ISR, irq_mask);
97c1719a03Sbsh 	GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
98c1719a03Sbsh }
99c1719a03Sbsh 
100c1719a03Sbsh void
imxgpio_pic_block_irqs(struct pic_softc * pic,size_t irq_base,uint32_t irq_mask)101001dea06Shkenken imxgpio_pic_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
102c1719a03Sbsh {
103001dea06Shkenken 	struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic);
104c1719a03Sbsh 	KASSERT(irq_base == 0);
105c1719a03Sbsh 
106c1719a03Sbsh 	gpio->gpio_enable_mask &= ~irq_mask;
107c1719a03Sbsh 	GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
108c1719a03Sbsh }
109c1719a03Sbsh 
110c1719a03Sbsh int
imxgpio_pic_find_pending_irqs(struct pic_softc * pic)111001dea06Shkenken imxgpio_pic_find_pending_irqs(struct pic_softc *pic)
112c1719a03Sbsh {
113001dea06Shkenken 	struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic);
114c1719a03Sbsh 	uint32_t v;
115c1719a03Sbsh 	uint32_t pending;
116c1719a03Sbsh 
117c1719a03Sbsh 	v = GPIO_READ(gpio, GPIO_ISR);
118c1719a03Sbsh 	pending = (v & gpio->gpio_enable_mask);
119c1719a03Sbsh 	if (pending == 0)
120c1719a03Sbsh 		return 0;
121c1719a03Sbsh 
122c1719a03Sbsh 	/*
123c1719a03Sbsh 	 * Disable the pending interrupts.
124c1719a03Sbsh 	 */
125c1719a03Sbsh 	gpio->gpio_enable_mask &= ~pending;
126c1719a03Sbsh 	GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
127c1719a03Sbsh 
128c1719a03Sbsh 	/*
129c1719a03Sbsh 	 * If any of the sources are edge triggered, ack them now so
130c1719a03Sbsh 	 * we won't lose them.
131c1719a03Sbsh 	 */
132c1719a03Sbsh 	if (v & gpio->gpio_edge_mask)
133c1719a03Sbsh 		GPIO_WRITE(gpio, GPIO_ISR, v & gpio->gpio_edge_mask);
134c1719a03Sbsh 
135c1719a03Sbsh 	/*
136c1719a03Sbsh 	 * Now find all the pending bits and mark them as pending.
137c1719a03Sbsh 	 */
138c1719a03Sbsh 	do {
139c1719a03Sbsh 		int irq;
140c1719a03Sbsh 		KASSERT(pending != 0);
141c1719a03Sbsh 		irq = 31 - __builtin_clz(pending);
142c1719a03Sbsh 		pending &= ~__BIT(irq);
143ec32498dShkenken 
144ec32498dShkenken 		const struct intrsource *is = pic->pic_sources[irq];
145ec32498dShkenken 		if (is->is_type == IST_EDGE_BOTH) {
146ec32498dShkenken 			/*
147ec32498dShkenken 			 * for both edge
148ec32498dShkenken 			 */
149ec32498dShkenken 			uint32_t icr_reg = GPIO_ICR1 + ((is->is_irq & 0x10) >> 2);
150ec32498dShkenken 			v = GPIO_READ(gpio, icr_reg);
151ec32498dShkenken 			uint32_t icr_shift = (is->is_irq & 0x0f) << 1;
152ec32498dShkenken 			uint32_t mask = (3 << icr_shift);
153ec32498dShkenken 			int gtype = __SHIFTOUT(v, mask);
154ec32498dShkenken 			if (gtype == GPIO_ICR_EDGE_RISING)
155ec32498dShkenken 				gtype = GPIO_ICR_EDGE_FALLING;
156ec32498dShkenken 			else if (gtype == GPIO_ICR_EDGE_FALLING)
157ec32498dShkenken 				gtype = GPIO_ICR_EDGE_RISING;
158ec32498dShkenken 			v &= ~mask;
159ec32498dShkenken 			v |= __SHIFTIN(gtype, mask);
160ec32498dShkenken 			GPIO_WRITE(gpio, icr_reg, v);
161ec32498dShkenken 		}
162c1719a03Sbsh 		pic_mark_pending(&gpio->gpio_pic, irq);
163c1719a03Sbsh 	} while (pending != 0);
164c1719a03Sbsh 
165c1719a03Sbsh 	return 1;
166c1719a03Sbsh }
167c1719a03Sbsh 
168c1719a03Sbsh #define	GPIO_TYPEMAP \
169c1719a03Sbsh 	((GPIO_ICR_LEVEL_LOW << (2*IST_LEVEL_LOW)) | \
170c1719a03Sbsh 	 (GPIO_ICR_LEVEL_HIGH << (2*IST_LEVEL_HIGH)) | \
171c1719a03Sbsh 	 (GPIO_ICR_EDGE_RISING << (2*IST_EDGE_RISING)) | \
172ec32498dShkenken 	 (GPIO_ICR_EDGE_FALLING << (2*IST_EDGE_FALLING)) | \
173ec32498dShkenken 	 (GPIO_ICR_EDGE_RISING << (2*IST_EDGE_BOTH)))
174c1719a03Sbsh 
175c1719a03Sbsh void
imxgpio_pic_establish_irq(struct pic_softc * pic,struct intrsource * is)176001dea06Shkenken imxgpio_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
177c1719a03Sbsh {
178001dea06Shkenken 	struct imxgpio_softc * const gpio = PIC_TO_SOFTC(pic);
179c1719a03Sbsh 	KASSERT(is->is_irq < 32);
180c1719a03Sbsh 	uint32_t irq_mask = __BIT(is->is_irq);
181c1719a03Sbsh 	uint32_t v;
182c1719a03Sbsh 	unsigned int icr_shift, icr_reg;
183c1719a03Sbsh 	unsigned int gtype;
184c1719a03Sbsh 
185c1719a03Sbsh 	/*
186c1719a03Sbsh 	 * Make sure the irq isn't enabled and not asserting.
187c1719a03Sbsh 	 */
188c1719a03Sbsh 	gpio->gpio_enable_mask &= ~irq_mask;
189c1719a03Sbsh 	GPIO_WRITE(gpio, GPIO_ISR, irq_mask);
190c1719a03Sbsh 	GPIO_WRITE(gpio, GPIO_IMR, gpio->gpio_enable_mask);
191c1719a03Sbsh 	/*
192c1719a03Sbsh 	 * Convert the type to a gpio type and figure out which bits in what
193c1719a03Sbsh 	 * register we have to tweak.
194c1719a03Sbsh 	 */
195c1719a03Sbsh 	gtype = (GPIO_TYPEMAP >> (2 * is->is_type)) & 3;
196c1719a03Sbsh 	icr_shift = (is->is_irq & 0x0f) << 1;
197c1719a03Sbsh 	icr_reg = GPIO_ICR1 + ((is->is_irq & 0x10) >> 2);
198c1719a03Sbsh 
199c1719a03Sbsh 	/*
200c1719a03Sbsh 	 * Set the interrupt type.
201c1719a03Sbsh 	 */
202c1719a03Sbsh 	v = GPIO_READ(gpio, icr_reg);
203c1719a03Sbsh 	v &= ~(3 << icr_shift);
204c1719a03Sbsh 	v |= gtype << icr_shift;
205c1719a03Sbsh 	GPIO_WRITE(gpio, icr_reg, v);
206c1719a03Sbsh 
207c1719a03Sbsh 	/*
208c1719a03Sbsh 	 * Mark it as input.
209c1719a03Sbsh 	 */
210c1719a03Sbsh 	v = GPIO_READ(gpio, GPIO_DIR);
211c1719a03Sbsh 	v &= ~irq_mask;
212c1719a03Sbsh 	GPIO_WRITE(gpio, GPIO_DIR, v);
213c1719a03Sbsh 
214c1719a03Sbsh 	/*
215c1719a03Sbsh 	 * Now record the type of interrupt.
216c1719a03Sbsh 	 */
217c1719a03Sbsh 	if (gtype == GPIO_ICR_EDGE_RISING || gtype == GPIO_ICR_EDGE_FALLING) {
218c1719a03Sbsh 		gpio->gpio_edge_mask |= irq_mask;
219c1719a03Sbsh 		gpio->gpio_level_mask &= ~irq_mask;
220c1719a03Sbsh 	} else {
221c1719a03Sbsh 		gpio->gpio_edge_mask &= ~irq_mask;
222c1719a03Sbsh 		gpio->gpio_level_mask |= irq_mask;
223c1719a03Sbsh 	}
224c1719a03Sbsh }
225c1719a03Sbsh 
226c1719a03Sbsh #if NGPIO > 0
227c1719a03Sbsh 
228001dea06Shkenken int
imxgpio_pin_read(void * arg,int pin)229c1719a03Sbsh imxgpio_pin_read(void *arg, int pin)
230c1719a03Sbsh {
231001dea06Shkenken 	struct imxgpio_softc * const gpio = arg;
232001dea06Shkenken 	int val;
233c1719a03Sbsh 
234001dea06Shkenken 	val = __SHIFTOUT(GPIO_READ(gpio, GPIO_DR), __BIT(pin));
235001dea06Shkenken 
236001dea06Shkenken 	return val;
237c1719a03Sbsh }
238c1719a03Sbsh 
239001dea06Shkenken void
imxgpio_pin_write(void * arg,int pin,int value)240c1719a03Sbsh imxgpio_pin_write(void *arg, int pin, int value)
241c1719a03Sbsh {
242001dea06Shkenken 	struct imxgpio_softc * const gpio = arg;
243001dea06Shkenken 	uint32_t mask = __BIT(pin);
244001dea06Shkenken 	uint32_t old;
245001dea06Shkenken 	uint32_t new;
246001dea06Shkenken 
247001dea06Shkenken 	mutex_enter(&gpio->gpio_lock);
248c1719a03Sbsh 
249c1719a03Sbsh 	old = GPIO_READ(gpio, GPIO_DR);
250c1719a03Sbsh 	if (value)
251c1719a03Sbsh 		new = old | mask;
252c1719a03Sbsh 	else
253c1719a03Sbsh 		new = old & ~mask;
254c1719a03Sbsh 
255c1719a03Sbsh 	if (old != new)
256c1719a03Sbsh 		GPIO_WRITE(gpio, GPIO_DR, new);
257001dea06Shkenken 
258001dea06Shkenken 	mutex_exit(&gpio->gpio_lock);
259c1719a03Sbsh }
260c1719a03Sbsh 
261001dea06Shkenken void
imxgpio_pin_ctl(void * arg,int pin,int flags)262c1719a03Sbsh imxgpio_pin_ctl(void *arg, int pin, int flags)
263c1719a03Sbsh {
264001dea06Shkenken 	struct imxgpio_softc * const gpio = arg;
265001dea06Shkenken 	uint32_t mask = __BIT(pin);
266001dea06Shkenken 	uint32_t old;
267001dea06Shkenken 	uint32_t new;
268001dea06Shkenken 
269001dea06Shkenken 	mutex_enter(&gpio->gpio_lock);
270c1719a03Sbsh 
271c1719a03Sbsh 	old = GPIO_READ(gpio, GPIO_DIR);
272c1719a03Sbsh 	new = old;
273c1719a03Sbsh 	switch (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
274001dea06Shkenken 	case GPIO_PIN_INPUT:
275001dea06Shkenken 		new &= ~mask;
276001dea06Shkenken 		break;
277001dea06Shkenken 	case GPIO_PIN_OUTPUT:
278001dea06Shkenken 		new |= mask;
279001dea06Shkenken 		break;
280001dea06Shkenken 	default:
281001dea06Shkenken 		break;
282c1719a03Sbsh 	}
283001dea06Shkenken 
284c1719a03Sbsh 	if (old != new)
285c1719a03Sbsh 		GPIO_WRITE(gpio, GPIO_DIR, new);
286001dea06Shkenken 
287001dea06Shkenken 	mutex_exit(&gpio->gpio_lock);
288c1719a03Sbsh }
289c1719a03Sbsh 
290c1719a03Sbsh static void
imxgpio_attach_ports(struct imxgpio_softc * gpio)291af6f2f7bShkenken imxgpio_attach_ports(struct imxgpio_softc *gpio)
292c1719a03Sbsh {
293c1719a03Sbsh 	struct gpio_chipset_tag * const gp = &gpio->gpio_chipset;
294c1719a03Sbsh 	struct gpiobus_attach_args gba;
295af6f2f7bShkenken 	uint32_t dir;
296af6f2f7bShkenken 	u_int pin;
297c1719a03Sbsh 
298c1719a03Sbsh 	gp->gp_cookie = gpio;
299c1719a03Sbsh 	gp->gp_pin_read = imxgpio_pin_read;
300c1719a03Sbsh 	gp->gp_pin_write = imxgpio_pin_write;
301c1719a03Sbsh 	gp->gp_pin_ctl = imxgpio_pin_ctl;
302c1719a03Sbsh 
303c1719a03Sbsh 	dir = GPIO_READ(gpio, GPIO_DIR);
304af6f2f7bShkenken 	for (pin = 0; pin < __arraycount(gpio->gpio_pins); pin++) {
305af6f2f7bShkenken 		uint32_t mask = __BIT(pin);
306af6f2f7bShkenken 		gpio_pin_t *pins = &gpio->gpio_pins[pin];
307c1719a03Sbsh 		pins->pin_num = pin;
308c1719a03Sbsh 		if ((gpio->gpio_edge_mask | gpio->gpio_level_mask) & mask)
309c1719a03Sbsh 			pins->pin_caps = GPIO_PIN_INPUT;
310c1719a03Sbsh 		else
311c1719a03Sbsh 			pins->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
312c1719a03Sbsh 		pins->pin_flags =
313c1719a03Sbsh 		    (dir & mask) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
314af6f2f7bShkenken 		pins->pin_state = imxgpio_pin_read(gpio, pin);
315c1719a03Sbsh 	}
316c1719a03Sbsh 
317af6f2f7bShkenken 	memset(&gba, 0, sizeof(gba));
318af6f2f7bShkenken 	gba.gba_gc = gp;
319af6f2f7bShkenken 	gba.gba_pins = gpio->gpio_pins;
320af6f2f7bShkenken 	gba.gba_npins = __arraycount(gpio->gpio_pins);
321*c7fb772bSthorpej 	config_found(gpio->gpio_dev, &gba, gpiobus_print, CFARGS_NONE);
322c1719a03Sbsh }
323c1719a03Sbsh #endif /* NGPIO > 0 */
324c1719a03Sbsh 
325c1719a03Sbsh void
imxgpio_attach_common(device_t self)326001dea06Shkenken imxgpio_attach_common(device_t self)
327c1719a03Sbsh {
328001dea06Shkenken 	struct imxgpio_softc * const gpio = device_private(self);
329c1719a03Sbsh 
330c1719a03Sbsh 	gpio->gpio_dev = self;
331c1719a03Sbsh 
33291882526Sjmcneill 	if (gpio->gpio_irqbase == PIC_IRQBASE_ALLOC || gpio->gpio_irqbase > 0) {
333001dea06Shkenken 		gpio->gpio_pic.pic_ops = &imxgpio_pic_ops;
334cbab9cadSchs 		strlcpy(gpio->gpio_pic.pic_name, device_xname(self),
335c1719a03Sbsh 		    sizeof(gpio->gpio_pic.pic_name));
33691882526Sjmcneill 		gpio->gpio_pic.pic_maxsources = GPIO_NPINS;
337c1719a03Sbsh 
33891882526Sjmcneill 		gpio->gpio_irqbase = pic_add(&gpio->gpio_pic, gpio->gpio_irqbase);
33991882526Sjmcneill 
34091882526Sjmcneill 		aprint_normal_dev(gpio->gpio_dev, "interrupts %d..%d\n",
34191882526Sjmcneill 		    gpio->gpio_irqbase, gpio->gpio_irqbase + GPIO_NPINS - 1);
342c1719a03Sbsh 	}
343c1719a03Sbsh 
344001dea06Shkenken 	mutex_init(&gpio->gpio_lock, MUTEX_DEFAULT, IPL_VM);
345001dea06Shkenken 
34691882526Sjmcneill 	if (gpio->gpio_unit != -1) {
34791882526Sjmcneill 		KASSERT(gpio->gpio_unit < MAX_NGROUP);
348001dea06Shkenken 		imxgpio_handles[gpio->gpio_unit] = gpio;
34991882526Sjmcneill 	}
350c1719a03Sbsh 
351c1719a03Sbsh #if NGPIO > 0
352af6f2f7bShkenken 	imxgpio_attach_ports(gpio);
353c1719a03Sbsh #endif
354c1719a03Sbsh }
355c1719a03Sbsh 
356001dea06Shkenken /* in-kernel GPIO access utility functions */
357c1719a03Sbsh void
imxgpio_set_direction(u_int gpio,int dir)35891882526Sjmcneill imxgpio_set_direction(u_int gpio, int dir)
359c1719a03Sbsh {
360c1719a03Sbsh 	int index = gpio / GPIO_NPINS;
361001dea06Shkenken 	int pin = gpio % GPIO_NPINS;
362c1719a03Sbsh 
363c1719a03Sbsh 	KDASSERT(index < imxgpio_ngroups);
364001dea06Shkenken 	KASSERT(imxgpio_handles[index] != NULL);
365c1719a03Sbsh 
366001dea06Shkenken 	imxgpio_pin_ctl(imxgpio_handles[index], pin, dir);
367c1719a03Sbsh }
368c1719a03Sbsh 
369c1719a03Sbsh void
imxgpio_data_write(u_int gpio,u_int value)37091882526Sjmcneill imxgpio_data_write(u_int gpio, u_int value)
371c1719a03Sbsh {
372c1719a03Sbsh 	int index = gpio / GPIO_NPINS;
373001dea06Shkenken 	int pin = gpio % GPIO_NPINS;
374c1719a03Sbsh 
375c1719a03Sbsh 	KDASSERT(index < imxgpio_ngroups);
376001dea06Shkenken 	KASSERT(imxgpio_handles[index] != NULL);
377c1719a03Sbsh 
378001dea06Shkenken 	imxgpio_pin_write(imxgpio_handles[index], pin, value);
379c1719a03Sbsh }
380c1719a03Sbsh 
381c1719a03Sbsh bool
imxgpio_data_read(u_int gpio)38291882526Sjmcneill imxgpio_data_read(u_int gpio)
383c1719a03Sbsh {
384c1719a03Sbsh 	int index = gpio / GPIO_NPINS;
385001dea06Shkenken 	int pin = gpio % GPIO_NPINS;
386c1719a03Sbsh 
387c1719a03Sbsh 	KDASSERT(index < imxgpio_ngroups);
388001dea06Shkenken 	KASSERT(imxgpio_handles[index] != NULL);
389c1719a03Sbsh 
390001dea06Shkenken 	return imxgpio_pin_read(imxgpio_handles[index], pin) ? true : false;
391c1719a03Sbsh }
392001dea06Shkenken 
393