Creating Templates from Kernel Bindings
This guide walks through creating a new device template starting from
a Linux kernel device tree binding. The tooling in scripts/ can
parse bindings, extract compatible strings and properties, and generate
starter template stubs — reducing the manual work to filling in
device-specific details.
Overview
The workflow has seven steps:
Step 1: Parse kernel bindings
Clone the ADI Linux kernel (or point to an existing checkout):
git clone https://github.com/analogdevicesinc/linux.git /path/to/linux
Run the binding collector to discover all ADI bindings:
python3 scripts/collect_adi_bindings.py \
--linux /path/to/linux \
--output bindings_report.json \
--markdown bindings_report.md
This produces a JSON report listing every ADI binding file with its compatible strings and properties.
Step 2: Audit against existing templates
Run the audit to find which bindings are already supported and which need templates:
python3 scripts/audit_adi_bindings.py \
--linux /path/to/linux \
--project .
The audit classifies each binding as:
Known — compatible string already in a template or profile
Partial — some compatible strings documented, others not
Undocumented — no template exists for this device
Step 3: Generate starter templates
Add --generate-templates to create stub files for undocumented
devices:
python3 scripts/audit_adi_bindings.py \
--linux /path/to/linux \
--project . \
--generate-templates
This creates starter .tmpl files in adidt/templates/xsa/ with
boilerplate structure:
// SPDX-License-Identifier: GPL-2.0
// AUTOGENERATED STARTER TEMPLATE — requires manual review
// Source binding: Documentation/devicetree/bindings/iio/imu/adi,adis16495.yaml
//
// TODO:
// - Replace placeholder nodes, clocks, GPIOs, interrupts
// - Add board-specific wiring
// - Review ADI properties from binding YAML
&spi_bus {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
device@0 {
compatible = "adi,adis16495-1";
reg = <0>;
spi-max-frequency = <2000000>;
/* TODO: Add clocks, interrupts, and device properties */
};
};
Step 4: Refine the template
The generated stub is a starting point. Open the binding YAML to see what properties the driver expects:
cat /path/to/linux/Documentation/devicetree/bindings/iio/imu/adi,adis16495.yaml
A typical YAML binding looks like:
properties:
compatible:
enum:
- adi,adis16495-1
- adi,adis16495-2
- adi,adis16495-3
- adi,adis16497-1
reg:
maxItems: 1
spi-max-frequency:
maximum: 2000000
spi-cpol: true
spi-cpha: true
interrupts:
maxItems: 1
Convert these into a Jinja2 template with conditional properties:
{{ label }}: {{ device }}@{{ cs }} {
compatible = "{{ compatible }}";
reg = <{{ cs }}>;
spi-max-frequency = <{{ spi_max_hz }}>;
{%- if spi_cpol %}
spi-cpol;
{%- endif %}
{%- if spi_cpha %}
spi-cpha;
{%- endif %}
{%- if interrupt_gpio is not none %}
interrupt-parent = <&{{ gpio_label }}>;
interrupts = <{{ interrupt_gpio }} {{ irq_type }}>;
{%- endif %}
};
Key rules for templates:
Use tabs for indentation (DTS convention)
Use
{%- if x is not none %}(not truthiness) for optional propertiesPre-format multi-value strings in the context builder, not in the template
Keep the closing
};at the same indentation as the opening label
Step 5: Write the context builder
Add a function to adidt/model/contexts.py that maps device
parameters to template variables:
def build_adis16495_ctx(
*,
label: str = "imu0",
device: str = "adis16495",
compatible: str = "adi,adis16495-1",
cs: int = 0,
spi_max_hz: int = 2_000_000,
spi_cpol: bool = True,
spi_cpha: bool = True,
gpio_label: str = "gpio",
interrupt_gpio: int | None = None,
irq_type: str = "IRQ_TYPE_EDGE_FALLING",
) -> dict:
"""Build context dict for ``adis16495.tmpl``."""
return {
"label": label,
"device": device,
"compatible": compatible,
"cs": cs,
"spi_max_hz": spi_max_hz,
"spi_cpol": spi_cpol,
"spi_cpha": spi_cpha,
"gpio_label": gpio_label,
"interrupt_gpio": interrupt_gpio,
"irq_type": irq_type,
}
Use keyword-only arguments (*) with sensible defaults from the
binding’s default or maximum fields.
Step 6: Add a component factory
Add a factory function to adidt/model/components.py so users don’t
need to know template filenames:
def adis16495(spi_bus: str = "spi0", cs: int = 0, **kwargs) -> ComponentModel:
"""ADIS16495 6-DOF IMU."""
config = contexts.build_adis16495_ctx(cs=cs, **kwargs)
return ComponentModel(
role="imu",
part="adis16495",
template="adis16495.tmpl",
spi_bus=spi_bus,
spi_cs=cs,
config=config,
)
Step 7: Write tests
Add tests to verify the template renders correctly:
from adidt.model import BoardModel, components
from adidt.model.renderer import BoardModelRenderer
def test_adis16495_renders():
model = BoardModel(
name="test", platform="test",
components=[
components.adis16495(spi_bus="spi0", cs=0, interrupt_gpio=25),
],
)
nodes = BoardModelRenderer().render(model)
out = nodes["converters"][0]
assert 'compatible = "adi,adis16495-1"' in out
assert "spi-cpol" in out
assert "interrupts = <25" in out
Run with:
python3 -m pytest test/test_adis16495.py -v
Reference: what the tools extract
The binding parser (scripts/adi_binding_lib.py) extracts:
Field |
Extracted? |
Notes |
|---|---|---|
Compatible strings |
Yes |
From YAML |
Property names |
Yes |
|
Property types |
No |
YAML has type info (uint32, string, bool) but not extracted |
Default values |
No |
YAML |
Required vs optional |
No |
YAML |
Descriptions |
No |
Prose descriptions not extracted |
For properties not automatically extracted, check the binding YAML
directly. The properties section lists every valid property with
its type, constraints, and description.
Tips
Start simple. A template with just
compatible,reg,spi-max-frequency, and an interrupt covers most simple SPI devices. Add properties incrementally.Check the driver source. The Linux driver’s
of_match_tableandprobefunction show exactly which DT properties are read. Path:drivers/iio/<subsystem>/<device>.cTest with dtc. Compile your template output to verify syntax:
dtc -@ -I dts -O dtb -o /dev/null my_overlay.dts
Use existing templates as reference. The
adidt/templates/xsa/directory has 35+ templates covering simple SPI devices to complex JESD204 transceivers.