Skip to content

Commit e3dd051

Browse files
committed
acpi: gpio: Add GeneralPurposeIo address space handler for GPIO controllers
1 parent 54896b6 commit e3dd051

File tree

2 files changed

+111
-8
lines changed

2 files changed

+111
-8
lines changed

sys/dev/acpi/acpi_gpio.c

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: acpi_gpio.c,v 1.2 2024/12/09 22:10:25 jmcneill Exp $ */
1+
/* $NetBSD: acpi_gpio.c,v 1.3 2024/12/11 01:00:02 jmcneill Exp $ */
22

33
/*-
44
* Copyright (c) 2024 The NetBSD Foundation, Inc.
@@ -34,30 +34,133 @@
3434
*/
3535

3636
#include <sys/cdefs.h>
37-
__KERNEL_RCSID(0, "$NetBSD: acpi_gpio.c,v 1.2 2024/12/09 22:10:25 jmcneill Exp $");
37+
__KERNEL_RCSID(0, "$NetBSD: acpi_gpio.c,v 1.3 2024/12/11 01:00:02 jmcneill Exp $");
3838

3939
#include <sys/param.h>
40+
#include <sys/kmem.h>
4041
#include <sys/gpio.h>
4142

43+
#include <dev/gpio/gpiovar.h>
44+
4245
#include <dev/acpi/acpireg.h>
4346
#include <dev/acpi/acpivar.h>
4447
#include <dev/acpi/acpi_gpio.h>
4548

46-
int
49+
struct acpi_gpio_address_space_context {
50+
ACPI_CONNECTION_INFO conn_info; /* must be first */
51+
struct acpi_devnode *ad;
52+
};
53+
54+
static ACPI_STATUS
55+
acpi_gpio_address_space_init(ACPI_HANDLE region_hdl, UINT32 function,
56+
void *handler_ctx, void **region_ctx)
57+
{
58+
if (function == ACPI_REGION_DEACTIVATE) {
59+
*region_ctx = NULL;
60+
} else {
61+
*region_ctx = region_hdl;
62+
}
63+
return AE_OK;
64+
}
65+
66+
static ACPI_STATUS
67+
acpi_gpio_address_space_handler(UINT32 function,
68+
ACPI_PHYSICAL_ADDRESS address, UINT32 bit_width, UINT64 *value,
69+
void *handler_ctx, void *region_ctx)
70+
{
71+
ACPI_OPERAND_OBJECT *region_obj = region_ctx;
72+
struct acpi_gpio_address_space_context *context = handler_ctx;
73+
ACPI_CONNECTION_INFO *conn_info = &context->conn_info;
74+
struct acpi_devnode *ad = context->ad;
75+
ACPI_RESOURCE *res;
76+
ACPI_STATUS rv;
77+
struct gpio_pinmap pinmap;
78+
int pins[1];
79+
void *gpiop;
80+
int pin;
81+
82+
if (region_obj->Region.Type != ACPI_TYPE_REGION) {
83+
return AE_OK;
84+
}
85+
86+
if (ad->ad_gpiodev == NULL) {
87+
return AE_NO_HANDLER;
88+
}
89+
90+
rv = AcpiBufferToResource(conn_info->Connection,
91+
conn_info->Length, &res);
92+
if (ACPI_FAILURE(rv)) {
93+
return rv;
94+
}
95+
96+
if (res->Data.Gpio.PinTableLength != 1) {
97+
/* TODO */
98+
aprint_debug_dev(ad->ad_gpiodev,
99+
"Pin table length %u not implemented\n",
100+
res->Data.Gpio.PinTableLength);
101+
rv = AE_NOT_IMPLEMENTED;
102+
goto done;
103+
}
104+
105+
pin = ad->ad_gpio_translate(ad->ad_gpio_priv,
106+
&res->Data.Gpio, &gpiop);
107+
if (pin == -1) {
108+
/* Pin could not be translated. */
109+
rv = AE_SUPPORT;
110+
goto done;
111+
}
112+
113+
pinmap.pm_map = pins;
114+
if (gpio_pin_map(gpiop, pin, 1, &pinmap) != 0) {
115+
rv = AE_NOT_ACQUIRED;
116+
goto done;
117+
}
118+
if (function & ACPI_IO_MASK) {
119+
gpio_pin_write(gpiop, &pinmap, 0, *value & 1);
120+
} else {
121+
*value = gpio_pin_read(gpiop, &pinmap, 0);
122+
}
123+
gpio_pin_unmap(gpiop, &pinmap);
124+
125+
done:
126+
ACPI_FREE(res);
127+
128+
return rv;
129+
}
130+
131+
ACPI_STATUS
47132
acpi_gpio_register(struct acpi_devnode *ad, device_t dev,
48133
int (*translate)(void *, ACPI_RESOURCE_GPIO *, void **), void *priv)
49134
{
135+
struct acpi_gpio_address_space_context *context;
136+
ACPI_STATUS rv;
137+
50138
if (ad->ad_gpiodev != NULL) {
51139
device_printf(dev, "%s already registered\n",
52140
device_xname(ad->ad_gpiodev));
53-
return EBUSY;
141+
return AE_ALREADY_EXISTS;
142+
}
143+
144+
context = kmem_zalloc(sizeof(*context), KM_SLEEP);
145+
context->ad = ad;
146+
147+
rv = AcpiInstallAddressSpaceHandler(ad->ad_handle,
148+
ACPI_ADR_SPACE_GPIO,
149+
acpi_gpio_address_space_handler,
150+
acpi_gpio_address_space_init,
151+
context);
152+
if (ACPI_FAILURE(rv)) {
153+
aprint_error_dev(dev,
154+
"couldn't install address space handler: %s",
155+
AcpiFormatException(rv));
156+
return rv;
54157
}
55158

56159
ad->ad_gpiodev = dev;
57160
ad->ad_gpio_translate = translate;
58161
ad->ad_gpio_priv = priv;
59162

60-
return 0;
163+
return AE_OK;
61164
}
62165

63166
static ACPI_STATUS
@@ -98,7 +201,7 @@ acpi_gpio_translate(ACPI_RESOURCE_GPIO *res, void **gpiop, int *pin)
98201
res, gpiop);
99202
if (xpin == -1) {
100203
/* Pin could not be translated. */
101-
return AE_NOT_IMPLEMENTED;
204+
return AE_SUPPORT;
102205
}
103206

104207
*pin = xpin;

sys/dev/acpi/acpi_gpio.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: acpi_gpio.h,v 1.2 2024/12/09 22:10:25 jmcneill Exp $ */
1+
/* $NetBSD: acpi_gpio.h,v 1.3 2024/12/11 01:00:02 jmcneill Exp $ */
22

33
/*-
44
* Copyright (c) 2024 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
3232
#ifndef _DEV_ACPI_ACPI_GPIO_H
3333
#define _DEV_ACPI_ACPI_GPIO_H
3434

35-
int acpi_gpio_register(struct acpi_devnode *, device_t,
35+
ACPI_STATUS acpi_gpio_register(struct acpi_devnode *, device_t,
3636
int (*)(void *, ACPI_RESOURCE_GPIO *, void **), void *);
3737
ACPI_STATUS acpi_gpio_get_int(ACPI_HANDLE, u_int, void **, int *, int *);
3838
ACPI_STATUS acpi_gpio_get_io(ACPI_HANDLE, u_int, void **, int *);

0 commit comments

Comments
 (0)