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