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