1 /* $OpenBSD: imxgpio.c,v 1.3 2018/08/08 11:06:47 patrick Exp $ */ 2 /* 3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> 4 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/queue.h> 22 #include <sys/device.h> 23 #include <sys/malloc.h> 24 #include <sys/evcount.h> 25 26 #include <machine/bus.h> 27 #include <machine/fdt.h> 28 #include <machine/intr.h> 29 30 #include <dev/ofw/openfirm.h> 31 #include <dev/ofw/ofw_gpio.h> 32 #include <dev/ofw/fdt.h> 33 34 /* iMX6 registers */ 35 #define GPIO_DR 0x00 36 #define GPIO_GDIR 0x04 37 #define GPIO_PSR 0x08 38 #define GPIO_ICR1 0x0C 39 #define GPIO_ICR2 0x10 40 #define GPIO_IMR 0x14 41 #define GPIO_ISR 0x18 42 #define GPIO_EDGE_SEL 0x1C 43 44 #define GPIO_NUM_PINS 32 45 46 struct intrhand { 47 int (*ih_func)(void *); /* handler */ 48 void *ih_arg; /* arg for handler */ 49 int ih_ipl; /* IPL_* */ 50 int ih_irq; /* IRQ number */ 51 int ih_level; /* GPIO level */ 52 struct evcount ih_count; 53 char *ih_name; 54 void *ih_sc; 55 }; 56 57 struct imxgpio_softc { 58 struct device sc_dev; 59 bus_space_tag_t sc_iot; 60 bus_space_handle_t sc_ioh; 61 int sc_node; 62 63 void *sc_ih_h; 64 void *sc_ih_l; 65 int sc_ipl; 66 int sc_irq; 67 struct intrhand *sc_handlers[GPIO_NUM_PINS]; 68 struct interrupt_controller sc_ic; 69 70 struct gpio_controller sc_gc; 71 }; 72 73 int imxgpio_match(struct device *, void *, void *); 74 void imxgpio_attach(struct device *, struct device *, void *); 75 76 void imxgpio_config_pin(void *, uint32_t *, int); 77 int imxgpio_get_pin(void *, uint32_t *); 78 void imxgpio_set_pin(void *, uint32_t *, int); 79 80 int imxgpio_intr(void *); 81 void *imxgpio_intr_establish(void *, int *, int, int (*)(void *), 82 void *, char *); 83 void imxgpio_intr_disestablish(void *); 84 void imxgpio_recalc_ipl(struct imxgpio_softc *); 85 void imxgpio_intr_enable(void *); 86 void imxgpio_intr_disable(void *); 87 88 89 struct cfattach imxgpio_ca = { 90 sizeof (struct imxgpio_softc), imxgpio_match, imxgpio_attach 91 }; 92 93 struct cfdriver imxgpio_cd = { 94 NULL, "imxgpio", DV_DULL 95 }; 96 97 int 98 imxgpio_match(struct device *parent, void *match, void *aux) 99 { 100 struct fdt_attach_args *faa = aux; 101 102 return OF_is_compatible(faa->fa_node, "fsl,imx35-gpio"); 103 } 104 105 void 106 imxgpio_attach(struct device *parent, struct device *self, void *aux) 107 { 108 struct imxgpio_softc *sc = (struct imxgpio_softc *)self; 109 struct fdt_attach_args *faa = aux; 110 111 if (faa->fa_nreg < 1) 112 return; 113 114 sc->sc_node = faa->fa_node; 115 sc->sc_iot = faa->fa_iot; 116 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 117 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 118 panic("imxgpio_attach: bus_space_map failed!"); 119 120 sc->sc_gc.gc_node = faa->fa_node; 121 sc->sc_gc.gc_cookie = sc; 122 sc->sc_gc.gc_config_pin = imxgpio_config_pin; 123 sc->sc_gc.gc_get_pin = imxgpio_get_pin; 124 sc->sc_gc.gc_set_pin = imxgpio_set_pin; 125 gpio_controller_register(&sc->sc_gc); 126 127 sc->sc_ipl = IPL_NONE; 128 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, 0); 129 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR, ~0); 130 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_EDGE_SEL, 0); 131 132 sc->sc_ic.ic_node = faa->fa_node; 133 sc->sc_ic.ic_cookie = sc; 134 sc->sc_ic.ic_establish = imxgpio_intr_establish; 135 sc->sc_ic.ic_disestablish = imxgpio_intr_disestablish; 136 sc->sc_ic.ic_enable = imxgpio_intr_enable; 137 sc->sc_ic.ic_disable = imxgpio_intr_disable; 138 fdt_intr_register(&sc->sc_ic); 139 140 printf("\n"); 141 142 /* XXX - SYSCONFIG */ 143 /* XXX - CTRL */ 144 /* XXX - DEBOUNCE */ 145 } 146 147 void 148 imxgpio_config_pin(void *cookie, uint32_t *cells, int config) 149 { 150 struct imxgpio_softc *sc = cookie; 151 uint32_t pin = cells[0]; 152 uint32_t val; 153 154 if (pin >= GPIO_NUM_PINS) 155 return; 156 157 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR); 158 if (config & GPIO_CONFIG_OUTPUT) 159 val |= 1 << pin; 160 else 161 val &= ~(1 << pin); 162 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR, val); 163 } 164 165 int 166 imxgpio_get_pin(void *cookie, uint32_t *cells) 167 { 168 struct imxgpio_softc *sc = cookie; 169 uint32_t pin = cells[0]; 170 uint32_t flags = cells[1]; 171 uint32_t reg; 172 int val; 173 174 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR); 175 reg &= (1 << pin); 176 val = (reg >> pin) & 1; 177 if (flags & GPIO_ACTIVE_LOW) 178 val = !val; 179 return val; 180 } 181 182 void 183 imxgpio_set_pin(void *cookie, uint32_t *cells, int val) 184 { 185 struct imxgpio_softc *sc = cookie; 186 uint32_t pin = cells[0]; 187 uint32_t flags = cells[1]; 188 uint32_t reg; 189 190 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR); 191 if (flags & GPIO_ACTIVE_LOW) 192 val = !val; 193 if (val) 194 reg |= (1 << pin); 195 else 196 reg &= ~(1 << pin); 197 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR, reg); 198 } 199 200 int 201 imxgpio_intr(void *cookie) 202 { 203 struct imxgpio_softc *sc = (struct imxgpio_softc *)cookie; 204 struct intrhand *ih; 205 uint32_t status, pending, mask; 206 int pin, s; 207 208 status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR); 209 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR); 210 211 status &= mask; 212 pending = status; 213 214 while (pending) { 215 pin = ffs(pending) - 1; 216 217 if ((ih = sc->sc_handlers[pin]) != NULL) { 218 s = splraise(ih->ih_ipl); 219 if (ih->ih_func(ih->ih_arg)) 220 ih->ih_count.ec_count++; 221 splx(s); 222 } 223 224 pending &= ~(1 << pin); 225 } 226 227 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR, status); 228 229 return 1; 230 } 231 232 void * 233 imxgpio_intr_establish(void *cookie, int *cells, int ipl, 234 int (*func)(void *), void *arg, char *name) 235 { 236 struct imxgpio_softc *sc = (struct imxgpio_softc *)cookie; 237 struct intrhand *ih; 238 int s, val, reg, shift; 239 int irqno = cells[0]; 240 int level = cells[1]; 241 242 if (irqno < 0 || irqno >= GPIO_NUM_PINS) 243 panic("%s: bogus irqnumber %d: %s", __func__, 244 irqno, name); 245 246 if (sc->sc_handlers[irqno] != NULL) 247 panic("%s: irqnumber %d reused: %s", __func__, 248 irqno, name); 249 250 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); 251 ih->ih_func = func; 252 ih->ih_arg = arg; 253 ih->ih_ipl = ipl; 254 ih->ih_irq = irqno; 255 ih->ih_name = name; 256 ih->ih_level = level; 257 ih->ih_sc = sc; 258 259 s = splhigh(); 260 261 sc->sc_handlers[irqno] = ih; 262 263 if (name != NULL) 264 evcount_attach(&ih->ih_count, name, &ih->ih_irq); 265 266 #ifdef DEBUG_INTC 267 printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl, 268 ih->ih_name); 269 #endif 270 271 imxgpio_recalc_ipl(sc); 272 273 switch (level) { 274 case 1: /* rising */ 275 val = 2; 276 break; 277 case 2: /* falling */ 278 val = 3; 279 break; 280 case 4: /* high */ 281 val = 1; 282 break; 283 case 8: /* low */ 284 val = 0; 285 break; 286 default: 287 panic("%s: unsupported trigger type", __func__); 288 } 289 290 if (irqno < 16) { 291 reg = GPIO_ICR1; 292 shift = irqno << 1; 293 } else { 294 reg = GPIO_ICR2; 295 shift = (irqno - 16) << 1; 296 } 297 298 bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, 299 bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) & ~(0x3 << shift)); 300 bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, 301 bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) | val << shift); 302 303 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, 304 bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR) | 1 << irqno); 305 306 splx(s); 307 return (ih); 308 } 309 310 void 311 imxgpio_intr_disestablish(void *cookie) 312 { 313 struct intrhand *ih = cookie; 314 struct imxgpio_softc *sc = ih->ih_sc; 315 uint32_t mask; 316 int s; 317 318 s = splhigh(); 319 320 #ifdef DEBUG_INTC 321 printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl, 322 ih->ih_name); 323 #endif 324 325 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR); 326 mask &= ~(1 << ih->ih_irq); 327 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask); 328 329 sc->sc_handlers[ih->ih_irq] = NULL; 330 if (ih->ih_name != NULL) 331 evcount_detach(&ih->ih_count); 332 free(ih, M_DEVBUF, sizeof(*ih)); 333 334 imxgpio_recalc_ipl(sc); 335 336 splx(s); 337 } 338 339 void 340 imxgpio_recalc_ipl(struct imxgpio_softc *sc) 341 { 342 struct intrhand *ih; 343 int pin; 344 int max = IPL_NONE; 345 int min = IPL_HIGH; 346 347 for (pin = 0; pin < GPIO_NUM_PINS; pin++) { 348 ih = sc->sc_handlers[pin]; 349 if (ih == NULL) 350 continue; 351 352 if (ih->ih_ipl > max) 353 max = ih->ih_ipl; 354 355 if (ih->ih_ipl < min) 356 min = ih->ih_ipl; 357 } 358 359 if (max == IPL_NONE) 360 min = IPL_NONE; 361 362 if (sc->sc_ipl != max) { 363 sc->sc_ipl = max; 364 365 if (sc->sc_ih_l != NULL) 366 fdt_intr_disestablish(sc->sc_ih_l); 367 368 if (sc->sc_ih_h != NULL) 369 fdt_intr_disestablish(sc->sc_ih_h); 370 371 if (sc->sc_ipl != IPL_NONE) { 372 sc->sc_ih_l = fdt_intr_establish_idx(sc->sc_node, 0, 373 sc->sc_ipl, imxgpio_intr, sc, sc->sc_dev.dv_xname); 374 sc->sc_ih_h = fdt_intr_establish_idx(sc->sc_node, 1, 375 sc->sc_ipl, imxgpio_intr, sc, sc->sc_dev.dv_xname); 376 } 377 } 378 } 379 380 void 381 imxgpio_intr_enable(void *cookie) 382 { 383 struct intrhand *ih = cookie; 384 struct imxgpio_softc *sc = ih->ih_sc; 385 uint32_t mask; 386 int s; 387 388 s = splhigh(); 389 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR); 390 mask |= (1 << ih->ih_irq); 391 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask); 392 splx(s); 393 } 394 395 void 396 imxgpio_intr_disable(void *cookie) 397 { 398 struct intrhand *ih = cookie; 399 struct imxgpio_softc *sc = ih->ih_sc; 400 uint32_t mask; 401 int s; 402 403 s = splhigh(); 404 mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR); 405 mask &= ~(1 << ih->ih_irq); 406 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask); 407 splx(s); 408 } 409