1 /* 2 * Copyright (c) 2016 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Imre Vadász <imre@vdsz.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * Intel SoC gpio driver. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/module.h> 42 #include <sys/errno.h> 43 #include <sys/lock.h> 44 #include <sys/bus.h> 45 46 #include <sys/rman.h> 47 48 #include "opt_acpi.h" 49 #include "acpi.h" 50 #include <dev/acpica/acpivar.h> 51 52 #include <bus/pci/pcivar.h> 53 54 #include "gpio_intel_var.h" 55 56 #include "gpio_if.h" 57 58 static int gpio_intel_probe(device_t dev); 59 static int gpio_intel_attach(device_t dev); 60 static int gpio_intel_detach(device_t dev); 61 static int gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger, 62 int polarity, int termination, void **cookiep); 63 static void gpio_intel_setup_intr(device_t dev, void *cookie, void *arg, 64 driver_intr_t *handler); 65 static void gpio_intel_teardown_intr(device_t dev, void *cookie); 66 static void gpio_intel_free_intr(device_t dev, void *cookie); 67 static int gpio_intel_alloc_io_pin(device_t dev, u_int pin, int flags, 68 void **cookiep); 69 static void gpio_intel_release_io_pin(device_t dev, void *cookie); 70 static int gpio_intel_read_pin(device_t dev, void *cookie); 71 static void gpio_intel_write_pin(device_t dev, void *cookie, int value); 72 73 static void gpio_intel_intr(void *arg); 74 static int gpio_intel_pin_exists(struct gpio_intel_softc *sc, 75 uint16_t pin); 76 77 static char *cherryview_ids[] = { "INT33FF", NULL }; 78 79 static int 80 gpio_intel_probe(device_t dev) 81 { 82 83 if (acpi_disabled("gpio_intel") || 84 ACPI_ID_PROBE(device_get_parent(dev), dev, cherryview_ids) == NULL) 85 return (ENXIO); 86 87 device_set_desc(dev, "Intel Cherry Trail GPIO Controller"); 88 89 return (BUS_PROBE_DEFAULT); 90 } 91 92 static int 93 gpio_intel_attach(device_t dev) 94 { 95 struct gpio_intel_softc *sc = device_get_softc(dev); 96 int error, i, rid; 97 98 lockinit(&sc->lk, "gpio_intel", 0, LK_CANRECURSE); 99 100 sc->dev = dev; 101 102 if (ACPI_ID_PROBE(device_get_parent(dev), dev, cherryview_ids) 103 != NULL) { 104 error = gpio_cherryview_matchuid(sc); 105 if (error) { 106 error = ENXIO; 107 goto err; 108 } 109 } else { 110 error = ENXIO; 111 goto err; 112 } 113 114 for (i = 0; i < NELEM(sc->intrmaps); i++) { 115 sc->intrmaps[i].pin = -1; 116 } 117 for (i = 0; i < NELEM(sc->iomaps); i++) { 118 sc->iomaps[i].pin = -1; 119 } 120 121 rid = 0; 122 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 123 &rid, RF_ACTIVE); 124 if (sc->mem_res == NULL) { 125 device_printf(dev, "unable to map registers"); 126 error = ENXIO; 127 goto err; 128 } 129 rid = 0; 130 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 131 &rid, RF_ACTIVE); 132 if (sc->irq_res == NULL) { 133 device_printf(dev, "unable to map interrupt"); 134 error = ENXIO; 135 goto err; 136 } 137 138 lockmgr(&sc->lk, LK_EXCLUSIVE); 139 /* Activate the interrupt */ 140 error = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE, 141 gpio_intel_intr, sc, &sc->intrhand, NULL); 142 if (error) 143 device_printf(dev, "Can't setup IRQ\n"); 144 145 /* power up the controller */ 146 pci_set_powerstate(dev, PCI_POWERSTATE_D0); 147 148 sc->fns->init(sc); 149 lockmgr(&sc->lk, LK_RELEASE); 150 151 device_add_child(dev, "gpio_acpi", -1); 152 bus_generic_attach(dev); 153 154 return (0); 155 156 err: 157 if (sc->irq_res) { 158 bus_release_resource(dev, SYS_RES_IRQ, 159 rman_get_rid(sc->irq_res), sc->irq_res); 160 sc->irq_res = NULL; 161 } 162 if (sc->mem_res) { 163 bus_release_resource(dev, SYS_RES_MEMORY, 164 rman_get_rid(sc->mem_res), sc->mem_res); 165 sc->mem_res = NULL; 166 } 167 return (error); 168 } 169 170 static int 171 gpio_intel_detach(device_t dev) 172 { 173 struct gpio_intel_softc *sc = device_get_softc(dev); 174 int error; 175 176 error = bus_generic_detach(dev); 177 if (error) 178 return (error); 179 180 device_delete_children(dev); 181 182 bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 183 if (sc->irq_res) { 184 bus_release_resource(dev, SYS_RES_IRQ, 185 rman_get_rid(sc->irq_res), sc->irq_res); 186 sc->irq_res = NULL; 187 } 188 if (sc->mem_res) { 189 bus_release_resource(dev, SYS_RES_MEMORY, 190 rman_get_rid(sc->mem_res), sc->mem_res); 191 sc->mem_res = NULL; 192 } 193 lockuninit(&sc->lk); 194 195 pci_set_powerstate(dev, PCI_POWERSTATE_D3); 196 197 return 0; 198 } 199 200 /* 201 * The trigger, polarity and termination parameters are only used for 202 * sanity checking. The gpios should already be configured correctly by 203 * the firmware. 204 */ 205 static int 206 gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger, int polarity, 207 int termination, void **cookiep) 208 { 209 struct gpio_intel_softc *sc = device_get_softc(dev); 210 struct pin_intr_map *map = NULL; 211 int i, ret; 212 213 if (cookiep == NULL) 214 return (EINVAL); 215 216 lockmgr(&sc->lk, LK_EXCLUSIVE); 217 218 if (gpio_intel_pin_exists(sc, pin)) { 219 /* Make sure this pin isn't mapped yet */ 220 for (i = 0; i < NELEM(sc->intrmaps); i++) { 221 if (sc->intrmaps[i].pin == pin) { 222 lockmgr(&sc->lk, LK_RELEASE); 223 return (EBUSY); 224 } 225 } 226 ret = sc->fns->map_intr(sc, pin, trigger, polarity, 227 termination); 228 if (ret == 0) { 229 /* XXX map_intr should return the pin_intr_map */ 230 for (i = 0; i < NELEM(sc->intrmaps); i++) { 231 if (sc->intrmaps[i].pin == pin) 232 map = &sc->intrmaps[i]; 233 } 234 if (map != NULL) { 235 *cookiep = map; 236 map->arg = NULL; 237 map->handler = NULL; 238 } 239 } 240 } else { 241 device_printf(sc->dev, "%s: Invalid pin %d\n", __func__, pin); 242 ret = ENOENT; 243 } 244 245 lockmgr(&sc->lk, LK_RELEASE); 246 247 return (ret); 248 } 249 250 static void 251 gpio_intel_free_intr(device_t dev, void *cookie) 252 { 253 struct gpio_intel_softc *sc = device_get_softc(dev); 254 struct pin_intr_map *map = (struct pin_intr_map *)cookie; 255 256 KKASSERT(gpio_intel_pin_exists(sc, map->pin)); 257 258 lockmgr(&sc->lk, LK_EXCLUSIVE); 259 map->arg = NULL; 260 map->handler = NULL; 261 sc->fns->unmap_intr(sc, map); 262 lockmgr(&sc->lk, LK_RELEASE); 263 } 264 265 static void 266 gpio_intel_setup_intr(device_t dev, void *cookie, void *arg, 267 driver_intr_t *handler) 268 { 269 struct gpio_intel_softc *sc = device_get_softc(dev); 270 struct pin_intr_map *map = (struct pin_intr_map *)cookie; 271 272 KKASSERT(gpio_intel_pin_exists(sc, map->pin)); 273 274 lockmgr(&sc->lk, LK_EXCLUSIVE); 275 map->arg = arg; 276 map->handler = handler; 277 sc->fns->enable_intr(sc, map); 278 lockmgr(&sc->lk, LK_RELEASE); 279 } 280 281 static void 282 gpio_intel_teardown_intr(device_t dev, void *cookie) 283 { 284 struct gpio_intel_softc *sc = device_get_softc(dev); 285 struct pin_intr_map *map = (struct pin_intr_map *)cookie; 286 287 KKASSERT(gpio_intel_pin_exists(sc, map->pin)); 288 289 lockmgr(&sc->lk, LK_EXCLUSIVE); 290 sc->fns->disable_intr(sc, map); 291 map->arg = NULL; 292 map->handler = NULL; 293 lockmgr(&sc->lk, LK_RELEASE); 294 } 295 296 static int 297 gpio_intel_alloc_io_pin(device_t dev, u_int pin, int flags, void **cookiep) 298 { 299 struct gpio_intel_softc *sc = device_get_softc(dev); 300 struct pin_io_map *map = NULL; 301 int i, ret; 302 303 if (cookiep == NULL) 304 return (EINVAL); 305 306 if (!gpio_intel_pin_exists(sc, pin)) 307 return (ENOENT); 308 309 lockmgr(&sc->lk, LK_EXCLUSIVE); 310 311 for (i = 0; i < NELEM(sc->iomaps); i++) { 312 if (sc->iomaps[i].pin == pin) { 313 lockmgr(&sc->lk, LK_RELEASE); 314 return (EBUSY); 315 } 316 } 317 for (i = 0; i < NELEM(sc->iomaps); i++) { 318 if (sc->iomaps[i].pin == -1) { 319 map = &sc->iomaps[i]; 320 break; 321 } 322 } 323 if (map == NULL) { 324 ret = EBUSY; 325 } else if (sc->fns->check_io_pin(sc, pin, flags)) { 326 /* 327 * XXX It's possible that RX gets disabled when the interrupt 328 * on this pin gets released. 329 */ 330 map->pin = pin; 331 map->flags = flags; 332 *cookiep = map; 333 ret = 0; 334 } else { 335 ret = EBUSY; 336 } 337 338 lockmgr(&sc->lk, LK_RELEASE); 339 340 return (ret); 341 } 342 343 static void 344 gpio_intel_release_io_pin(device_t dev, void *cookie) 345 { 346 struct gpio_intel_softc *sc = device_get_softc(dev); 347 struct pin_io_map *map = (struct pin_io_map *)cookie; 348 349 lockmgr(&sc->lk, LK_EXCLUSIVE); 350 map->pin = -1; 351 map->flags = 0; 352 lockmgr(&sc->lk, LK_RELEASE); 353 } 354 355 static int 356 gpio_intel_read_pin(device_t dev, void *cookie) 357 { 358 struct gpio_intel_softc *sc = device_get_softc(dev); 359 struct pin_io_map *map = (struct pin_io_map *)cookie; 360 int val; 361 362 KKASSERT(map->pin >= 0); 363 KKASSERT(gpio_intel_pin_exists(sc, map->pin)); 364 365 lockmgr(&sc->lk, LK_EXCLUSIVE); 366 val = sc->fns->read_pin(sc, map->pin); 367 lockmgr(&sc->lk, LK_RELEASE); 368 369 return (val); 370 } 371 372 static void 373 gpio_intel_write_pin(device_t dev, void *cookie, int value) 374 { 375 struct gpio_intel_softc *sc = device_get_softc(dev); 376 struct pin_io_map *map = (struct pin_io_map *)cookie; 377 378 KKASSERT(map->pin >= 0); 379 KKASSERT(gpio_intel_pin_exists(sc, map->pin)); 380 381 lockmgr(&sc->lk, LK_EXCLUSIVE); 382 sc->fns->write_pin(sc, map->pin, value); 383 lockmgr(&sc->lk, LK_RELEASE); 384 } 385 386 static void 387 gpio_intel_intr(void *arg) 388 { 389 struct gpio_intel_softc *sc = (struct gpio_intel_softc *)arg; 390 391 lockmgr(&sc->lk, LK_EXCLUSIVE); 392 sc->fns->intr(arg); 393 lockmgr(&sc->lk, LK_RELEASE); 394 } 395 396 static int 397 gpio_intel_pin_exists(struct gpio_intel_softc *sc, uint16_t pin) 398 { 399 struct pinrange *r; 400 401 for (r = sc->ranges; r->start != -1 && r->end != -1; r++) { 402 if (r->start <= (int)pin && r->end >= (int)pin) 403 return (TRUE); 404 } 405 406 return (FALSE); 407 } 408 409 static device_method_t gpio_intel_methods[] = { 410 /* Device interface */ 411 DEVMETHOD(device_probe, gpio_intel_probe), 412 DEVMETHOD(device_attach, gpio_intel_attach), 413 DEVMETHOD(device_detach, gpio_intel_detach), 414 415 /* GPIO methods */ 416 DEVMETHOD(gpio_alloc_intr, gpio_intel_alloc_intr), 417 DEVMETHOD(gpio_free_intr, gpio_intel_free_intr), 418 DEVMETHOD(gpio_setup_intr, gpio_intel_setup_intr), 419 DEVMETHOD(gpio_teardown_intr, gpio_intel_teardown_intr), 420 DEVMETHOD(gpio_alloc_io_pin, gpio_intel_alloc_io_pin), 421 DEVMETHOD(gpio_release_io_pin, gpio_intel_release_io_pin), 422 DEVMETHOD(gpio_read_pin, gpio_intel_read_pin), 423 DEVMETHOD(gpio_write_pin, gpio_intel_write_pin), 424 425 DEVMETHOD_END 426 }; 427 428 static driver_t gpio_intel_driver = { 429 "gpio_intel", 430 gpio_intel_methods, 431 sizeof(struct gpio_intel_softc) 432 }; 433 434 static devclass_t gpio_intel_devclass; 435 436 DRIVER_MODULE(gpio_intel, acpi, gpio_intel_driver, gpio_intel_devclass, 437 NULL, NULL); 438 MODULE_DEPEND(gpio_intel, acpi, 1, 1, 1); 439 MODULE_DEPEND(gpio_intel, gpio_acpi, 1, 1, 1); 440 MODULE_VERSION(gpio_intel, 1); 441