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