Display backlight node
nodes/backlight puts a display module’s backlight and the sensors on the module onto the bus:
- status out: brightness, the driver’s own state, ambient light and temperatures;
- brightness in: a single service that sets it.
All of the file reading lives in libs/display_backlight. The node adds the config, a thread for the light sensors and the schema translation.
It deliberately does not:
- Turn the backlight on or off. The panel needs valid video before LED_EN, and
redline-display-backlight.servicehandles that ordering. This node writesbrightnessand nothing else. - Dim automatically. The lux-to-brightness curve is still a product decision. The sensors are published so that whatever makes that decision can read them.
redline-display monitorhas a placeholder curve. It ships disabled and must stay disabled while anything callsset_brightness, or the two will fight over the value. - Detect anything. The rootfs does detection at boot.
Inputs
The node reads the record redline-display-setup writes for its role, at /run/redline/displays/<role>. As a real boot on the LattePanda wrote it:
[display]
role=primary
name=Rivian Gen1 IC, LG LA123WF9-SL07, 1920x720
connector=HDMI-A-2
[backlight]
type=lp8863
device=/sys/class/backlight/lp8863
max=65535
[sensors]
ambient_light=/sys/bus/iio/devices/iio:device0 /sys/bus/iio/devices/iio:device1
temperature=/sys/class/hwmon/hwmon1 /sys/class/hwmon/hwmon2
What it reads from each of those, with the values seen on the board on 2026-09-12:
| Device | Attributes |
|---|---|
backlight class (lp8863_bl) | brightness 24576, actual_brightness 24576, max_brightness 65535, bl_power 0, type raw |
lp8863 driver (<device>/device/) | faults 0x0000 0x0000 0x0800, fsm_state 0xd NORMAL, led_current 0x0fff, pwm_output 0x6000, boost 0x0549 |
IIO (opt3001 ×2) | name, in_illuminance_input 3.42 / 2.12 lux |
hwmon (tmp1075 ×2) | name, temp1_input 45187 / 44500 m°C (no label) |
Every attribute is optional. A different module’s drivers will expose a different subset, and a missing attribute is reported as absent, never as zero.
No record means no module was detected in that slot this boot. That is the normal state of any machine without one, so the node logs one line and exits 0, and Restart=on-failure does not loop.
device=serializer means no kernel driver owns the backlight and the rootfs drives it through the serializer. In that case the node still publishes the sensors, sets writable=false, and refuses set_brightness.
Topics
The schema is schemas/display_backlight.capnp, and the prefix defaults to nodes/backlight/<role>.
| Key | Schema | |
|---|---|---|
<prefix>/status | DisplayBacklightStatus | on change, and every 2 s |
<prefix>/set_brightness | DisplayBrightnessRequest → DisplayBrightnessResponse | service |
inspect echo nodes/backlight/primary/status -n 1
inspect call nodes/backlight/primary/set_brightness -d '{"unit":"percent","value":20}'
inspect call nodes/backlight/primary/set_brightness -d '{"unit":"raw","value":13107}'
The status is published when something moves past its deadband: any change to the backlight attributes, a light sensor by 5 % (never less than 0.05 lux), a temperature by 0.5 °C, or a sensor appearing or going missing. Otherwise it is published every 2 s. The backlight is read every poll_ms, the light sensors every second and the temperatures every 5 s.
The light sensors are read on their own thread, and the status carries the latest value. An opt3001 read blocks for the whole conversion: at the driver’s default 0.8 s integration time each read took about a second on the board, and with two sensors inline that held set_brightness up for about 2 s. So at start the node writes light_integration_time to each sensor’s in_illuminance_integration_time. If a sensor has no such attribute it is left alone, and if the write fails the node logs it and carries on.
A request is clamped to between min_percent of max_brightness and max_brightness. The response gives the raw value actually applied and, when the clamp changed it, says so. Clamping up to min_percent stops a slider or a remote from turning the panel off by accident, since a backlight at zero looks exactly like a dead display.
Health
nodes/backlight/health (NodeHealth), once a second and at once on any change:
| Check | Not ok when |
|---|---|
backlight | the backlight device is not writable, so brightness cannot be set |
inspect health prints them.
Config
configs/backlight/backlight.yaml:
role: primary # names the record file
record_dir: /run/redline/displays # point at a fake tree to run off the target
# topic_prefix: nodes/backlight/primary
poll_ms: 500 # how often the backlight is read
min_percent: 1
light_integration_time: 0.1 # seconds; 0 leaves the driver's
On the target
The node runs as an instance of the redline-node@.service template:
- the binary is
/opt/redline/bin/backlight; - its arguments come from
/opt/redline/nodes/backlight.args, or from/data/nodes/backlight.args, which takes precedence:
REDLINE_NODE_ARGS=--config /opt/redline/configs/backlight/backlight.yaml
The unit runs as root, which is what writing brightness requires.
Running it without the hardware
display_backlight_test_record and display_backlight_test_sysfs build a fake /sys tree under a temp directory, matching the board. To run the whole node the same way, create a directory tree with the attribute files above, write a record whose paths point into it, and set record_dir to the directory holding that record. inspect echo then shows the status, and set_brightness rewrites the fake brightness file.
Not done yet
clear_faultsis not wired. The driver exposes it as a write-only attribute, and what value it expects has not been checked against thelp8863_blsource.- Nothing sets brightness automatically. See above.
The Yocto side needs to install the node and its args file and enableDone 2026-09-12:redline-node@backlight.redline-nodesshipsbacklight.argsand a drop-in ordering the instance afterredline-display-setupandredline-display-backlight; the lattepanda-mu machine enables it (REDLINE_ENABLED_NODES).