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