Module Name: src Committed By: jmcneill Date: Wed Dec 11 01:00:02 UTC 2024
Modified Files: src/sys/dev/acpi: acpi_gpio.c acpi_gpio.h Log Message: acpi: gpio: Add GeneralPurposeIo address space handler for GPIO controllers To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/dev/acpi/acpi_gpio.c \ src/sys/dev/acpi/acpi_gpio.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/acpi/acpi_gpio.c diff -u src/sys/dev/acpi/acpi_gpio.c:1.2 src/sys/dev/acpi/acpi_gpio.c:1.3 --- src/sys/dev/acpi/acpi_gpio.c:1.2 Mon Dec 9 22:10:25 2024 +++ src/sys/dev/acpi/acpi_gpio.c Wed Dec 11 01:00:02 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_gpio.c,v 1.2 2024/12/09 22:10:25 jmcneill Exp $ */ +/* $NetBSD: acpi_gpio.c,v 1.3 2024/12/11 01:00:02 jmcneill Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -34,30 +34,133 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_gpio.c,v 1.2 2024/12/09 22:10:25 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_gpio.c,v 1.3 2024/12/11 01:00:02 jmcneill Exp $"); #include <sys/param.h> +#include <sys/kmem.h> #include <sys/gpio.h> +#include <dev/gpio/gpiovar.h> + #include <dev/acpi/acpireg.h> #include <dev/acpi/acpivar.h> #include <dev/acpi/acpi_gpio.h> -int +struct acpi_gpio_address_space_context { + ACPI_CONNECTION_INFO conn_info; /* must be first */ + struct acpi_devnode *ad; +}; + +static ACPI_STATUS +acpi_gpio_address_space_init(ACPI_HANDLE region_hdl, UINT32 function, + void *handler_ctx, void **region_ctx) +{ + if (function == ACPI_REGION_DEACTIVATE) { + *region_ctx = NULL; + } else { + *region_ctx = region_hdl; + } + return AE_OK; +} + +static ACPI_STATUS +acpi_gpio_address_space_handler(UINT32 function, + ACPI_PHYSICAL_ADDRESS address, UINT32 bit_width, UINT64 *value, + void *handler_ctx, void *region_ctx) +{ + ACPI_OPERAND_OBJECT *region_obj = region_ctx; + struct acpi_gpio_address_space_context *context = handler_ctx; + ACPI_CONNECTION_INFO *conn_info = &context->conn_info; + struct acpi_devnode *ad = context->ad; + ACPI_RESOURCE *res; + ACPI_STATUS rv; + struct gpio_pinmap pinmap; + int pins[1]; + void *gpiop; + int pin; + + if (region_obj->Region.Type != ACPI_TYPE_REGION) { + return AE_OK; + } + + if (ad->ad_gpiodev == NULL) { + return AE_NO_HANDLER; + } + + rv = AcpiBufferToResource(conn_info->Connection, + conn_info->Length, &res); + if (ACPI_FAILURE(rv)) { + return rv; + } + + if (res->Data.Gpio.PinTableLength != 1) { + /* TODO */ + aprint_debug_dev(ad->ad_gpiodev, + "Pin table length %u not implemented\n", + res->Data.Gpio.PinTableLength); + rv = AE_NOT_IMPLEMENTED; + goto done; + } + + pin = ad->ad_gpio_translate(ad->ad_gpio_priv, + &res->Data.Gpio, &gpiop); + if (pin == -1) { + /* Pin could not be translated. */ + rv = AE_SUPPORT; + goto done; + } + + pinmap.pm_map = pins; + if (gpio_pin_map(gpiop, pin, 1, &pinmap) != 0) { + rv = AE_NOT_ACQUIRED; + goto done; + } + if (function & ACPI_IO_MASK) { + gpio_pin_write(gpiop, &pinmap, 0, *value & 1); + } else { + *value = gpio_pin_read(gpiop, &pinmap, 0); + } + gpio_pin_unmap(gpiop, &pinmap); + +done: + ACPI_FREE(res); + + return rv; +} + +ACPI_STATUS acpi_gpio_register(struct acpi_devnode *ad, device_t dev, int (*translate)(void *, ACPI_RESOURCE_GPIO *, void **), void *priv) { + struct acpi_gpio_address_space_context *context; + ACPI_STATUS rv; + if (ad->ad_gpiodev != NULL) { device_printf(dev, "%s already registered\n", device_xname(ad->ad_gpiodev)); - return EBUSY; + return AE_ALREADY_EXISTS; + } + + context = kmem_zalloc(sizeof(*context), KM_SLEEP); + context->ad = ad; + + rv = AcpiInstallAddressSpaceHandler(ad->ad_handle, + ACPI_ADR_SPACE_GPIO, + acpi_gpio_address_space_handler, + acpi_gpio_address_space_init, + context); + if (ACPI_FAILURE(rv)) { + aprint_error_dev(dev, + "couldn't install address space handler: %s", + AcpiFormatException(rv)); + return rv; } ad->ad_gpiodev = dev; ad->ad_gpio_translate = translate; ad->ad_gpio_priv = priv; - return 0; + return AE_OK; } static ACPI_STATUS @@ -98,7 +201,7 @@ acpi_gpio_translate(ACPI_RESOURCE_GPIO * res, gpiop); if (xpin == -1) { /* Pin could not be translated. */ - return AE_NOT_IMPLEMENTED; + return AE_SUPPORT; } *pin = xpin; Index: src/sys/dev/acpi/acpi_gpio.h diff -u src/sys/dev/acpi/acpi_gpio.h:1.2 src/sys/dev/acpi/acpi_gpio.h:1.3 --- src/sys/dev/acpi/acpi_gpio.h:1.2 Mon Dec 9 22:10:25 2024 +++ src/sys/dev/acpi/acpi_gpio.h Wed Dec 11 01:00:02 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_gpio.h,v 1.2 2024/12/09 22:10:25 jmcneill Exp $ */ +/* $NetBSD: acpi_gpio.h,v 1.3 2024/12/11 01:00:02 jmcneill Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -32,7 +32,7 @@ #ifndef _DEV_ACPI_ACPI_GPIO_H #define _DEV_ACPI_ACPI_GPIO_H -int acpi_gpio_register(struct acpi_devnode *, device_t, +ACPI_STATUS acpi_gpio_register(struct acpi_devnode *, device_t, int (*)(void *, ACPI_RESOURCE_GPIO *, void **), void *); ACPI_STATUS acpi_gpio_get_int(ACPI_HANDLE, u_int, void **, int *, int *); ACPI_STATUS acpi_gpio_get_io(ACPI_HANDLE, u_int, void **, int *);