192adaa58SAhmad Khalifa /*-
292adaa58SAhmad Khalifa * SPDX-License-Identifier: BSD-2-Clause
392adaa58SAhmad Khalifa *
492adaa58SAhmad Khalifa * Copyright (c) 2024 Ahmad Khalifa <ahmadkhalifa570@gmail.com>
592adaa58SAhmad Khalifa *
692adaa58SAhmad Khalifa * Redistribution and use in source and binary forms, with or without
792adaa58SAhmad Khalifa * modification, are permitted provided that the following conditions
892adaa58SAhmad Khalifa * are met:
992adaa58SAhmad Khalifa * 1. Redistributions of source code must retain the above copyright
1092adaa58SAhmad Khalifa * notice, this list of conditions and the following disclaimer.
1192adaa58SAhmad Khalifa * 2. Redistributions in binary form must reproduce the above copyright
1292adaa58SAhmad Khalifa * notice, this list of conditions and the following disclaimer in the
1392adaa58SAhmad Khalifa * documentation and/or other materials provided with the distribution.
1492adaa58SAhmad Khalifa *
1592adaa58SAhmad Khalifa * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1692adaa58SAhmad Khalifa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1792adaa58SAhmad Khalifa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1892adaa58SAhmad Khalifa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1992adaa58SAhmad Khalifa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2092adaa58SAhmad Khalifa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2192adaa58SAhmad Khalifa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2292adaa58SAhmad Khalifa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2392adaa58SAhmad Khalifa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2492adaa58SAhmad Khalifa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2592adaa58SAhmad Khalifa * SUCH DAMAGE.
2692adaa58SAhmad Khalifa */
2792adaa58SAhmad Khalifa
2892adaa58SAhmad Khalifa #include <sys/types.h>
2992adaa58SAhmad Khalifa #include <sys/bus.h>
3092adaa58SAhmad Khalifa #include <sys/kernel.h>
3192adaa58SAhmad Khalifa #include <sys/module.h>
3292adaa58SAhmad Khalifa #include <sys/gpio.h>
3392adaa58SAhmad Khalifa
3492adaa58SAhmad Khalifa #include <contrib/dev/acpica/include/acpi.h>
3592adaa58SAhmad Khalifa #include <dev/acpica/acpivar.h>
3692adaa58SAhmad Khalifa
3792adaa58SAhmad Khalifa #include <dev/gpio/gpiobusvar.h>
38*9709bda0SColin Percival #include <dev/gpio/acpi_gpiobusvar.h>
39*9709bda0SColin Percival
40*9709bda0SColin Percival #include "gpiobus_if.h"
4192adaa58SAhmad Khalifa
4292adaa58SAhmad Khalifa struct acpi_gpiobus_softc {
4392adaa58SAhmad Khalifa struct gpiobus_softc super_sc;
4492adaa58SAhmad Khalifa ACPI_CONNECTION_INFO handler_info;
4592adaa58SAhmad Khalifa };
4692adaa58SAhmad Khalifa
4792adaa58SAhmad Khalifa struct acpi_gpiobus_ctx {
4892adaa58SAhmad Khalifa struct gpiobus_softc *sc;
4992adaa58SAhmad Khalifa ACPI_HANDLE dev_handle;
5092adaa58SAhmad Khalifa };
5192adaa58SAhmad Khalifa
52*9709bda0SColin Percival struct acpi_gpiobus_ivar
53*9709bda0SColin Percival {
54*9709bda0SColin Percival struct gpiobus_ivar gpiobus; /* Must come first */
55*9709bda0SColin Percival ACPI_HANDLE dev_handle; /* ACPI handle for bus */
56*9709bda0SColin Percival uint32_t flags;
57*9709bda0SColin Percival };
58*9709bda0SColin Percival
5992adaa58SAhmad Khalifa static uint32_t
acpi_gpiobus_convflags(ACPI_RESOURCE_GPIO * gpio_res)6092adaa58SAhmad Khalifa acpi_gpiobus_convflags(ACPI_RESOURCE_GPIO *gpio_res)
6192adaa58SAhmad Khalifa {
6292adaa58SAhmad Khalifa uint32_t flags = 0;
6392adaa58SAhmad Khalifa
6492adaa58SAhmad Khalifa /* Figure out pin flags */
6592adaa58SAhmad Khalifa if (gpio_res->ConnectionType == ACPI_RESOURCE_GPIO_TYPE_INT) {
6692adaa58SAhmad Khalifa switch (gpio_res->Polarity) {
6792adaa58SAhmad Khalifa case ACPI_ACTIVE_HIGH:
6892adaa58SAhmad Khalifa flags = gpio_res->Triggering == ACPI_LEVEL_SENSITIVE ?
6992adaa58SAhmad Khalifa GPIO_INTR_LEVEL_HIGH : GPIO_INTR_EDGE_RISING;
7092adaa58SAhmad Khalifa break;
7192adaa58SAhmad Khalifa case ACPI_ACTIVE_LOW:
7292adaa58SAhmad Khalifa flags = gpio_res->Triggering == ACPI_LEVEL_SENSITIVE ?
7392adaa58SAhmad Khalifa GPIO_INTR_LEVEL_LOW : GPIO_INTR_EDGE_FALLING;
7492adaa58SAhmad Khalifa break;
7592adaa58SAhmad Khalifa case ACPI_ACTIVE_BOTH:
7692adaa58SAhmad Khalifa flags = GPIO_INTR_EDGE_BOTH;
7792adaa58SAhmad Khalifa break;
7892adaa58SAhmad Khalifa }
7992adaa58SAhmad Khalifa
802d421991SColin Percival #ifdef NOT_YET
812d421991SColin Percival /* This is not currently implemented. */
8292adaa58SAhmad Khalifa if (gpio_res->Shareable == ACPI_SHARED)
8392adaa58SAhmad Khalifa flags |= GPIO_INTR_SHAREABLE;
8492adaa58SAhmad Khalifa #endif
852d421991SColin Percival }
860ffd7d4dSColin Percival if (gpio_res->ConnectionType == ACPI_RESOURCE_GPIO_TYPE_IO) {
8792adaa58SAhmad Khalifa switch (gpio_res->IoRestriction) {
8892adaa58SAhmad Khalifa case ACPI_IO_RESTRICT_INPUT:
89c8081327SColin Percival flags |= GPIO_PIN_INPUT;
9092adaa58SAhmad Khalifa break;
9192adaa58SAhmad Khalifa case ACPI_IO_RESTRICT_OUTPUT:
92c8081327SColin Percival flags |= GPIO_PIN_OUTPUT;
9392adaa58SAhmad Khalifa break;
9492adaa58SAhmad Khalifa }
950ffd7d4dSColin Percival }
9692adaa58SAhmad Khalifa
9792adaa58SAhmad Khalifa switch (gpio_res->PinConfig) {
9892adaa58SAhmad Khalifa case ACPI_PIN_CONFIG_PULLUP:
9992adaa58SAhmad Khalifa flags |= GPIO_PIN_PULLUP;
10092adaa58SAhmad Khalifa break;
10192adaa58SAhmad Khalifa case ACPI_PIN_CONFIG_PULLDOWN:
10292adaa58SAhmad Khalifa flags |= GPIO_PIN_PULLDOWN;
10392adaa58SAhmad Khalifa break;
10492adaa58SAhmad Khalifa }
10592adaa58SAhmad Khalifa
10692adaa58SAhmad Khalifa return (flags);
10792adaa58SAhmad Khalifa }
10892adaa58SAhmad Khalifa
10992adaa58SAhmad Khalifa static ACPI_STATUS
acpi_gpiobus_enumerate_res(ACPI_RESOURCE * res,void * context)11092adaa58SAhmad Khalifa acpi_gpiobus_enumerate_res(ACPI_RESOURCE *res, void *context)
11192adaa58SAhmad Khalifa {
11292adaa58SAhmad Khalifa ACPI_RESOURCE_GPIO *gpio_res = &res->Data.Gpio;
11392adaa58SAhmad Khalifa struct acpi_gpiobus_ctx *ctx = context;
11492adaa58SAhmad Khalifa struct gpiobus_softc *super_sc = ctx->sc;
11592adaa58SAhmad Khalifa ACPI_HANDLE handle;
11692adaa58SAhmad Khalifa uint32_t flags, i;
11792adaa58SAhmad Khalifa
11892adaa58SAhmad Khalifa if (res->Type != ACPI_RESOURCE_TYPE_GPIO)
11992adaa58SAhmad Khalifa return (AE_OK);
12092adaa58SAhmad Khalifa
12192adaa58SAhmad Khalifa if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT,
12292adaa58SAhmad Khalifa gpio_res->ResourceSource.StringPtr, &handle)) ||
12392adaa58SAhmad Khalifa handle != ctx->dev_handle)
12492adaa58SAhmad Khalifa return (AE_OK);
12592adaa58SAhmad Khalifa
12692adaa58SAhmad Khalifa if (__predict_false(gpio_res->PinTableLength > super_sc->sc_npins)) {
12792adaa58SAhmad Khalifa device_printf(super_sc->sc_busdev,
12892adaa58SAhmad Khalifa "invalid pin table length %hu, max: %d (bad ACPI tables?)\n",
12992adaa58SAhmad Khalifa gpio_res->PinTableLength, super_sc->sc_npins);
13092adaa58SAhmad Khalifa return (AE_LIMIT);
13192adaa58SAhmad Khalifa }
13292adaa58SAhmad Khalifa
13392adaa58SAhmad Khalifa flags = acpi_gpiobus_convflags(gpio_res);
13492adaa58SAhmad Khalifa for (i = 0; i < gpio_res->PinTableLength; i++) {
13592adaa58SAhmad Khalifa UINT16 pin = gpio_res->PinTable[i];
13692adaa58SAhmad Khalifa
13792adaa58SAhmad Khalifa if (__predict_false(pin >= super_sc->sc_npins)) {
13892adaa58SAhmad Khalifa device_printf(super_sc->sc_busdev,
13992adaa58SAhmad Khalifa "invalid pin 0x%x, max: 0x%x (bad ACPI tables?)\n",
14092adaa58SAhmad Khalifa pin, super_sc->sc_npins - 1);
14192adaa58SAhmad Khalifa return (AE_LIMIT);
14292adaa58SAhmad Khalifa }
14392adaa58SAhmad Khalifa
14492adaa58SAhmad Khalifa GPIO_PIN_SETFLAGS(super_sc->sc_dev, pin, flags &
14592adaa58SAhmad Khalifa ~GPIO_INTR_MASK);
14692adaa58SAhmad Khalifa }
14792adaa58SAhmad Khalifa
14892adaa58SAhmad Khalifa return (AE_OK);
14992adaa58SAhmad Khalifa }
15092adaa58SAhmad Khalifa
151*9709bda0SColin Percival static struct acpi_gpiobus_ivar *
acpi_gpiobus_setup_devinfo(device_t bus,device_t child,ACPI_RESOURCE_GPIO * gpio_res)152*9709bda0SColin Percival acpi_gpiobus_setup_devinfo(device_t bus, device_t child,
153*9709bda0SColin Percival ACPI_RESOURCE_GPIO *gpio_res)
154*9709bda0SColin Percival {
155*9709bda0SColin Percival struct acpi_gpiobus_ivar *devi;
156*9709bda0SColin Percival
157*9709bda0SColin Percival devi = malloc(sizeof(*devi), M_DEVBUF, M_NOWAIT | M_ZERO);
158*9709bda0SColin Percival if (devi == NULL)
159*9709bda0SColin Percival return (NULL);
160*9709bda0SColin Percival resource_list_init(&devi->gpiobus.rl);
161*9709bda0SColin Percival
162*9709bda0SColin Percival devi->flags = acpi_gpiobus_convflags(gpio_res);
163*9709bda0SColin Percival if (acpi_quirks & ACPI_Q_AEI_NOPULL)
164*9709bda0SColin Percival devi->flags &= ~GPIO_PIN_PULLUP;
165*9709bda0SColin Percival
166*9709bda0SColin Percival devi->gpiobus.npins = 1;
167*9709bda0SColin Percival if (gpiobus_alloc_ivars(&devi->gpiobus) != 0) {
168*9709bda0SColin Percival free(devi, M_DEVBUF);
169*9709bda0SColin Percival return (NULL);
170*9709bda0SColin Percival }
171*9709bda0SColin Percival
172*9709bda0SColin Percival for (int i = 0; i < devi->gpiobus.npins; i++)
173*9709bda0SColin Percival devi->gpiobus.pins[i] = gpio_res->PinTable[i];
174*9709bda0SColin Percival
175*9709bda0SColin Percival return (devi);
176*9709bda0SColin Percival }
177*9709bda0SColin Percival
178*9709bda0SColin Percival static ACPI_STATUS
acpi_gpiobus_enumerate_aei(ACPI_RESOURCE * res,void * context)179*9709bda0SColin Percival acpi_gpiobus_enumerate_aei(ACPI_RESOURCE *res, void *context)
180*9709bda0SColin Percival {
181*9709bda0SColin Percival ACPI_RESOURCE_GPIO *gpio_res = &res->Data.Gpio;
182*9709bda0SColin Percival struct acpi_gpiobus_ctx *ctx = context;
183*9709bda0SColin Percival device_t bus = ctx->sc->sc_busdev;
184*9709bda0SColin Percival device_t child;
185*9709bda0SColin Percival struct acpi_gpiobus_ivar *devi;
186*9709bda0SColin Percival
187*9709bda0SColin Percival /* Check that we have a GpioInt object. */
188*9709bda0SColin Percival if (res->Type != ACPI_RESOURCE_TYPE_GPIO)
189*9709bda0SColin Percival return (AE_OK);
190*9709bda0SColin Percival if (gpio_res->ConnectionType != ACPI_RESOURCE_GPIO_TYPE_INT)
191*9709bda0SColin Percival return (AE_OK);
192*9709bda0SColin Percival
193*9709bda0SColin Percival /* Add a child. */
194*9709bda0SColin Percival child = device_add_child_ordered(bus, 0, "gpio_aei", DEVICE_UNIT_ANY);
195*9709bda0SColin Percival if (child == NULL)
196*9709bda0SColin Percival return (AE_OK);
197*9709bda0SColin Percival devi = acpi_gpiobus_setup_devinfo(bus, child, gpio_res);
198*9709bda0SColin Percival if (devi == NULL) {
199*9709bda0SColin Percival device_delete_child(bus, child);
200*9709bda0SColin Percival return (AE_OK);
201*9709bda0SColin Percival }
202*9709bda0SColin Percival device_set_ivars(child, devi);
203*9709bda0SColin Percival
204*9709bda0SColin Percival for (int i = 0; i < devi->gpiobus.npins; i++) {
205*9709bda0SColin Percival if (GPIOBUS_PIN_SETFLAGS(bus, child, 0, devi->flags)) {
206*9709bda0SColin Percival gpiobus_free_ivars(&devi->gpiobus);
207*9709bda0SColin Percival free(devi, M_DEVBUF);
208*9709bda0SColin Percival device_delete_child(bus, child);
209*9709bda0SColin Percival return (AE_OK);
210*9709bda0SColin Percival }
211*9709bda0SColin Percival }
212*9709bda0SColin Percival
213*9709bda0SColin Percival /* Pass ACPI information to children. */
214*9709bda0SColin Percival devi->dev_handle = ctx->dev_handle;
215*9709bda0SColin Percival
216*9709bda0SColin Percival return (AE_OK);
217*9709bda0SColin Percival }
218*9709bda0SColin Percival
21992adaa58SAhmad Khalifa static ACPI_STATUS
acpi_gpiobus_enumerate(ACPI_HANDLE handle,UINT32 depth,void * context,void ** result)22092adaa58SAhmad Khalifa acpi_gpiobus_enumerate(ACPI_HANDLE handle, UINT32 depth, void *context,
22192adaa58SAhmad Khalifa void **result)
22292adaa58SAhmad Khalifa {
22392adaa58SAhmad Khalifa UINT32 sta;
22492adaa58SAhmad Khalifa
22592adaa58SAhmad Khalifa /*
22692adaa58SAhmad Khalifa * If no _STA method or if it failed, then assume that
22792adaa58SAhmad Khalifa * the device is present.
22892adaa58SAhmad Khalifa */
22992adaa58SAhmad Khalifa if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) &&
23092adaa58SAhmad Khalifa !ACPI_DEVICE_PRESENT(sta))
23192adaa58SAhmad Khalifa return (AE_OK);
23292adaa58SAhmad Khalifa
23392adaa58SAhmad Khalifa if (!acpi_has_hid(handle))
23492adaa58SAhmad Khalifa return (AE_OK);
23592adaa58SAhmad Khalifa
23692adaa58SAhmad Khalifa /* Look for GPIO resources */
23792adaa58SAhmad Khalifa AcpiWalkResources(handle, "_CRS", acpi_gpiobus_enumerate_res, context);
23892adaa58SAhmad Khalifa
23992adaa58SAhmad Khalifa return (AE_OK);
24092adaa58SAhmad Khalifa }
24192adaa58SAhmad Khalifa
24292adaa58SAhmad Khalifa static ACPI_STATUS
acpi_gpiobus_space_handler(UINT32 function,ACPI_PHYSICAL_ADDRESS address,UINT32 length,UINT64 * value,void * context,void * region_context)24392adaa58SAhmad Khalifa acpi_gpiobus_space_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address,
24492adaa58SAhmad Khalifa UINT32 length, UINT64 *value, void *context, void *region_context)
24592adaa58SAhmad Khalifa {
24692adaa58SAhmad Khalifa ACPI_CONNECTION_INFO *info = context;
24792adaa58SAhmad Khalifa ACPI_RESOURCE_GPIO *gpio_res;
24892adaa58SAhmad Khalifa device_t controller;
24992adaa58SAhmad Khalifa ACPI_RESOURCE *res;
25092adaa58SAhmad Khalifa ACPI_STATUS status;
25192adaa58SAhmad Khalifa
25292adaa58SAhmad Khalifa status = AcpiBufferToResource(info->Connection, info->Length, &res);
25392adaa58SAhmad Khalifa if (ACPI_FAILURE(status) || res->Type != ACPI_RESOURCE_TYPE_GPIO)
25492adaa58SAhmad Khalifa goto err;
25592adaa58SAhmad Khalifa
25692adaa58SAhmad Khalifa gpio_res = &res->Data.Gpio;
25792adaa58SAhmad Khalifa controller = __containerof(info, struct acpi_gpiobus_softc,
25892adaa58SAhmad Khalifa handler_info)->super_sc.sc_dev;
25992adaa58SAhmad Khalifa
26092adaa58SAhmad Khalifa switch (function) {
26192adaa58SAhmad Khalifa case ACPI_WRITE:
26292adaa58SAhmad Khalifa if (__predict_false(
26392adaa58SAhmad Khalifa gpio_res->IoRestriction == ACPI_IO_RESTRICT_INPUT))
26492adaa58SAhmad Khalifa goto err;
26592adaa58SAhmad Khalifa
26692adaa58SAhmad Khalifa for (int i = 0; i < length; i++)
26792adaa58SAhmad Khalifa if (GPIO_PIN_SET(controller,
26892adaa58SAhmad Khalifa gpio_res->PinTable[address + i], (*value & 1 << i) ?
26992adaa58SAhmad Khalifa GPIO_PIN_HIGH : GPIO_PIN_LOW) != 0)
27092adaa58SAhmad Khalifa goto err;
27192adaa58SAhmad Khalifa break;
27292adaa58SAhmad Khalifa case ACPI_READ:
27392adaa58SAhmad Khalifa if (__predict_false(
27492adaa58SAhmad Khalifa gpio_res->IoRestriction == ACPI_IO_RESTRICT_OUTPUT))
27592adaa58SAhmad Khalifa goto err;
27692adaa58SAhmad Khalifa
27792adaa58SAhmad Khalifa for (int i = 0; i < length; i++) {
27892adaa58SAhmad Khalifa uint32_t v;
27992adaa58SAhmad Khalifa
28092adaa58SAhmad Khalifa if (GPIO_PIN_GET(controller,
28192adaa58SAhmad Khalifa gpio_res->PinTable[address + i], &v) != 0)
28292adaa58SAhmad Khalifa goto err;
28392adaa58SAhmad Khalifa *value |= v << i;
28492adaa58SAhmad Khalifa }
28592adaa58SAhmad Khalifa break;
28692adaa58SAhmad Khalifa default:
28792adaa58SAhmad Khalifa goto err;
28892adaa58SAhmad Khalifa }
28992adaa58SAhmad Khalifa
29092adaa58SAhmad Khalifa ACPI_FREE(res);
29192adaa58SAhmad Khalifa return (AE_OK);
29292adaa58SAhmad Khalifa
29392adaa58SAhmad Khalifa err:
29492adaa58SAhmad Khalifa ACPI_FREE(res);
29592adaa58SAhmad Khalifa return (AE_BAD_PARAMETER);
29692adaa58SAhmad Khalifa }
29792adaa58SAhmad Khalifa
29892adaa58SAhmad Khalifa static int
acpi_gpiobus_probe(device_t dev)29992adaa58SAhmad Khalifa acpi_gpiobus_probe(device_t dev)
30092adaa58SAhmad Khalifa {
30192adaa58SAhmad Khalifa device_t controller;
30292adaa58SAhmad Khalifa
30392adaa58SAhmad Khalifa if (acpi_disabled("gpiobus"))
30492adaa58SAhmad Khalifa return (ENXIO);
30592adaa58SAhmad Khalifa
30692adaa58SAhmad Khalifa controller = device_get_parent(dev);
30792adaa58SAhmad Khalifa if (controller == NULL)
30892adaa58SAhmad Khalifa return (ENXIO);
30992adaa58SAhmad Khalifa
31092adaa58SAhmad Khalifa if (acpi_get_handle(controller) == NULL)
31192adaa58SAhmad Khalifa return (ENXIO);
31292adaa58SAhmad Khalifa
31392adaa58SAhmad Khalifa device_set_desc(dev, "GPIO bus (ACPI-hinted)");
31492adaa58SAhmad Khalifa return (BUS_PROBE_DEFAULT);
31592adaa58SAhmad Khalifa }
31692adaa58SAhmad Khalifa
31792adaa58SAhmad Khalifa static int
acpi_gpiobus_attach(device_t dev)31892adaa58SAhmad Khalifa acpi_gpiobus_attach(device_t dev)
31992adaa58SAhmad Khalifa {
32092adaa58SAhmad Khalifa struct acpi_gpiobus_softc *sc;
32192adaa58SAhmad Khalifa struct acpi_gpiobus_ctx ctx;
32292adaa58SAhmad Khalifa ACPI_HANDLE handle;
32392adaa58SAhmad Khalifa ACPI_STATUS status;
32492adaa58SAhmad Khalifa int err;
32592adaa58SAhmad Khalifa
32692adaa58SAhmad Khalifa if ((err = gpiobus_attach(dev)) != 0)
32792adaa58SAhmad Khalifa return (err);
32892adaa58SAhmad Khalifa
32992adaa58SAhmad Khalifa sc = device_get_softc(dev);
33092adaa58SAhmad Khalifa handle = acpi_get_handle(sc->super_sc.sc_dev);
33192adaa58SAhmad Khalifa if (handle == NULL) {
33292adaa58SAhmad Khalifa gpiobus_detach(dev);
33392adaa58SAhmad Khalifa return (ENXIO);
33492adaa58SAhmad Khalifa }
33592adaa58SAhmad Khalifa
33692adaa58SAhmad Khalifa status = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GPIO,
33792adaa58SAhmad Khalifa acpi_gpiobus_space_handler, NULL, &sc->handler_info);
33892adaa58SAhmad Khalifa
33992adaa58SAhmad Khalifa if (ACPI_FAILURE(status)) {
34092adaa58SAhmad Khalifa device_printf(dev,
34192adaa58SAhmad Khalifa "Failed to install GPIO address space handler\n");
34292adaa58SAhmad Khalifa gpiobus_detach(dev);
34392adaa58SAhmad Khalifa return (ENXIO);
34492adaa58SAhmad Khalifa }
34592adaa58SAhmad Khalifa
34692adaa58SAhmad Khalifa ctx.dev_handle = handle;
34792adaa58SAhmad Khalifa ctx.sc = &sc->super_sc;
34892adaa58SAhmad Khalifa
34992adaa58SAhmad Khalifa status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
35092adaa58SAhmad Khalifa ACPI_UINT32_MAX, acpi_gpiobus_enumerate, NULL, &ctx, NULL);
35192adaa58SAhmad Khalifa
35292adaa58SAhmad Khalifa if (ACPI_FAILURE(status))
35392adaa58SAhmad Khalifa device_printf(dev, "Failed to enumerate GPIO resources\n");
35492adaa58SAhmad Khalifa
355*9709bda0SColin Percival /* Look for AEI children */
356*9709bda0SColin Percival status = AcpiWalkResources(handle, "_AEI", acpi_gpiobus_enumerate_aei,
357*9709bda0SColin Percival &ctx);
358*9709bda0SColin Percival
359*9709bda0SColin Percival if (ACPI_FAILURE(status))
360*9709bda0SColin Percival device_printf(dev, "Failed to enumerate GPIO resources\n");
361*9709bda0SColin Percival
36292adaa58SAhmad Khalifa return (0);
36392adaa58SAhmad Khalifa }
36492adaa58SAhmad Khalifa
36592adaa58SAhmad Khalifa static int
acpi_gpiobus_detach(device_t dev)36692adaa58SAhmad Khalifa acpi_gpiobus_detach(device_t dev)
36792adaa58SAhmad Khalifa {
36892adaa58SAhmad Khalifa struct gpiobus_softc *super_sc;
36992adaa58SAhmad Khalifa ACPI_STATUS status;
37092adaa58SAhmad Khalifa
37192adaa58SAhmad Khalifa super_sc = device_get_softc(dev);
37292adaa58SAhmad Khalifa status = AcpiRemoveAddressSpaceHandler(
37392adaa58SAhmad Khalifa acpi_get_handle(super_sc->sc_dev), ACPI_ADR_SPACE_GPIO,
37492adaa58SAhmad Khalifa acpi_gpiobus_space_handler
37592adaa58SAhmad Khalifa );
37692adaa58SAhmad Khalifa
37792adaa58SAhmad Khalifa if (ACPI_FAILURE(status))
37892adaa58SAhmad Khalifa device_printf(dev,
37992adaa58SAhmad Khalifa "Failed to remove GPIO address space handler\n");
38092adaa58SAhmad Khalifa
38192adaa58SAhmad Khalifa return (gpiobus_detach(dev));
38292adaa58SAhmad Khalifa }
38392adaa58SAhmad Khalifa
384*9709bda0SColin Percival int
gpio_pin_get_by_acpi_index(device_t consumer,uint32_t idx,gpio_pin_t * out_pin)385*9709bda0SColin Percival gpio_pin_get_by_acpi_index(device_t consumer, uint32_t idx,
386*9709bda0SColin Percival gpio_pin_t *out_pin)
387*9709bda0SColin Percival {
388*9709bda0SColin Percival struct acpi_gpiobus_ivar *devi;
389*9709bda0SColin Percival int rv;
390*9709bda0SColin Percival
391*9709bda0SColin Percival rv = gpio_pin_get_by_child_index(consumer, idx, out_pin);
392*9709bda0SColin Percival if (rv != 0)
393*9709bda0SColin Percival return (rv);
394*9709bda0SColin Percival
395*9709bda0SColin Percival devi = device_get_ivars(consumer);
396*9709bda0SColin Percival (*out_pin)->flags = devi->flags;
397*9709bda0SColin Percival
398*9709bda0SColin Percival return (0);
399*9709bda0SColin Percival }
400*9709bda0SColin Percival
401*9709bda0SColin Percival static int
acpi_gpiobus_read_ivar(device_t dev,device_t child,int which,uintptr_t * result)402*9709bda0SColin Percival acpi_gpiobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
403*9709bda0SColin Percival {
404*9709bda0SColin Percival struct acpi_gpiobus_ivar *devi = device_get_ivars(child);
405*9709bda0SColin Percival
406*9709bda0SColin Percival switch (which) {
407*9709bda0SColin Percival case ACPI_GPIOBUS_IVAR_HANDLE:
408*9709bda0SColin Percival *result = (uintptr_t)devi->dev_handle;
409*9709bda0SColin Percival break;
410*9709bda0SColin Percival default:
411*9709bda0SColin Percival return (gpiobus_read_ivar(dev, child, which, result));
412*9709bda0SColin Percival }
413*9709bda0SColin Percival
414*9709bda0SColin Percival return (0);
415*9709bda0SColin Percival }
416*9709bda0SColin Percival
41792adaa58SAhmad Khalifa static device_method_t acpi_gpiobus_methods[] = {
41892adaa58SAhmad Khalifa /* Device interface */
41992adaa58SAhmad Khalifa DEVMETHOD(device_probe, acpi_gpiobus_probe),
42092adaa58SAhmad Khalifa DEVMETHOD(device_attach, acpi_gpiobus_attach),
42192adaa58SAhmad Khalifa DEVMETHOD(device_detach, acpi_gpiobus_detach),
42292adaa58SAhmad Khalifa
423*9709bda0SColin Percival /* Bus interface */
424*9709bda0SColin Percival DEVMETHOD(bus_read_ivar, acpi_gpiobus_read_ivar),
425*9709bda0SColin Percival
42692adaa58SAhmad Khalifa DEVMETHOD_END
42792adaa58SAhmad Khalifa };
42892adaa58SAhmad Khalifa
42992adaa58SAhmad Khalifa DEFINE_CLASS_1(gpiobus, acpi_gpiobus_driver, acpi_gpiobus_methods,
43092adaa58SAhmad Khalifa sizeof(struct acpi_gpiobus_softc), gpiobus_driver);
43192adaa58SAhmad Khalifa EARLY_DRIVER_MODULE(acpi_gpiobus, gpio, acpi_gpiobus_driver, NULL, NULL,
43292adaa58SAhmad Khalifa BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
43392adaa58SAhmad Khalifa MODULE_VERSION(acpi_gpiobus, 1);
43492adaa58SAhmad Khalifa MODULE_DEPEND(acpi_gpiobus, acpi, 1, 1, 1);
435