19709bda0SColin Percival /*-
29709bda0SColin Percival * SPDX-License-Identifier: BSD-2-Clause
39709bda0SColin Percival *
49709bda0SColin Percival * Copyright (c) 2024 Colin Percival
59709bda0SColin Percival *
69709bda0SColin Percival * Redistribution and use in source and binary forms, with or without
79709bda0SColin Percival * modification, are permitted provided that the following conditions
89709bda0SColin Percival * are met:
99709bda0SColin Percival * 1. Redistributions of source code must retain the above copyright
109709bda0SColin Percival * notice, this list of conditions and the following disclaimer.
119709bda0SColin Percival * 2. Redistributions in binary form must reproduce the above copyright
129709bda0SColin Percival * notice, this list of conditions and the following disclaimer in the
139709bda0SColin Percival * documentation and/or other materials provided with the distribution.
149709bda0SColin Percival *
159709bda0SColin Percival * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
169709bda0SColin Percival * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
179709bda0SColin Percival * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
189709bda0SColin Percival * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199709bda0SColin Percival * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
209709bda0SColin Percival * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
219709bda0SColin Percival * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
229709bda0SColin Percival * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
239709bda0SColin Percival * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
249709bda0SColin Percival * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
259709bda0SColin Percival * SUCH DAMAGE.
269709bda0SColin Percival */
279709bda0SColin Percival
289709bda0SColin Percival #include <sys/types.h>
299709bda0SColin Percival #include <sys/bus.h>
309709bda0SColin Percival #include <sys/gpio.h>
319709bda0SColin Percival #include <sys/kernel.h>
329709bda0SColin Percival #include <sys/module.h>
339709bda0SColin Percival
349709bda0SColin Percival #include "gpiobus_if.h"
359709bda0SColin Percival
369709bda0SColin Percival #include <contrib/dev/acpica/include/acpi.h>
379709bda0SColin Percival #include <dev/acpica/acpivar.h>
389709bda0SColin Percival
399709bda0SColin Percival #include <dev/gpio/gpiobusvar.h>
409709bda0SColin Percival #include <dev/gpio/acpi_gpiobusvar.h>
419709bda0SColin Percival
42*adc2c156SVladimir Kondratyev enum gpio_aei_type {
43*adc2c156SVladimir Kondratyev ACPI_AEI_TYPE_UNKNOWN,
44*adc2c156SVladimir Kondratyev ACPI_AEI_TYPE_ELX,
45*adc2c156SVladimir Kondratyev ACPI_AEI_TYPE_EVT
46*adc2c156SVladimir Kondratyev };
47*adc2c156SVladimir Kondratyev
489709bda0SColin Percival struct gpio_aei_softc {
499709bda0SColin Percival ACPI_HANDLE handle;
50*adc2c156SVladimir Kondratyev enum gpio_aei_type type;
51*adc2c156SVladimir Kondratyev int pin;
529709bda0SColin Percival struct resource * intr_res;
539709bda0SColin Percival int intr_rid;
549709bda0SColin Percival void * intr_cookie;
559709bda0SColin Percival };
569709bda0SColin Percival
579709bda0SColin Percival static int
gpio_aei_probe(device_t dev)589709bda0SColin Percival gpio_aei_probe(device_t dev)
599709bda0SColin Percival {
609709bda0SColin Percival
619709bda0SColin Percival /* We only match when gpiobus explicitly requested gpio_aei. */
629709bda0SColin Percival return (BUS_PROBE_NOWILDCARD);
639709bda0SColin Percival }
649709bda0SColin Percival
659709bda0SColin Percival static void
gpio_aei_intr(void * arg)669709bda0SColin Percival gpio_aei_intr(void * arg)
679709bda0SColin Percival {
689709bda0SColin Percival struct gpio_aei_softc * sc = arg;
699709bda0SColin Percival
70*adc2c156SVladimir Kondratyev /* Ask ACPI to run the appropriate _EVT, _Exx or _Lxx method. */
71*adc2c156SVladimir Kondratyev if (sc->type == ACPI_AEI_TYPE_EVT)
72*adc2c156SVladimir Kondratyev acpi_SetInteger(sc->handle, NULL, sc->pin);
73*adc2c156SVladimir Kondratyev else
74*adc2c156SVladimir Kondratyev AcpiEvaluateObject(sc->handle, NULL, NULL, NULL);
759709bda0SColin Percival }
769709bda0SColin Percival
779709bda0SColin Percival static int
gpio_aei_attach(device_t dev)789709bda0SColin Percival gpio_aei_attach(device_t dev)
799709bda0SColin Percival {
809709bda0SColin Percival struct gpio_aei_softc * sc = device_get_softc(dev);
819709bda0SColin Percival gpio_pin_t pin;
82*adc2c156SVladimir Kondratyev ACPI_HANDLE handle;
839709bda0SColin Percival int err;
849709bda0SColin Percival
859709bda0SColin Percival /* This is us. */
869709bda0SColin Percival device_set_desc(dev, "ACPI Event Information Device");
879709bda0SColin Percival
889709bda0SColin Percival /* Store parameters needed by gpio_aei_intr. */
89*adc2c156SVladimir Kondratyev handle = acpi_gpiobus_get_handle(dev);
909709bda0SColin Percival if (gpio_pin_get_by_acpi_index(dev, 0, &pin) != 0) {
919709bda0SColin Percival device_printf(dev, "Unable to get the input pin\n");
929709bda0SColin Percival return (ENXIO);
939709bda0SColin Percival }
949709bda0SColin Percival
95*adc2c156SVladimir Kondratyev sc->type = ACPI_AEI_TYPE_UNKNOWN;
96*adc2c156SVladimir Kondratyev sc->pin = pin->pin;
97*adc2c156SVladimir Kondratyev if (pin->pin <= 255) {
98*adc2c156SVladimir Kondratyev char objname[5]; /* "_EXX" or "_LXX" */
99*adc2c156SVladimir Kondratyev sprintf(objname, "_%c%02X",
100*adc2c156SVladimir Kondratyev (pin->flags & GPIO_INTR_EDGE_MASK) ? 'E' : 'L', pin->pin);
101*adc2c156SVladimir Kondratyev if (ACPI_SUCCESS(AcpiGetHandle(handle, objname, &sc->handle)))
102*adc2c156SVladimir Kondratyev sc->type = ACPI_AEI_TYPE_ELX;
103*adc2c156SVladimir Kondratyev }
104*adc2c156SVladimir Kondratyev if (sc->type == ACPI_AEI_TYPE_UNKNOWN) {
105*adc2c156SVladimir Kondratyev if (ACPI_SUCCESS(AcpiGetHandle(handle, "_EVT", &sc->handle)))
106*adc2c156SVladimir Kondratyev sc->type = ACPI_AEI_TYPE_EVT;
107*adc2c156SVladimir Kondratyev }
108*adc2c156SVladimir Kondratyev
109*adc2c156SVladimir Kondratyev if (sc->type == ACPI_AEI_TYPE_UNKNOWN) {
110*adc2c156SVladimir Kondratyev device_printf(dev, "ACPI Event Information Device type is unknown");
1119709bda0SColin Percival return (ENOTSUP);
1129709bda0SColin Percival }
1139709bda0SColin Percival
1149709bda0SColin Percival /* Set up the interrupt. */
1159709bda0SColin Percival if ((sc->intr_res = gpio_alloc_intr_resource(dev, &sc->intr_rid,
1169709bda0SColin Percival RF_ACTIVE, pin, pin->flags & GPIO_INTR_MASK)) == NULL) {
1179709bda0SColin Percival device_printf(dev, "Cannot allocate an IRQ\n");
1189709bda0SColin Percival return (ENOTSUP);
1199709bda0SColin Percival }
1209709bda0SColin Percival err = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_MISC | INTR_MPSAFE,
1219709bda0SColin Percival NULL, gpio_aei_intr, sc, &sc->intr_cookie);
1229709bda0SColin Percival if (err != 0) {
1239709bda0SColin Percival device_printf(dev, "Cannot set up IRQ\n");
1249709bda0SColin Percival bus_release_resource(dev, SYS_RES_IRQ, sc->intr_rid,
1259709bda0SColin Percival sc->intr_res);
1269709bda0SColin Percival return (err);
1279709bda0SColin Percival }
1289709bda0SColin Percival
1299709bda0SColin Percival return (0);
1309709bda0SColin Percival }
1319709bda0SColin Percival
1329709bda0SColin Percival static int
gpio_aei_detach(device_t dev)1339709bda0SColin Percival gpio_aei_detach(device_t dev)
1349709bda0SColin Percival {
1359709bda0SColin Percival struct gpio_aei_softc * sc = device_get_softc(dev);
1369709bda0SColin Percival
1379709bda0SColin Percival bus_teardown_intr(dev, sc->intr_res, sc->intr_cookie);
1389709bda0SColin Percival bus_release_resource(dev, SYS_RES_IRQ, sc->intr_rid, sc->intr_res);
1399709bda0SColin Percival return (0);
1409709bda0SColin Percival }
1419709bda0SColin Percival
1429709bda0SColin Percival static device_method_t gpio_aei_methods[] = {
1439709bda0SColin Percival /* Device interface. */
1449709bda0SColin Percival DEVMETHOD(device_probe, gpio_aei_probe),
1459709bda0SColin Percival DEVMETHOD(device_attach, gpio_aei_attach),
1469709bda0SColin Percival DEVMETHOD(device_detach, gpio_aei_detach),
1479709bda0SColin Percival
1489709bda0SColin Percival DEVMETHOD_END
1499709bda0SColin Percival };
1509709bda0SColin Percival
1519709bda0SColin Percival DEFINE_CLASS_0(gpio_aei, gpio_aei_driver, gpio_aei_methods, sizeof(struct gpio_aei_softc));
1529709bda0SColin Percival DRIVER_MODULE(gpio_aei, gpiobus, gpio_aei_driver, NULL, NULL);
1539709bda0SColin Percival MODULE_DEPEND(gpio_aei, acpi_gpiobus, 1, 1, 1);
154