1*9709bda0SColin Percival /*- 2*9709bda0SColin Percival * SPDX-License-Identifier: BSD-2-Clause 3*9709bda0SColin Percival * 4*9709bda0SColin Percival * Copyright (c) 2024 Colin Percival 5*9709bda0SColin Percival * 6*9709bda0SColin Percival * Redistribution and use in source and binary forms, with or without 7*9709bda0SColin Percival * modification, are permitted provided that the following conditions 8*9709bda0SColin Percival * are met: 9*9709bda0SColin Percival * 1. Redistributions of source code must retain the above copyright 10*9709bda0SColin Percival * notice, this list of conditions and the following disclaimer. 11*9709bda0SColin Percival * 2. Redistributions in binary form must reproduce the above copyright 12*9709bda0SColin Percival * notice, this list of conditions and the following disclaimer in the 13*9709bda0SColin Percival * documentation and/or other materials provided with the distribution. 14*9709bda0SColin Percival * 15*9709bda0SColin Percival * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*9709bda0SColin Percival * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*9709bda0SColin Percival * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*9709bda0SColin Percival * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*9709bda0SColin Percival * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*9709bda0SColin Percival * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*9709bda0SColin Percival * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*9709bda0SColin Percival * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*9709bda0SColin Percival * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*9709bda0SColin Percival * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*9709bda0SColin Percival * SUCH DAMAGE. 26*9709bda0SColin Percival */ 27*9709bda0SColin Percival 28*9709bda0SColin Percival #include <sys/types.h> 29*9709bda0SColin Percival #include <sys/bus.h> 30*9709bda0SColin Percival #include <sys/gpio.h> 31*9709bda0SColin Percival #include <sys/kernel.h> 32*9709bda0SColin Percival #include <sys/module.h> 33*9709bda0SColin Percival 34*9709bda0SColin Percival #include "gpiobus_if.h" 35*9709bda0SColin Percival 36*9709bda0SColin Percival #include <contrib/dev/acpica/include/acpi.h> 37*9709bda0SColin Percival #include <dev/acpica/acpivar.h> 38*9709bda0SColin Percival 39*9709bda0SColin Percival #include <dev/gpio/gpiobusvar.h> 40*9709bda0SColin Percival #include <dev/gpio/acpi_gpiobusvar.h> 41*9709bda0SColin Percival 42*9709bda0SColin Percival struct gpio_aei_softc { 43*9709bda0SColin Percival ACPI_HANDLE handle; 44*9709bda0SColin Percival char objname[5]; /* "_EXX" or "_LXX" */ 45*9709bda0SColin Percival struct resource * intr_res; 46*9709bda0SColin Percival int intr_rid; 47*9709bda0SColin Percival void * intr_cookie; 48*9709bda0SColin Percival }; 49*9709bda0SColin Percival 50*9709bda0SColin Percival static int 51*9709bda0SColin Percival gpio_aei_probe(device_t dev) 52*9709bda0SColin Percival { 53*9709bda0SColin Percival 54*9709bda0SColin Percival /* We only match when gpiobus explicitly requested gpio_aei. */ 55*9709bda0SColin Percival return (BUS_PROBE_NOWILDCARD); 56*9709bda0SColin Percival } 57*9709bda0SColin Percival 58*9709bda0SColin Percival static void 59*9709bda0SColin Percival gpio_aei_intr(void * arg) 60*9709bda0SColin Percival { 61*9709bda0SColin Percival struct gpio_aei_softc * sc = arg; 62*9709bda0SColin Percival 63*9709bda0SColin Percival /* Ask ACPI to run the appropriate _Exx or _Lxx method. */ 64*9709bda0SColin Percival AcpiEvaluateObject(sc->handle, sc->objname, NULL, NULL); 65*9709bda0SColin Percival } 66*9709bda0SColin Percival 67*9709bda0SColin Percival static int 68*9709bda0SColin Percival gpio_aei_attach(device_t dev) 69*9709bda0SColin Percival { 70*9709bda0SColin Percival struct gpio_aei_softc * sc = device_get_softc(dev); 71*9709bda0SColin Percival gpio_pin_t pin; 72*9709bda0SColin Percival int err; 73*9709bda0SColin Percival 74*9709bda0SColin Percival /* This is us. */ 75*9709bda0SColin Percival device_set_desc(dev, "ACPI Event Information Device"); 76*9709bda0SColin Percival 77*9709bda0SColin Percival /* Store parameters needed by gpio_aei_intr. */ 78*9709bda0SColin Percival sc->handle = acpi_gpiobus_get_handle(dev); 79*9709bda0SColin Percival if (gpio_pin_get_by_acpi_index(dev, 0, &pin) != 0) { 80*9709bda0SColin Percival device_printf(dev, "Unable to get the input pin\n"); 81*9709bda0SColin Percival return (ENXIO); 82*9709bda0SColin Percival } 83*9709bda0SColin Percival sprintf(sc->objname, "_%c%02X", 84*9709bda0SColin Percival (pin->flags & GPIO_INTR_EDGE_MASK) ? 'E' : 'L', pin->pin); 85*9709bda0SColin Percival 86*9709bda0SColin Percival /* Support for GPIO pins > 255 is not implemented. */ 87*9709bda0SColin Percival if (pin->pin > 255) { 88*9709bda0SColin Percival device_printf(dev, "ACPI Event Information Device does not support pins > 255"); 89*9709bda0SColin Percival return (ENOTSUP); 90*9709bda0SColin Percival } 91*9709bda0SColin Percival 92*9709bda0SColin Percival /* Set up the interrupt. */ 93*9709bda0SColin Percival if ((sc->intr_res = gpio_alloc_intr_resource(dev, &sc->intr_rid, 94*9709bda0SColin Percival RF_ACTIVE, pin, pin->flags & GPIO_INTR_MASK)) == NULL) { 95*9709bda0SColin Percival device_printf(dev, "Cannot allocate an IRQ\n"); 96*9709bda0SColin Percival return (ENOTSUP); 97*9709bda0SColin Percival } 98*9709bda0SColin Percival err = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_MISC | INTR_MPSAFE, 99*9709bda0SColin Percival NULL, gpio_aei_intr, sc, &sc->intr_cookie); 100*9709bda0SColin Percival if (err != 0) { 101*9709bda0SColin Percival device_printf(dev, "Cannot set up IRQ\n"); 102*9709bda0SColin Percival bus_release_resource(dev, SYS_RES_IRQ, sc->intr_rid, 103*9709bda0SColin Percival sc->intr_res); 104*9709bda0SColin Percival return (err); 105*9709bda0SColin Percival } 106*9709bda0SColin Percival 107*9709bda0SColin Percival return (0); 108*9709bda0SColin Percival } 109*9709bda0SColin Percival 110*9709bda0SColin Percival static int 111*9709bda0SColin Percival gpio_aei_detach(device_t dev) 112*9709bda0SColin Percival { 113*9709bda0SColin Percival struct gpio_aei_softc * sc = device_get_softc(dev); 114*9709bda0SColin Percival 115*9709bda0SColin Percival bus_teardown_intr(dev, sc->intr_res, sc->intr_cookie); 116*9709bda0SColin Percival bus_release_resource(dev, SYS_RES_IRQ, sc->intr_rid, sc->intr_res); 117*9709bda0SColin Percival return (0); 118*9709bda0SColin Percival } 119*9709bda0SColin Percival 120*9709bda0SColin Percival static device_method_t gpio_aei_methods[] = { 121*9709bda0SColin Percival /* Device interface. */ 122*9709bda0SColin Percival DEVMETHOD(device_probe, gpio_aei_probe), 123*9709bda0SColin Percival DEVMETHOD(device_attach, gpio_aei_attach), 124*9709bda0SColin Percival DEVMETHOD(device_detach, gpio_aei_detach), 125*9709bda0SColin Percival 126*9709bda0SColin Percival DEVMETHOD_END 127*9709bda0SColin Percival }; 128*9709bda0SColin Percival 129*9709bda0SColin Percival DEFINE_CLASS_0(gpio_aei, gpio_aei_driver, gpio_aei_methods, sizeof(struct gpio_aei_softc)); 130*9709bda0SColin Percival DRIVER_MODULE(gpio_aei, gpiobus, gpio_aei_driver, NULL, NULL); 131*9709bda0SColin Percival MODULE_DEPEND(gpio_aei, acpi_gpiobus, 1, 1, 1); 132