A raw capture through v4l2-ctl delivers frames, but the platform's ISP camera stack lists no camera and logs V4L2Device not available. That combination rules out wiring and driver probing: the sensor came up, the CSI link is up, and the video node exists. It is a naming mismatch between two layers — the device tree description of each camera module and the V4L2 subdev name the kernel actually registered. This guide shows how the stack matches modules by name string, how to read both names in two commands, and how to fix the devname property and hold the I2C bus numbering still across reflashes. It is written for engineers bringing up MIPI sensors on embedded Linux capture platforms, where the camera subsystem is described in the device tree rather than enumerated.
What the symptom tells you
v4l2-ctl --list-devices shows both sensors: a vi-output, ox08b40 0-0030 node on /dev/video0, a vi-output, ox08b40 0-0031 node on /dev/video1, and one media device for the capture pipeline. Stream a few raw frames from the video node and they arrive. Then the camera service starts, walks the platform's camera module list, and fails every camera open with the same two lines:
Error ModuleNotPresent: V4L2Device not available
SCF: Error BadParameter: Sensor could not be opened.
Both imager GUIDs fail with error 0xA000E, the provider initializes with no cameras in it, and the application exits.
The two observations do not contradict each other. The raw V4L2 path needs only the kernel media graph, which is fully up. The camera stack resolves cameras through the platform description in the device tree and matches each module to a live kernel device by name string. The kernel graph is healthy; the match comes back empty.
Two names for one sensor
On the kernel side, a MIPI sensor is an I2C client. When its driver probes, the kernel registers a V4L2 sub-device and names it from three facts: the driver name, the adapter index and the client address — driver, space, bus number, hyphen, then the address as four lowercase hex digits. A sensor whose driver is ox08b40, sitting on adapter 0 at address 0x30, becomes the subdev ox08b40 0-0030, and its capture node becomes vi-output, ox08b40 0-0030. In the kernel's model, these subdevs are the kernel-side view of the sensor and the CSI receiver, which is why the stack must name them to open them.
On the stack side, the camera platform description in the device tree lists one module entry per camera. A module carries a badge, a position, an orientation and one or more drivernode entries. Each drivernode has three values: a pcl_id naming the role — sensor driver nodes carry the string v4l2_sensor — a devname that must equal the live subdev name, and a proc-device-tree path pointing at the sensor's own node. The comparison is literal: every character counts, including the space between driver name and bus token. One stale character, and the stack treats that camera as absent no matter how healthy the graph looks in media-ctl -p.
Likely causes, in order of probability
- The I2C bus renumbered. The declared devname names adapter 2 while the kernel registered the sensor on adapter 0 — the case the worked example below walks through. This shows up when the platform file was written for another board revision or copied from a carrier whose controllers probe in a different order.
- The address token is wrong. A typo in the address, a missing zero in the four-digit padding, or two identical sensors whose entries were swapped so both modules claim 0x30. When two sensors genuinely share one address, the two image sensors with the same I2C address case covers the bus options.
- The proc-device-tree path is stale. It points at a sensor node that was renamed or moved in the device tree source, so the module resolves to nothing.
- The pcl_id or the drivernode entry is wrong. A missing or mistyped role tag leaves the module without a kernel device to bind, with the same log as a devname mismatch.
In practice the first cause accounts for most of these tickets; the others produce the identical log and fall to the same two-read test.
Confirm the mismatch in two reads
-
Read the live names.
v4l2-ctl --list-devicesprints every capture node with the subdev name embedded in it;media-ctl -d /dev/media0 -pprints the same names as media graph entities. Note the exact string per sensor, bus token included. - Read the declared names. Each module's drivernode directory under /proc/device-tree holds a devname file. This loop prints path and value together; the glob matches the camera-platform directory whatever your platform calls it:
for f in /proc/device-tree/*/modules/*/drivernode0/devname; do
printf '%s: ' $f; tr -d '\0' < $f; echo
done
- Compare token by token. Driver name, bus number, address. A differing bus token is flash-time renumbering; a differing address token is a typo or a swapped pair. If every string matches, the failure is not the devname — the last section lists the neighbors.
Fix: set devname to the name the kernel registers
Edit the device tree source, not the running board. In the affected module's drivernode entry, set devname to the exact live string from the first read, rebuild the DTB, install it the way your build flow does and reboot. Leave pcl_id and proc-device-tree exactly as the reference platform file has them: on this class of failure only the bus-address token changes.
After the reboot, run both reads again: the camera service should enumerate the expected number of cameras and raw capture should still deliver frames. Where a platform documents an override file for camera modules, use that mechanism instead of patching a generated DTB — it survives the next flash.
Worked example: two sensors declared on I2C bus 2, registered on bus 0
Inputs. Two identical sensors, driver ox08b40, at I2C addresses 0x30 (decimal 48) and 0x31 (decimal 49), streaming SBGGR12_1X12 at 3840 × 2160; the pad format comes off the media graph printout. Kernel side, the graph shows subdev ox08b40 0-0030 on /dev/v4l-subdev2 and ox08b40 0-0031 on /dev/v4l-subdev3, feeding /dev/video0 and /dev/video1 — both sensors live on adapter 0. Device tree side, module0 declares devname ox08b40 2-0030 with proc-device-tree /proc/device-tree/i2c@3160000/ox08b40_a@30, and module1 declares devname ox08b40 2-0031 with proc-device-tree /proc/device-tree/i2c@3160000/ox08b40_c@31.
Rule. The stack opens a module only when its devname equals the registered subdev name character for character.
Arithmetic. The address 0x30 is 48 decimal; the kernel renders a client address as four lowercase hex digits, so 0x30 becomes 0030, and the name assembles as adapter index 0 plus 0030: 0-0030. The declared token names adapter 2: 2-0030. Compare: 0-0030 differs from 2-0030 in exactly one token. The string comparison fails for module0 and module1 alike, both imager GUIDs fail with V4L2Device not available and error 0xA000E, and the stack reports zero cameras.
Decision. Set the two devname values to ox08b40 0-0030 and ox08b40 0-0031, rebuild the DTB and reboot. The build passes when the camera service enumerates two cameras and raw capture still returns 3840 × 2160 frames. If GUID 1 still fails after the fix, its module entry still carries the old bus token — check both drivernodes, not only module0.
Why the bus number moved, and how to pin it
I2C adapter indexes are handed out in the order the controllers register, not fixed by hardware. Enable or disable a controller, change the boot sequence, or move to a build whose drivers probe in a different order, and a sensor node written for bus 2 lands on bus 0 with its device tree source untouched. That is why the same files flash fine on one board revision and miss on the next.
The device tree's standard mechanism for holding numbering still is alias entries at the root, which assign each controller a fixed index; on platforms that honor them, the sensor keeps its bus across updates. Whatever your build does, keep the two-read comparison in the bring-up checklist — a renumbering then surfaces as a two-line diff instead of a morning spent reading daemon logs.
When the failure is not the devname
The same service log with a different root cause, in the order worth testing:
- No vi-output node at all. The sensor driver never probed, so there is no subdev for the stack to name. The camera driver device tree mismatch: diagnose missing DTBs guide covers the missing-driver side, and sensor detected but frames time out: separating I2C from MIPI failures covers a probe that succeeds but capture that stalls.
- Video works, controls return nothing. Controls live on the node the driver registered, which is not always the video node you opened; the v4l2-ctl list-ctrls returns nothing case walks that check.
- The camera opens, then the stream comes up green or the ISP crashes. The name match now passes and the failure has moved downstream; for ox08b40-class sensors, the OX08B40 ISP activation crash and green screen fix covers that stage on the same sensor family.
None of this device-tree naming applies once the design moves to standard industrial cameras. GigE and USB3 area scan cameras are discovered by enumeration over the link, and a USB3 board-level camera in an embedded build that bypasses the platform ISP has no devname to go stale.
Closing checks
- Every module's devname equals its live subdev name — in a two-sensor build, check both drivernodes, not only module0.
- The DTB was rebuilt from source and installed; nothing was patched under /proc/device-tree at runtime.
- Raw capture still returns frames after the reflash.
- The camera service enumerates the expected camera count, one module per sensor.
- The I2C bus numbering is pinned with aliases or recorded in the integration notes, so the next reflash cannot renumber the sensors.
When the project moves from CSI sensors to industrial cameras, the camera finder filters GigE, USB3 and CoaXPress models by sensor format, mount and shutter, and the build a system configurator pairs camera, lens and light from one set of inputs. The systems guides collect the neighboring device-tree and streaming failures, and specific integration questions go through the contact page.
Questions
Why does raw V4L2 capture work when the ISP stack reports no camera?
The raw path needs only the kernel media graph: the sensor subdev, the CSI link and the video node, and it never consults the platform description. The ISP stack ignores those nodes and resolves cameras through the device tree module list, matching each devname against the live subdev name as a plain string. One stale character in that string streams raw frames fine while the stack reports zero cameras.
Why did the sensor's I2C bus number change after flashing?
Adapter indexes are handed out in registration order, not baked into the hardware. A new build can enable or probe controllers in a different sequence, so a sensor whose node was written for bus 2 lands on bus 0. Aliases in the device tree root pin indexes on platforms that honor them; list /sys/bus/i2c/devices before and after an update to see your numbering.
Can I correct the devname by editing /proc/device-tree directly?
You can write the file, but it will not last: /proc/device-tree is the kernel's rendering of the flashed DTB and returns to the old value at the next boot. The durable fix is in the device tree source, rebuilt and installed. Some platforms document override or overlay files for camera modules; prefer that documented mechanism where it exists.
What does pcl_id = v4l2_sensor mean in a camera module entry?
It tags the role a drivernode plays, and the stack loads the matching driver for that role. Sensor entries carry v4l2_sensor; other roles, such as a focus actuator, carry their own tags in the same reference layout. A wrong tag or a missing drivernode entry fails the module in much the same way as a devname mismatch does.
Does a wrong devname also break USB3 or GigE Vision cameras?
No. USB3 Vision and GigE Vision cameras are discovered by enumeration over the link, with the host reading their identity at connect time, so no device tree name string is involved. A devname mismatch is specific to platforms whose camera description in the device tree must name the kernel-side device. A USB3 camera that drops off fails for link, power or cable reasons instead.