GPIO refactored (#495)

* **Refactor**
  * GPIO subsystem moved to a descriptor-based model for per-pin ownership and runtime pin management; many platform drivers now acquire/release descriptors.
  * Device trees and drivers now use GPIO phandle-style pin specifications across all boards and all drivers.

* **Behavior**
  * Device list now encodes per-device status (ok/disabled); boot will skip disabled devices accordingly.

* **Deprecation**
  * Legacy GPIO HAL marked deprecated and replaced with descriptor-based interfaces.

* **Chores**
  * Bindings and platform configs updated to the new GPIO pin-spec format.
This commit is contained in:
Ken Van Hoeylandt
2026-02-11 20:34:54 +01:00
committed by GitHub
parent dff93cb655
commit 26c17986c6
80 changed files with 1129 additions and 665 deletions
@@ -57,7 +57,7 @@ def find_phandle(devices: list[Device], phandle: str):
for device in devices:
if device.node_name == phandle or device.node_alias == phandle:
return f"&{get_device_node_name_safe(device)}"
raise DevicetreeException(f"phandle '{phandle}' not found in device tree")
raise DevicetreeException(f"phandle '{phandle}' not found in devicetree")
def property_to_string(property: DeviceProperty, devices: list[Device]) -> str:
type = property.type
@@ -77,6 +77,20 @@ def property_to_string(property: DeviceProperty, devices: list[Device]) -> str:
return "{ " + ",".join(value_list) + " }"
elif type == "phandle":
return find_phandle(devices, property.value)
elif type == "phandle-array":
value_list = list()
if isinstance(property.value, list):
for item in property.value:
if isinstance(item, PropertyValue):
value_list.append(property_to_string(DeviceProperty(name="", type=item.type, value=item.value), devices))
else:
value_list.append(str(item))
return "{ " + ",".join(value_list) + " }"
elif isinstance(property.value, str):
# If it's a string, assume it's a #define and show it as-is
return property.value
else:
raise Exception(f"Unsupported phandle-array type for {property.value}")
else:
raise DevicetreeException(f"property_to_string() has an unsupported type: {type}")
@@ -167,7 +181,15 @@ def write_device_structs(file, device: Device, parent_device: Device, bindings:
for child_device in device.devices:
write_device_structs(file, child_device, device, bindings, devices, verbose)
def write_device_init(file, device: Device, bindings: list[Binding], verbose: bool):
def get_device_status_variable(device: Device):
if device.status == "okay" or device.status is None:
return "DTS_DEVICE_STATUS_OKAY"
elif device.status == "disabled":
return "DTS_DEVICE_STATUS_DISABLED"
else:
raise DevicetreeException(f"Unsupported device status '{device.status}'")
def write_device_list_entry(file, device: Device, bindings: list[Binding], verbose: bool):
if verbose:
print(f"Processing device init code for '{device.node_name}'")
# Assemble some pre-requisites
@@ -177,11 +199,12 @@ def write_device_init(file, device: Device, bindings: list[Binding], verbose: bo
# Type & instance names
node_name = get_device_node_name_safe(device)
device_variable = node_name
status = get_device_status_variable(device)
# Write device struct
file.write("\t{ " f"&{device_variable}, \"{compatible_property.value}\"" " },\n")
file.write("\t{ " f"&{device_variable}, \"{compatible_property.value}\", {status}" " },\n")
# Write children
for child_device in device.devices:
write_device_init(file, child_device, bindings, verbose)
write_device_list_entry(file, child_device, bindings, verbose)
# Walk the tree and gather all devices
def gather_devices(device: Device, output: list[Device]):
@@ -201,6 +224,7 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin
file.write(dedent('''\
// Default headers
#include <tactility/device.h>
#include <tactility/dts.h>
// DTS headers
'''))
@@ -216,14 +240,11 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin
for item in items:
if type(item) is Device:
write_device_structs(file, item, None, bindings, devices, verbose)
# Init function body start
file.write("struct CompatibleDevice devicetree_devices[] = {\n")
# Init function body logic
file.write("struct DtsDevice dts_devices[] = {\n")
for item in items:
if type(item) is Device:
write_device_init(file, item, bindings, verbose)
# Init function body end
file.write("\t{ NULL, NULL },\n")
write_device_list_entry(file, item, bindings, verbose)
file.write("\tDTS_DEVICE_TERMINATOR\n")
file.write("};\n")
def generate_devicetree_h(filename: str):
@@ -231,12 +252,13 @@ def generate_devicetree_h(filename: str):
file.write(dedent('''\
#pragma once
#include <tactility/error.h>
#include <tactility/dts.h>
#ifdef __cplusplus
extern "C" {
#endif
extern struct CompatibleDevice devicetree_devices[];
extern struct DtsDevice dts_devices[];
#ifdef __cplusplus
}
@@ -8,6 +8,7 @@ class DtsVersion:
class Device:
node_name: str
node_alias: str
status: str
properties: list
devices: list
@@ -29,6 +29,7 @@ class DtsTransformer(Transformer):
def device(self, tokens: list):
node_name = None
node_alias = None
status = None
properties = list()
child_devices = list()
for index, item in enumerate(tokens):
@@ -37,10 +38,13 @@ class DtsTransformer(Transformer):
elif type(item) is Token and item.type == 'NODE_ALIAS':
node_alias = item.value
elif type(item) is DeviceProperty:
properties.append(item)
if item.name == "status":
status = item.value
else:
properties.append(item)
elif type(item) is Device:
child_devices.append(item)
return Device(node_name, node_alias, properties, child_devices)
return Device(node_name, node_alias, status, properties, child_devices)
def device_property(self, objects: List[object]):
name = objects[0]
# Boolean property has no value as the value is implied to be true