Device migrations, drivers and fixes (#571)

Device migrations:

- cyd-4848S040c
- guition-jc1060p470ciwy
- guition-jc2432w328c
- guition-jc3248w535c (known issue with display and touch, Shadowtrance will look into it)
- guition-jc8048w550c
- heltec-wifi-lora-32-v3
- lilygo-tdeck-max (excluding graphics)
- lilygo-tdisplay
- lilygo-tdisplay-s3
- lilygo-tdongle-s3
- lilygo-tlora-pager

Driver migrations:

- Implemented haptic driver interface in kernel
- AXS15231b
- BQ25896
- BQ27220
- CST328
- CST6xx
- DRV2605
- JD9165
- Custom LilyGO driver for T-Lora Pager
- SSD1306
- ST7701
- ST7735
- SY6970
- TCA8418

Fixes/improvements:

- Boot app: support for multiple power devices, improved UI
- lvgl_devices and related code: fixes for mapping
- Support for arrays in dts parser
This commit is contained in:
Ken Van Hoeylandt
2026-07-18 15:01:42 +02:00
committed by GitHub
parent 3b5a401594
commit d896657bf9
290 changed files with 9113 additions and 6719 deletions
@@ -161,7 +161,7 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], de
node_name = get_device_node_name_safe(device)
result = []
phandle_arrays = []
array_decls = []
for binding_property in binding_properties:
device_property = find_device_property(device, binding_property.name)
@@ -172,7 +172,35 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], de
array_var = f"{node_name}_{prop_safe}"
if device_property is not None:
entries = resolve_phandle_array_entries(device_property, devices)
phandle_arrays.append((array_var, binding_property.element_type, entries))
array_decls.append((array_var, binding_property.element_type, entries))
result.append(f"({binding_property.element_type}*){array_var}")
result.append(str(len(entries)))
elif binding_property.default is not None:
result.append("NULL")
result.append("0")
elif binding_property.required:
raise DevicetreeException(f"device {device.node_name} doesn't have property '{binding_property.name}'")
else:
result.append("NULL")
result.append("0")
continue
if binding_property.type == "array":
# A flat literal array (DTS `[ ... ]` syntax, e.g. a byte blob), as opposed to
# phandle-array's list of resolved device references. Emits the same
# (pointer, length) parameter pair, backed by a plain data array instead of one
# holding phandle-derived initializers.
if binding_property.element_type is None:
raise DevicetreeException(f"array property '{binding_property.name}' requires 'element-type' in binding")
prop_safe = binding_property.name.replace("-", "_")
array_var = f"{node_name}_{prop_safe}"
if device_property is not None:
if device_property.type != "array":
raise DevicetreeException(
f"Device '{device.node_name}' property '{binding_property.name}' must use '[ ... ]' array syntax"
)
entries = [str(value) for value in device_property.value]
array_decls.append((array_var, binding_property.element_type, entries))
result.append(f"({binding_property.element_type}*){array_var}")
result.append(str(len(entries)))
elif binding_property.default is not None:
@@ -207,17 +235,17 @@ def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], de
validate_property_range(device, binding_property, device_property.value)
result.append(property_to_string(device_property, devices))
return result, phandle_arrays
return result, array_decls
def write_config(file, device: Device, bindings: list[Binding], devices: list[Device], type_name: str):
node_name = get_device_node_name_safe(device)
config_type = f"{type_name}_config_dt"
config_variable_name = f"{node_name}_config"
config_params, phandle_arrays = resolve_parameters_from_bindings(device, bindings, devices)
config_params, array_decls = resolve_parameters_from_bindings(device, bindings, devices)
# Write phandle-array variables before the config struct
for array_var, element_type, entries in phandle_arrays:
# Write phandle-array/array variables before the config struct
for array_var, element_type, entries in array_decls:
entries_str = ", ".join(entries)
file.write(f"static {element_type} {array_var}[] = {{ {entries_str} }};\n")
@@ -209,6 +209,92 @@ def test_minmax_symbolic_value_skips_validation():
print("PASSED")
return True
def write_array_config(tmp_dir, device_property_line):
config_dir = os.path.join(tmp_dir, "array_data")
bindings_dir = os.path.join(config_dir, "bindings")
os.makedirs(bindings_dir)
with open(os.path.join(config_dir, "devicetree.yaml"), "w") as f:
f.write("dts: test.dts\nbindings: bindings")
with open(os.path.join(config_dir, "test.dts"), "w") as f:
f.write(f"""/dts-v1/;
/ {{
compatible = "test,root";
model = "Test Model";
test-device@0 {{
compatible = "test,array-device";
{device_property_line}
}};
}};
""")
with open(os.path.join(bindings_dir, "test,root.yaml"), "w") as f:
f.write("description: Test root binding\ncompatible: \"test,root\"\nproperties:\n model:\n type: string\n")
with open(os.path.join(bindings_dir, "test,array-device.yaml"), "w") as f:
f.write("""description: Test array binding
compatible: "test,array-device"
properties:
init-sequence:
type: array
element-type: uint8_t
""")
return config_dir
def test_array_property_generates_static_array_and_length():
print("Running test_array_property_generates_static_array_and_length...")
with tempfile.TemporaryDirectory() as tmp_dir:
config_dir = write_array_config(tmp_dir, "init-sequence = [0xFF 0x01 0x00 0x00 0x10 5 0];")
output_dir = os.path.join(tmp_dir, "output")
os.makedirs(output_dir)
result = run_compiler(config_dir, output_dir)
if result.returncode != 0:
print(f"FAILED: Compilation should have succeeded: {result.stderr} {result.stdout}")
return False
with open(os.path.join(output_dir, "devicetree.c")) as f:
generated = f.read()
if "static uint8_t test_device_init_sequence[] = { 0xFF, 0x01, 0x00, 0x00, 0x10, 5, 0 };" not in generated:
print(f"FAILED: Expected static array declaration not found:\n{generated}")
return False
if "(uint8_t*)test_device_init_sequence" not in generated or "\t7\n" not in generated:
print(f"FAILED: Expected (pointer, length) config params not found:\n{generated}")
return False
print("PASSED")
return True
def test_array_property_defaults_to_null_when_absent():
print("Running test_array_property_defaults_to_null_when_absent...")
with tempfile.TemporaryDirectory() as tmp_dir:
config_dir = write_array_config(tmp_dir, "")
output_dir = os.path.join(tmp_dir, "output")
os.makedirs(output_dir)
result = run_compiler(config_dir, output_dir)
if result.returncode != 0:
print(f"FAILED: Compilation should have succeeded: {result.stderr} {result.stdout}")
return False
with open(os.path.join(output_dir, "devicetree.c")) as f:
generated = f.read()
if "NULL,\n\t0" not in generated:
print(f"FAILED: Expected NULL/0 defaults not found:\n{generated}")
return False
print("PASSED")
return True
def test_compile_missing_config():
print("Running test_compile_missing_config...")
with tempfile.TemporaryDirectory() as output_dir:
@@ -234,7 +320,9 @@ if __name__ == "__main__":
test_minmax_below_minimum_fails,
test_minmax_above_maximum_fails,
test_minmax_out_of_range_default_fails,
test_minmax_symbolic_value_skips_validation
test_minmax_symbolic_value_skips_validation,
test_array_property_generates_static_array_and_length,
test_array_property_defaults_to_null_when_absent
]
failed = 0