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