gpiobus.c revision 308333
1105239Sphantom/*- 2330449Seadler * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org> 3330449Seadler * All rights reserved. 4116612Sphantom * 5105239Sphantom * Redistribution and use in source and binary forms, with or without 6105239Sphantom * modification, are permitted provided that the following conditions 7105239Sphantom * are met: 8105239Sphantom * 1. Redistributions of source code must retain the above copyright 9105239Sphantom * notice, this list of conditions and the following disclaimer. 10105239Sphantom * 2. Redistributions in binary form must reproduce the above copyright 11105239Sphantom * notice, this list of conditions and the following disclaimer in the 12105239Sphantom * documentation and/or other materials provided with the distribution. 13105239Sphantom * 14105239Sphantom * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15105239Sphantom * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16105239Sphantom * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17105239Sphantom * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18105239Sphantom * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19105239Sphantom * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20105239Sphantom * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21105239Sphantom * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22105239Sphantom * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23105239Sphantom * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24105239Sphantom * SUCH DAMAGE. 25105239Sphantom */ 26105239Sphantom 27105239Sphantom#include <sys/cdefs.h> 28105239Sphantom__FBSDID("$FreeBSD: stable/11/sys/dev/gpio/gpiobus.c 308333 2016-11-05 10:23:02Z mmel $"); 29105239Sphantom 30105239Sphantom#include <sys/param.h> 31116612Sphantom#include <sys/systm.h> 32116873Sphantom#include <sys/bus.h> 33116873Sphantom#include <sys/gpio.h> 34116612Sphantom#ifdef INTRNG 35116612Sphantom#include <sys/intr.h> 36242808Sgrog#endif 37116612Sphantom#include <sys/kernel.h> 38116612Sphantom#include <sys/malloc.h> 39116612Sphantom#include <sys/module.h> 40298169Sbapt 41105239Sphantom#include <dev/gpio/gpiobusvar.h> 42298169Sbapt 43105239Sphantom#include "gpiobus_if.h" 44116612Sphantom 45309330Svangyzen#undef GPIOBUS_DEBUG 46105239Sphantom#ifdef GPIOBUS_DEBUG 47116612Sphantom#define dprintf printf 48105239Sphantom#else 49105239Sphantom#define dprintf(x, arg...) 50105239Sphantom#endif 51105239Sphantom 52105239Sphantomstatic void gpiobus_print_pins(struct gpiobus_ivar *, char *, size_t); 53116851Sphantomstatic int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int); 54105239Sphantomstatic int gpiobus_probe(device_t); 55105239Sphantomstatic int gpiobus_attach(device_t); 56309330Svangyzenstatic int gpiobus_detach(device_t); 57116612Sphantomstatic int gpiobus_suspend(device_t); 58116876Sphantomstatic int gpiobus_resume(device_t); 59105239Sphantomstatic void gpiobus_probe_nomatch(device_t, device_t); 60116675Sphantomstatic int gpiobus_print_child(device_t, device_t); 61116616Sphantomstatic int gpiobus_child_location_str(device_t, device_t, char *, size_t); 62310040Svangyzenstatic int gpiobus_child_pnpinfo_str(device_t, device_t, char *, size_t); 63310040Svangyzenstatic device_t gpiobus_add_child(device_t, u_int, const char *, int); 64197764Sedwinstatic void gpiobus_hinted_child(device_t, const char *, int); 65116612Sphantom 66116616Sphantom/* 67105239Sphantom * GPIOBUS interface 68105239Sphantom */ 69105239Sphantomstatic int gpiobus_acquire_bus(device_t, device_t, int); 70105239Sphantomstatic void gpiobus_release_bus(device_t, device_t); 71310040Svangyzenstatic int gpiobus_pin_setflags(device_t, device_t, uint32_t, uint32_t); 72310040Svangyzenstatic int gpiobus_pin_getflags(device_t, device_t, uint32_t, uint32_t*); 73310040Svangyzenstatic int gpiobus_pin_getcaps(device_t, device_t, uint32_t, uint32_t*); 74310040Svangyzenstatic int gpiobus_pin_set(device_t, device_t, uint32_t, unsigned int); 75105239Sphantomstatic int gpiobus_pin_get(device_t, device_t, uint32_t, unsigned int*); 76310040Svangyzenstatic int gpiobus_pin_toggle(device_t, device_t, uint32_t); 77116616Sphantom 78116616Sphantom/* 79105239Sphantom * XXX -> Move me to better place - gpio_subr.c? 80116616Sphantom * Also, this function must be changed when interrupt configuration 81116616Sphantom * data will be moved into struct resource. 82116612Sphantom */ 83116612Sphantom#ifdef INTRNG 84116612Sphantom 85116612Sphantomstruct resource * 86105239Sphantomgpio_alloc_intr_resource(device_t consumer_dev, int *rid, u_int alloc_flags, 87298169Sbapt gpio_pin_t pin, uint32_t intr_mode) 88105239Sphantom{ 89116612Sphantom u_int irq; 90116612Sphantom struct intr_map_data_gpio *gpio_data; 91116612Sphantom struct resource *res; 92242851Sgrog 93242851Sgrog gpio_data = (struct intr_map_data_gpio *)intr_alloc_map_data( 94242851Sgrog INTR_MAP_DATA_GPIO, sizeof(*gpio_data), M_WAITOK | M_ZERO); 95242851Sgrog gpio_data->gpio_pin_num = pin->pin; 96242851Sgrog gpio_data->gpio_pin_flags = pin->flags; 97242851Sgrog gpio_data->gpio_intr_mode = intr_mode; 98242851Sgrog 99242851Sgrog irq = intr_map_irq(pin->dev, 0, (struct intr_map_data *)gpio_data); 100242851Sgrog res = bus_alloc_resource(consumer_dev, SYS_RES_IRQ, rid, irq, irq, 1, 101242851Sgrog alloc_flags); 102242851Sgrog if (res == NULL) { 103242851Sgrog intr_free_intr_map_data((struct intr_map_data *)gpio_data); 104242851Sgrog return (NULL); 105242851Sgrog } 106242851Sgrog rman_set_virtual(res, gpio_data); 107242851Sgrog return (res); 108242851Sgrog} 109242851Sgrog#else 110242851Sgrogstruct resource * 111242851Sgroggpio_alloc_intr_resource(device_t consumer_dev, int *rid, u_int alloc_flags, 112242851Sgrog gpio_pin_t pin, uint32_t intr_mode) 113116612Sphantom{ 114310040Svangyzen 115116616Sphantom return (NULL); 116116616Sphantom} 117116616Sphantom#endif 118116616Sphantom 119116675Sphantomint 120116612Sphantomgpio_check_flags(uint32_t caps, uint32_t flags) 121116675Sphantom{ 122116612Sphantom 123116675Sphantom /* Check for unwanted flags. */ 124116675Sphantom if ((flags & caps) == 0 || (flags & caps) != flags) 125116675Sphantom return (EINVAL); 126116675Sphantom /* Cannot mix input/output together. */ 127116675Sphantom if (flags & GPIO_PIN_INPUT && flags & GPIO_PIN_OUTPUT) 128116675Sphantom return (EINVAL); 129116675Sphantom /* Cannot mix pull-up/pull-down together. */ 130116612Sphantom if (flags & GPIO_PIN_PULLUP && flags & GPIO_PIN_PULLDOWN) 131116675Sphantom return (EINVAL); 132116675Sphantom 133116675Sphantom return (0); 134116675Sphantom} 135116675Sphantom 136116675Sphantomstatic void 137116675Sphantomgpiobus_print_pins(struct gpiobus_ivar *devi, char *buf, size_t buflen) 138116612Sphantom{ 139116675Sphantom char tmp[128]; 140116675Sphantom int i, range_start, range_stop, need_coma; 141116675Sphantom 142116675Sphantom if (devi->npins == 0) 143116675Sphantom return; 144116675Sphantom 145116675Sphantom need_coma = 0; 146116675Sphantom range_start = range_stop = devi->pins[0]; 147116873Sphantom for (i = 1; i < devi->npins; i++) { 148116873Sphantom if (devi->pins[i] != (range_stop + 1)) { 149116873Sphantom if (need_coma) 150116873Sphantom strlcat(buf, ",", buflen); 151116873Sphantom memset(tmp, 0, sizeof(tmp)); 152116873Sphantom if (range_start != range_stop) 153116612Sphantom snprintf(tmp, sizeof(tmp) - 1, "%d-%d", 154116675Sphantom range_start, range_stop); 155116675Sphantom else 156116675Sphantom snprintf(tmp, sizeof(tmp) - 1, "%d", 157116675Sphantom range_start); 158116675Sphantom strlcat(buf, tmp, buflen); 159116675Sphantom 160116675Sphantom range_start = range_stop = devi->pins[i]; 161116675Sphantom need_coma = 1; 162116675Sphantom } 163116675Sphantom else 164116675Sphantom range_stop++; 165116675Sphantom } 166116675Sphantom 167116675Sphantom if (need_coma) 168116675Sphantom strlcat(buf, ",", buflen); 169116675Sphantom memset(tmp, 0, sizeof(tmp)); 170116675Sphantom if (range_start != range_stop) 171116675Sphantom snprintf(tmp, sizeof(tmp) - 1, "%d-%d", 172116675Sphantom range_start, range_stop); 173116675Sphantom else 174116675Sphantom snprintf(tmp, sizeof(tmp) - 1, "%d", 175116675Sphantom range_start); 176116675Sphantom strlcat(buf, tmp, buflen); 177116675Sphantom} 178116675Sphantom 179116675Sphantomdevice_t 180116675Sphantomgpiobus_attach_bus(device_t dev) 181116675Sphantom{ 182116675Sphantom device_t busdev; 183116675Sphantom 184116675Sphantom busdev = device_add_child(dev, "gpiobus", -1); 185116675Sphantom if (busdev == NULL) 186116675Sphantom return (NULL); 187116675Sphantom if (device_add_child(dev, "gpioc", -1) == NULL) { 188116675Sphantom device_delete_child(dev, busdev); 189116675Sphantom return (NULL); 190116675Sphantom } 191116675Sphantom#ifdef FDT 192116675Sphantom ofw_gpiobus_register_provider(dev); 193116675Sphantom#endif 194116675Sphantom bus_generic_attach(dev); 195116675Sphantom 196116675Sphantom return (busdev); 197116675Sphantom} 198197847Sedwin 199197847Sedwinint 200197847Sedwingpiobus_detach_bus(device_t dev) 201197847Sedwin{ 202197847Sedwin int err; 203197847Sedwin 204197847Sedwin#ifdef FDT 205197847Sedwin ofw_gpiobus_unregister_provider(dev); 206197847Sedwin#endif 207197847Sedwin err = bus_generic_detach(dev); 208197847Sedwin if (err != 0) 209197847Sedwin return (err); 210116675Sphantom 211116675Sphantom return (device_delete_children(dev)); 212116675Sphantom} 213116675Sphantom 214116675Sphantomint 215116675Sphantomgpiobus_init_softc(device_t dev) 216116675Sphantom{ 217116612Sphantom struct gpiobus_softc *sc; 218116675Sphantom 219116675Sphantom sc = GPIOBUS_SOFTC(dev); 220116675Sphantom sc->sc_busdev = dev; 221116675Sphantom sc->sc_dev = device_get_parent(dev); 222116675Sphantom sc->sc_intr_rman.rm_type = RMAN_ARRAY; 223116675Sphantom sc->sc_intr_rman.rm_descr = "GPIO Interrupts"; 224116612Sphantom if (rman_init(&sc->sc_intr_rman) != 0 || 225116612Sphantom rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0) 226307697Saraujo panic("%s: failed to set up rman.", __func__); 227116612Sphantom 228310040Svangyzen if (GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins) != 0) 229307697Saraujo return (ENXIO); 230133013Stjr 231105239Sphantom KASSERT(sc->sc_npins >= 0, ("GPIO device with no pins")); 232105239Sphantom 233105239Sphantom /* Pins = GPIO_PIN_MAX() + 1 */ 234124830Sgrehan sc->sc_npins++; 235116675Sphantom 236105239Sphantom sc->sc_pins = malloc(sizeof(*sc->sc_pins) * sc->sc_npins, M_DEVBUF, 237197764Sedwin M_NOWAIT | M_ZERO); 238105239Sphantom if (sc->sc_pins == NULL) 239105239Sphantom return (ENOMEM); 240105239Sphantom 241105239Sphantom /* Initialize the bus lock. */ 242116612Sphantom GPIOBUS_LOCK_INIT(sc); 243116612Sphantom 244105239Sphantom return (0); 245116612Sphantom} 246116612Sphantom 247116612Sphantomint 248116612Sphantomgpiobus_alloc_ivars(struct gpiobus_ivar *devi) 249116612Sphantom{ 250116612Sphantom 251105239Sphantom /* Allocate pins and flags memory. */ 252105239Sphantom devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, 253105239Sphantom M_NOWAIT | M_ZERO); 254116612Sphantom if (devi->pins == NULL) 255105239Sphantom return (ENOMEM); 256105239Sphantom devi->flags = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, 257105239Sphantom M_NOWAIT | M_ZERO); 258116612Sphantom if (devi->flags == NULL) { 259116612Sphantom free(devi->pins, M_DEVBUF); 260116612Sphantom return (ENOMEM); 261242743Sgrog } 262116612Sphantom 263116612Sphantom return (0); 264116612Sphantom} 265116612Sphantom 266116612Sphantomvoid 267105239Sphantomgpiobus_free_ivars(struct gpiobus_ivar *devi) 268105239Sphantom{ 269105239Sphantom 270105239Sphantom if (devi->flags) { 271105239Sphantom free(devi->flags, M_DEVBUF); 272116612Sphantom devi->flags = NULL; 273116612Sphantom } 274116876Sphantom if (devi->pins) { 275116876Sphantom free(devi->pins, M_DEVBUF); 276116612Sphantom devi->pins = NULL; 277116612Sphantom } 278116675Sphantom} 279116675Sphantom 280116675Sphantomint 281116675Sphantomgpiobus_acquire_pin(device_t bus, uint32_t pin) 282116675Sphantom{ 283197764Sedwin struct gpiobus_softc *sc; 284116675Sphantom 285116675Sphantom sc = device_get_softc(bus); 286116675Sphantom /* Consistency check. */ 287243201Sgrog if (pin >= sc->sc_npins) { 288243201Sgrog device_printf(bus, 289309180Sume "invalid pin %d, max: %d\n", pin, sc->sc_npins - 1); 290309180Sume return (-1); 291242743Sgrog } 292242808Sgrog /* Mark pin as mapped and give warning if it's already mapped. */ 293242743Sgrog if (sc->sc_pins[pin].mapped) { 294242808Sgrog device_printf(bus, "warning: pin %d is already mapped\n", pin); 295242808Sgrog return (-1); 296242808Sgrog } 297242808Sgrog sc->sc_pins[pin].mapped = 1; 298242743Sgrog 299298169Sbapt return (0); 300310040Svangyzen} 301242808Sgrog 302116612Sphantom/* Release mapped pin */ 303116612Sphantomint 304116612Sphantomgpiobus_release_pin(device_t bus, uint32_t pin) 305116612Sphantom{ 306116612Sphantom struct gpiobus_softc *sc; 307116612Sphantom 308105239Sphantom sc = device_get_softc(bus); 309105239Sphantom /* Consistency check. */ 310105239Sphantom if (pin >= sc->sc_npins) { 311105239Sphantom device_printf(bus, 312105239Sphantom "gpiobus_acquire_pin: invalid pin %d, max=%d\n", 313105239Sphantom pin, sc->sc_npins - 1); 314116612Sphantom return (-1); 315242808Sgrog } 316242808Sgrog 317105239Sphantom if (!sc->sc_pins[pin].mapped) { 318105239Sphantom device_printf(bus, "gpiobus_acquire_pin: pin %d is not mapped\n", pin); 319105239Sphantom return (-1); 320116612Sphantom } 321116612Sphantom sc->sc_pins[pin].mapped = 0; 322116612Sphantom 323116612Sphantom return (0); 324116612Sphantom} 325242851Sgrog 326116612Sphantomstatic int 327116612Sphantomgpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) 328105239Sphantom{ 329105239Sphantom struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); 330105239Sphantom int i, npins; 331116616Sphantom 332105239Sphantom npins = 0; 333116612Sphantom for (i = 0; i < 32; i++) { 334105239Sphantom if (mask & (1 << i)) 335105239Sphantom npins++; 336105239Sphantom } 337105239Sphantom if (npins == 0) { 338105239Sphantom device_printf(child, "empty pin mask\n"); 339116876Sphantom return (EINVAL); 340116877Sphantom } 341116877Sphantom devi->npins = npins; 342116877Sphantom if (gpiobus_alloc_ivars(devi) != 0) { 343116877Sphantom device_printf(child, "cannot allocate device ivars\n"); 344116877Sphantom return (EINVAL); 345310040Svangyzen } 346116877Sphantom npins = 0; 347116877Sphantom for (i = 0; i < 32; i++) { 348116877Sphantom if ((mask & (1 << i)) == 0) 349116876Sphantom continue; 350116876Sphantom /* Reserve the GPIO pin. */ 351116876Sphantom if (gpiobus_acquire_pin(sc->sc_busdev, i) != 0) { 352116876Sphantom gpiobus_free_ivars(devi); 353116876Sphantom return (EINVAL); 354116876Sphantom } 355116876Sphantom devi->pins[npins++] = i; 356116876Sphantom /* Use the child name as pin name. */ 357116876Sphantom GPIOBUS_PIN_SETNAME(sc->sc_busdev, i, 358116876Sphantom device_get_nameunit(child)); 359116876Sphantom } 360116876Sphantom 361116612Sphantom return (0); 362116876Sphantom} 363116876Sphantom 364116876Sphantomstatic int 365116876Sphantomgpiobus_probe(device_t dev) 366116876Sphantom{ 367116876Sphantom device_set_desc(dev, "GPIO bus"); 368116876Sphantom 369116876Sphantom return (BUS_PROBE_GENERIC); 370116876Sphantom} 371116876Sphantom 372116876Sphantomstatic int 373116876Sphantomgpiobus_attach(device_t dev) 374116876Sphantom{ 375116876Sphantom int err; 376116876Sphantom 377116876Sphantom err = gpiobus_init_softc(dev); 378116876Sphantom if (err != 0) 379116876Sphantom return (err); 380116876Sphantom 381116876Sphantom /* 382310040Svangyzen * Get parent's pins and mark them as unmapped 383116876Sphantom */ 384116876Sphantom bus_generic_probe(dev); 385116876Sphantom bus_enumerate_hinted_children(dev); 386116876Sphantom 387116876Sphantom return (bus_generic_attach(dev)); 388116876Sphantom} 389116876Sphantom 390116876Sphantom/* 391116876Sphantom * Since this is not a self-enumerating bus, and since we always add 392116876Sphantom * children in attach, we have to always delete children here. 393116612Sphantom */ 394116612Sphantomstatic int 395116612Sphantomgpiobus_detach(device_t dev) 396116612Sphantom{ 397105239Sphantom struct gpiobus_softc *sc; 398116612Sphantom struct gpiobus_ivar *devi; 399105239Sphantom device_t *devlist; 400116612Sphantom int i, err, ndevs; 401116612Sphantom 402133013Stjr sc = GPIOBUS_SOFTC(dev); 403133013Stjr KASSERT(mtx_initialized(&sc->sc_mtx), 404105239Sphantom ("gpiobus mutex not initialized")); 405116612Sphantom GPIOBUS_LOCK_DESTROY(sc); 406116612Sphantom 407105239Sphantom if ((err = bus_generic_detach(dev)) != 0) 408116612Sphantom return (err); 409116612Sphantom 410116612Sphantom if ((err = device_get_children(dev, &devlist, &ndevs)) != 0) 411116612Sphantom return (err); 412116612Sphantom for (i = 0; i < ndevs; i++) { 413116612Sphantom devi = GPIOBUS_IVAR(devlist[i]); 414116612Sphantom gpiobus_free_ivars(devi); 415116851Sphantom resource_list_free(&devi->rl); 416116851Sphantom free(devi, M_DEVBUF); 417116612Sphantom device_delete_child(dev, devlist[i]); 418116612Sphantom } 419116851Sphantom free(devlist, M_TEMP); 420116612Sphantom rman_fini(&sc->sc_intr_rman); 421116851Sphantom if (sc->sc_pins) { 422116612Sphantom for (i = 0; i < sc->sc_npins; i++) { 423116612Sphantom if (sc->sc_pins[i].name != NULL) 424116612Sphantom free(sc->sc_pins[i].name, M_DEVBUF); 425116612Sphantom sc->sc_pins[i].name = NULL; 426116612Sphantom } 427133013Stjr free(sc->sc_pins, M_DEVBUF); 428133013Stjr sc->sc_pins = NULL; 429133013Stjr } 430133013Stjr 431133013Stjr return (0); 432133013Stjr} 433105239Sphantom 434116612Sphantomstatic int 435105239Sphantomgpiobus_suspend(device_t dev) 436242808Sgrog{ 437116612Sphantom 438242808Sgrog return (bus_generic_suspend(dev)); 439242808Sgrog} 440116612Sphantom 441310040Svangyzenstatic int 442105239Sphantomgpiobus_resume(device_t dev) 443116612Sphantom{ 444310040Svangyzen 445105239Sphantom return (bus_generic_resume(dev)); 446116612Sphantom} 447116612Sphantom 448105239Sphantomstatic void 449105239Sphantomgpiobus_probe_nomatch(device_t dev, device_t child) 450116612Sphantom{ 451116612Sphantom char pins[128]; 452116612Sphantom struct gpiobus_ivar *devi; 453105239Sphantom 454116612Sphantom devi = GPIOBUS_IVAR(child); 455105239Sphantom memset(pins, 0, sizeof(pins)); 456116616Sphantom gpiobus_print_pins(devi, pins, sizeof(pins)); 457125329Sache if (devi->npins > 1) 458105239Sphantom device_printf(dev, "<unknown device> at pins %s", pins); 459125329Sache else 460105239Sphantom device_printf(dev, "<unknown device> at pin %s", pins); 461125329Sache resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd"); 462125329Sache printf("\n"); 463116612Sphantom} 464125329Sache 465125329Sachestatic int 466116616Sphantomgpiobus_print_child(device_t dev, device_t child) 467105239Sphantom{ 468116612Sphantom char pins[128]; 469116612Sphantom int retval = 0; 470116612Sphantom struct gpiobus_ivar *devi; 471116612Sphantom 472116612Sphantom devi = GPIOBUS_IVAR(child); 473116612Sphantom memset(pins, 0, sizeof(pins)); 474116612Sphantom retval += bus_print_child_header(dev, child); 475289677Seadler if (devi->npins > 0) { 476116612Sphantom if (devi->npins > 1) 477116612Sphantom retval += printf(" at pins "); 478289677Seadler else 479116612Sphantom retval += printf(" at pin "); 480116612Sphantom gpiobus_print_pins(devi, pins, sizeof(pins)); 481116612Sphantom retval += printf("%s", pins); 482116612Sphantom } 483116612Sphantom resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd"); 484116612Sphantom retval += bus_print_child_footer(dev, child); 485105239Sphantom 486105239Sphantom return (retval); 487125329Sache} 488125329Sache 489125329Sachestatic int 490125329Sachegpiobus_child_location_str(device_t bus, device_t child, char *buf, 491125329Sache size_t buflen) 492105239Sphantom{ 493105239Sphantom struct gpiobus_ivar *devi; 494309330Svangyzen 495309330Svangyzen devi = GPIOBUS_IVAR(child); 496309330Svangyzen if (devi->npins > 1) 497309330Svangyzen strlcpy(buf, "pins=", buflen); 498309330Svangyzen else 499310040Svangyzen strlcpy(buf, "pin=", buflen); 500310040Svangyzen gpiobus_print_pins(devi, buf, buflen); 501309330Svangyzen 502309330Svangyzen return (0); 503310040Svangyzen} 504309330Svangyzen 505310040Svangyzenstatic int 506310040Svangyzengpiobus_child_pnpinfo_str(device_t bus, device_t child, char *buf, 507310040Svangyzen size_t buflen) 508310040Svangyzen{ 509310040Svangyzen 510310040Svangyzen *buf = '\0'; 511310040Svangyzen return (0); 512310040Svangyzen} 513310040Svangyzen 514310040Svangyzenstatic device_t 515309330Svangyzengpiobus_add_child(device_t dev, u_int order, const char *name, int unit) 516309330Svangyzen{ 517310040Svangyzen device_t child; 518310040Svangyzen struct gpiobus_ivar *devi; 519310040Svangyzen 520309330Svangyzen child = device_add_child_ordered(dev, order, name, unit); 521310040Svangyzen if (child == NULL) 522309330Svangyzen return (child); 523309330Svangyzen devi = malloc(sizeof(struct gpiobus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 524116612Sphantom if (devi == NULL) { 525116612Sphantom device_delete_child(dev, child); 526116612Sphantom return (NULL); 527116612Sphantom } 528116612Sphantom resource_list_init(&devi->rl); 529105239Sphantom device_set_ivars(child, devi); 530116616Sphantom 531116616Sphantom return (child); 532105239Sphantom} 533116616Sphantom 534116616Sphantomstatic void 535116612Sphantomgpiobus_hinted_child(device_t bus, const char *dname, int dunit) 536116612Sphantom{ 537309330Svangyzen struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus); 538116612Sphantom struct gpiobus_ivar *devi; 539116612Sphantom device_t child; 540116612Sphantom int irq, pins; 541116612Sphantom 542116612Sphantom child = BUS_ADD_CHILD(bus, 0, dname, dunit); 543116612Sphantom devi = GPIOBUS_IVAR(child); 544116612Sphantom resource_int_value(dname, dunit, "pins", &pins); 545116612Sphantom if (gpiobus_parse_pins(sc, child, pins)) { 546116612Sphantom resource_list_free(&devi->rl); 547116612Sphantom free(devi, M_DEVBUF); 548116612Sphantom device_delete_child(bus, child); 549116612Sphantom } 550116612Sphantom if (resource_int_value(dname, dunit, "irq", &irq) == 0) { 551116612Sphantom if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0) 552309330Svangyzen device_printf(bus, 553116612Sphantom "warning: bus_set_resource() failed\n"); 554116612Sphantom } 555116612Sphantom} 556116612Sphantom 557116612Sphantomstatic int 558116612Sphantomgpiobus_set_resource(device_t dev, device_t child, int type, int rid, 559116612Sphantom rman_res_t start, rman_res_t count) 560116612Sphantom{ 561116612Sphantom struct gpiobus_ivar *devi; 562116612Sphantom struct resource_list_entry *rle; 563116612Sphantom 564116612Sphantom dprintf("%s: entry (%p, %p, %d, %d, %p, %ld)\n", 565116612Sphantom __func__, dev, child, type, rid, (void *)(intptr_t)start, count); 566116612Sphantom devi = GPIOBUS_IVAR(child); 567116612Sphantom rle = resource_list_add(&devi->rl, type, rid, start, 568116612Sphantom start + count - 1, count); 569116612Sphantom if (rle == NULL) 570116612Sphantom return (ENXIO); 571116612Sphantom 572116612Sphantom return (0); 573116612Sphantom} 574116612Sphantom 575116612Sphantomstatic struct resource * 576116612Sphantomgpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid, 577116612Sphantom rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 578116612Sphantom{ 579116612Sphantom struct gpiobus_softc *sc; 580116612Sphantom struct resource *rv; 581116612Sphantom struct resource_list *rl; 582116612Sphantom struct resource_list_entry *rle; 583116612Sphantom int isdefault; 584116873Sphantom 585116873Sphantom if (type != SYS_RES_IRQ) 586116873Sphantom return (NULL); 587116873Sphantom isdefault = (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1); 588116873Sphantom rle = NULL; 589116873Sphantom if (isdefault) { 590116873Sphantom rl = BUS_GET_RESOURCE_LIST(bus, child); 591116873Sphantom if (rl == NULL) 592116873Sphantom return (NULL); 593116873Sphantom rle = resource_list_find(rl, type, *rid); 594116873Sphantom if (rle == NULL) 595116873Sphantom return (NULL); 596116873Sphantom if (rle->res != NULL) 597116873Sphantom panic("%s: resource entry is busy", __func__); 598116873Sphantom start = rle->start; 599116873Sphantom count = rle->count; 600116873Sphantom end = rle->end; 601116873Sphantom } 602116612Sphantom sc = device_get_softc(bus); 603116612Sphantom rv = rman_reserve_resource(&sc->sc_intr_rman, start, end, count, flags, 604116612Sphantom child); 605116612Sphantom if (rv == NULL) 606105239Sphantom return (NULL); 607105239Sphantom rman_set_rid(rv, *rid); 608116612Sphantom if ((flags & RF_ACTIVE) != 0 && 609116612Sphantom bus_activate_resource(child, type, *rid, rv) != 0) { 610116612Sphantom rman_release_resource(rv); 611116612Sphantom return (NULL); 612310040Svangyzen } 613105239Sphantom 614116616Sphantom return (rv); 615116616Sphantom} 616116612Sphantom 617116616Sphantomstatic int 618116612Sphantomgpiobus_release_resource(device_t bus __unused, device_t child, int type, 619116612Sphantom int rid, struct resource *r) 620116612Sphantom{ 621116612Sphantom int error; 622116612Sphantom 623116612Sphantom if (rman_get_flags(r) & RF_ACTIVE) { 624116612Sphantom error = bus_deactivate_resource(child, type, rid, r); 625116612Sphantom if (error) 626116612Sphantom return (error); 627116612Sphantom } 628116612Sphantom 629116612Sphantom return (rman_release_resource(r)); 630116612Sphantom} 631116612Sphantom 632116612Sphantomstatic struct resource_list * 633105239Sphantomgpiobus_get_resource_list(device_t bus __unused, device_t child) 634105239Sphantom{ 635116612Sphantom struct gpiobus_ivar *ivar; 636116612Sphantom 637116612Sphantom ivar = GPIOBUS_IVAR(child); 638116612Sphantom 639105239Sphantom return (&ivar->rl); 640310040Svangyzen} 641105239Sphantom 642116616Sphantomstatic int 643116616Sphantomgpiobus_acquire_bus(device_t busdev, device_t child, int how) 644105239Sphantom{ 645116612Sphantom struct gpiobus_softc *sc; 646116612Sphantom 647116612Sphantom sc = device_get_softc(busdev); 648116612Sphantom GPIOBUS_ASSERT_UNLOCKED(sc); 649116612Sphantom GPIOBUS_LOCK(sc); 650197764Sedwin if (sc->sc_owner != NULL) { 651105239Sphantom if (sc->sc_owner == child) 652116612Sphantom panic("%s: %s still owns the bus.", 653105239Sphantom device_get_nameunit(busdev), 654116612Sphantom device_get_nameunit(child)); 655310040Svangyzen if (how == GPIOBUS_DONTWAIT) { 656242743Sgrog GPIOBUS_UNLOCK(sc); 657310040Svangyzen return (EWOULDBLOCK); 658242808Sgrog } 659116612Sphantom while (sc->sc_owner != NULL) 660105239Sphantom mtx_sleep(sc, &sc->sc_mtx, 0, "gpiobuswait", 0); 661116612Sphantom } 662116612Sphantom sc->sc_owner = child; 663116612Sphantom GPIOBUS_UNLOCK(sc); 664116612Sphantom 665116616Sphantom return (0); 666116616Sphantom} 667116612Sphantom 668116612Sphantomstatic void 669105239Sphantomgpiobus_release_bus(device_t busdev, device_t child) 670116612Sphantom{ 671116612Sphantom struct gpiobus_softc *sc; 672116612Sphantom 673116612Sphantom sc = device_get_softc(busdev); 674116616Sphantom GPIOBUS_ASSERT_UNLOCKED(sc); 675116616Sphantom GPIOBUS_LOCK(sc); 676116612Sphantom if (sc->sc_owner == NULL) 677105239Sphantom panic("%s: %s releasing unowned bus.", 678105239Sphantom device_get_nameunit(busdev), 679116675Sphantom device_get_nameunit(child)); 680116675Sphantom if (sc->sc_owner != child) 681116675Sphantom panic("%s: %s trying to release bus owned by %s", 682116675Sphantom device_get_nameunit(busdev), 683116675Sphantom device_get_nameunit(child), 684116675Sphantom device_get_nameunit(sc->sc_owner)); 685116675Sphantom sc->sc_owner = NULL; 686116675Sphantom wakeup(sc); 687116675Sphantom GPIOBUS_UNLOCK(sc); 688116675Sphantom} 689116675Sphantom 690116675Sphantomstatic int 691116675Sphantomgpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, 692116675Sphantom uint32_t flags) 693116675Sphantom{ 694116675Sphantom struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); 695116675Sphantom struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); 696116675Sphantom uint32_t caps; 697116675Sphantom 698116675Sphantom if (pin >= devi->npins) 699197764Sedwin return (EINVAL); 700116675Sphantom if (GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], &caps) != 0) 701116675Sphantom return (EINVAL); 702116675Sphantom if (gpio_check_flags(caps, flags) != 0) 703242851Sgrog return (EINVAL); 704116675Sphantom 705197764Sedwin return (GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags)); 706197764Sedwin} 707197764Sedwin 708197764Sedwinstatic int 709197764Sedwingpiobus_pin_getflags(device_t dev, device_t child, uint32_t pin, 710116675Sphantom uint32_t *flags) 711116675Sphantom{ 712116675Sphantom struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); 713197764Sedwin struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); 714197764Sedwin 715197764Sedwin if (pin >= devi->npins) 716197764Sedwin return (EINVAL); 717197764Sedwin 718116675Sphantom return GPIO_PIN_GETFLAGS(sc->sc_dev, devi->pins[pin], flags); 719116675Sphantom} 720116675Sphantom 721116675Sphantomstatic int 722116675Sphantomgpiobus_pin_getcaps(device_t dev, device_t child, uint32_t pin, 723116675Sphantom uint32_t *caps) 724116675Sphantom{ 725 struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); 726 struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); 727 728 if (pin >= devi->npins) 729 return (EINVAL); 730 731 return GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], caps); 732} 733 734static int 735gpiobus_pin_set(device_t dev, device_t child, uint32_t pin, 736 unsigned int value) 737{ 738 struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); 739 struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); 740 741 if (pin >= devi->npins) 742 return (EINVAL); 743 744 return GPIO_PIN_SET(sc->sc_dev, devi->pins[pin], value); 745} 746 747static int 748gpiobus_pin_get(device_t dev, device_t child, uint32_t pin, 749 unsigned int *value) 750{ 751 struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); 752 struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); 753 754 if (pin >= devi->npins) 755 return (EINVAL); 756 757 return GPIO_PIN_GET(sc->sc_dev, devi->pins[pin], value); 758} 759 760static int 761gpiobus_pin_toggle(device_t dev, device_t child, uint32_t pin) 762{ 763 struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); 764 struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); 765 766 if (pin >= devi->npins) 767 return (EINVAL); 768 769 return GPIO_PIN_TOGGLE(sc->sc_dev, devi->pins[pin]); 770} 771 772static int 773gpiobus_pin_getname(device_t dev, uint32_t pin, char *name) 774{ 775 struct gpiobus_softc *sc; 776 777 sc = GPIOBUS_SOFTC(dev); 778 if (pin > sc->sc_npins) 779 return (EINVAL); 780 /* Did we have a name for this pin ? */ 781 if (sc->sc_pins[pin].name != NULL) { 782 memcpy(name, sc->sc_pins[pin].name, GPIOMAXNAME); 783 return (0); 784 } 785 786 /* Return the default pin name. */ 787 return (GPIO_PIN_GETNAME(device_get_parent(dev), pin, name)); 788} 789 790static int 791gpiobus_pin_setname(device_t dev, uint32_t pin, const char *name) 792{ 793 struct gpiobus_softc *sc; 794 795 sc = GPIOBUS_SOFTC(dev); 796 if (pin > sc->sc_npins) 797 return (EINVAL); 798 if (name == NULL) 799 return (EINVAL); 800 /* Save the pin name. */ 801 if (sc->sc_pins[pin].name == NULL) 802 sc->sc_pins[pin].name = malloc(GPIOMAXNAME, M_DEVBUF, 803 M_WAITOK | M_ZERO); 804 strlcpy(sc->sc_pins[pin].name, name, GPIOMAXNAME); 805 806 return (0); 807} 808 809static device_method_t gpiobus_methods[] = { 810 /* Device interface */ 811 DEVMETHOD(device_probe, gpiobus_probe), 812 DEVMETHOD(device_attach, gpiobus_attach), 813 DEVMETHOD(device_detach, gpiobus_detach), 814 DEVMETHOD(device_shutdown, bus_generic_shutdown), 815 DEVMETHOD(device_suspend, gpiobus_suspend), 816 DEVMETHOD(device_resume, gpiobus_resume), 817 818 /* Bus interface */ 819 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 820 DEVMETHOD(bus_config_intr, bus_generic_config_intr), 821 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 822 DEVMETHOD(bus_set_resource, gpiobus_set_resource), 823 DEVMETHOD(bus_alloc_resource, gpiobus_alloc_resource), 824 DEVMETHOD(bus_release_resource, gpiobus_release_resource), 825 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 826 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 827 DEVMETHOD(bus_get_resource_list, gpiobus_get_resource_list), 828 DEVMETHOD(bus_add_child, gpiobus_add_child), 829 DEVMETHOD(bus_probe_nomatch, gpiobus_probe_nomatch), 830 DEVMETHOD(bus_print_child, gpiobus_print_child), 831 DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str), 832 DEVMETHOD(bus_child_location_str, gpiobus_child_location_str), 833 DEVMETHOD(bus_hinted_child, gpiobus_hinted_child), 834 835 /* GPIO protocol */ 836 DEVMETHOD(gpiobus_acquire_bus, gpiobus_acquire_bus), 837 DEVMETHOD(gpiobus_release_bus, gpiobus_release_bus), 838 DEVMETHOD(gpiobus_pin_getflags, gpiobus_pin_getflags), 839 DEVMETHOD(gpiobus_pin_getcaps, gpiobus_pin_getcaps), 840 DEVMETHOD(gpiobus_pin_setflags, gpiobus_pin_setflags), 841 DEVMETHOD(gpiobus_pin_get, gpiobus_pin_get), 842 DEVMETHOD(gpiobus_pin_set, gpiobus_pin_set), 843 DEVMETHOD(gpiobus_pin_toggle, gpiobus_pin_toggle), 844 DEVMETHOD(gpiobus_pin_getname, gpiobus_pin_getname), 845 DEVMETHOD(gpiobus_pin_setname, gpiobus_pin_setname), 846 847 DEVMETHOD_END 848}; 849 850driver_t gpiobus_driver = { 851 "gpiobus", 852 gpiobus_methods, 853 sizeof(struct gpiobus_softc) 854}; 855 856devclass_t gpiobus_devclass; 857 858DRIVER_MODULE(gpiobus, gpio, gpiobus_driver, gpiobus_devclass, 0, 0); 859MODULE_VERSION(gpiobus, 1); 860