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 *);