Linux I2C Mux Topology: Adapter Trees, Locking, and Address Collisions
Model Linux I2C muxes as adapter trees and reason about channel selection, parent locking, nested topology, address collisions, and safe bus diagnostics.
An I2C mux is not just a switch that userspace toggles before every register access. Linux represents mux channels as child adapters in a topology tree. A client driver issues transfers to its adapter, and the mux framework selects a channel around the transfer. This model lets ordinary I2C client drivers operate behind muxes, gates, or arbiters without knowing the whole board wiring.
The abstraction has important concurrency rules. Mux drivers can use parent-locked or mux-locked behavior, and nested combinations can interleave transfers in ways that surprise board designers. An I2C operation may also have side effects: probing addresses can reset devices, trigger commands, or contend with an external bus master. Diagnose topology and ownership before issuing active scans.
Understand the adapter tree
The root adapter is backed by the actual controller that drives the physical bus. A mux channel appears as a child adapter; another mux can create further descendants. Each client is registered against one adapter and address. A transfer through a child adapter causes the mux framework to run the channel-selection operation, execute the transfer, and optionally run deselection.
The path is visible through sysfs and tooling:
i2cdetect -l
find /sys/bus/i2c/devices -maxdepth 2 -type l -print
ls -l /sys/class/i2c-adapter/
The -l option lists adapters; it is not the same as probing address ranges on a live bus. Avoid an active scan unless the device vendor confirms that probing is harmless. Some chips interpret reads or writes at particular addresses as state-changing operations.
Adapter numbers can vary across boots and probe order. Do not hard-code an adapter number as physical identity in a production application. Resolve the intended controller and mux channel using stable firmware descriptions, device paths, or board-specific labels, then verify the discovered topology after boot.
Channel select and deselect are part of the transfer
The mux driver may write a selection register over I2C before forwarding a client operation. A gate can open or close the route; an arbiter can coordinate an external master. An optional deselect step may restore a default channel or close the gate. The full operation is therefore a transaction over the adapter tree, not merely the client’s wire transfer.
If a mux-selection callback itself needs to issue an I2C transaction on the parent adapter, lock mode matters. The kernel documentation distinguishes mux-locked and parent-locked muxes. Mux-locked behavior protects muxes on the parent while permitting some unrelated parent transfers to interleave. Parent-locked behavior holds the parent adapter for the entire select-transfer-deselect sequence. These models have different deadlock and interleaving hazards.
Do not treat the names as a universal performance choice. The correct lock mode depends on how selection is implemented, whether it uses I2C transfers, and what state other channels share. A custom mux driver that recursively takes a lock already held by the core can deadlock. A mux that assumes exclusive use while unrelated transfers interleave may select the wrong channel or expose another device to a transaction.
Nested muxes need topology-aware reasoning
Consider two muxes on a shared root bus, each with a downstream device at the same address. If two non-sibling mux paths can interleave selection and transfer, one target may receive another device’s command. The adapter-tree abstraction does not remove physical address collisions; it routes transfers according to the topology and lock rules.
Nested muxes are valid, but not every arrangement is safe. The kernel documentation lists caveats for combinations of mux-locked and parent-locked devices, automatic-closing gates, and select operations that access the parent. Review the documented restrictions for the exact controller drivers in the target kernel. Do not infer the behavior from a logical device tree diagram alone.
For a board with an external bus master, arbitration must protect the same physical transaction the hardware expects. Linux locking coordinates Linux callers; it cannot by itself force an external controller to honor a software lock. The board may need a hardware arbitration signal or explicit ownership protocol.
Client registration and firmware description
Board firmware describes which client devices exist, their addresses, interrupt lines, supplies, and their relationship to mux channels. The I2C core creates adapters and clients from those descriptions and driver probes bind when a compatible driver is available. A missing client may indicate a firmware-description error, a mux probe failure, or a driver mismatch rather than a bad device.
Do not use dynamic userspace instantiation to bypass a missing board description unless the device is genuinely hot-pluggable and ownership is designed for it. Creating a client at the wrong adapter can target a different device with the same address. Before changing overlays or platform data, record the existing sysfs tree, kernel logs, controller driver, and channel-selection behavior.
The i2c-dev interface exposes raw transfers to userspace where enabled. It is useful for controlled diagnostics, but it bypasses much of the normal client-driver ownership model. Multiple userspace tools or a bound kernel driver can race over the same device. Restrict access and avoid raw register operations without a device-specific protocol reference.
Diagnose without damaging the bus
Begin with adapter listing, topology links, kernel probe messages, and the bound driver. Inspect whether the failing client is behind a mux and whether its child adapter exists. Capture the controller and mux driver versions, firmware description, root adapter, channel path, address, and whether the bus is shared with another master.
If a transfer hangs, identify whether the controller is waiting for bus idle, a mux-selection transaction failed, a device held SDA low, or an adapter lock is blocked. Correlate bus-level traces with driver logs. An I2C analyzer can reveal the physical transaction, but do not attach it in a way that adds capacitance or violates voltage constraints.
Never recover by blindly toggling reset, power, or a mux channel on a production board. A reset may affect unrelated clients, and switching the route while a transfer is active can corrupt state. Use the documented controller recovery procedure in a maintenance window and preserve the pre-change evidence.
When a transfer times out, distinguish a physical bus-stuck condition from a software lock wait. If SCL or SDA remains low, the controller may be unable to complete a STOP condition; a supported bus-recovery routine may clock or reset the bus, but it can also disturb every client sharing that wireset. If sysfs and logs show the adapter still registered but requests stop progressing, collect task stacks or lock diagnostics through approved kernel debugging instead of repeatedly issuing transactions.
Mux select and deselect failures should be reported with the child adapter and parent path, not only the client address. Two clients can legitimately share an address behind different channels. A log that says only address 0x50 hides which EEPROM or sensor was actually selected. Include the channel-selection result, transfer errno, and whether cleanup ran after failure.
Production acceptance should include a concurrency test that drives independent sibling channels while checking a known transaction counter or bus analyzer trace. The test should also exercise the error path after selection, so the next client is not left on an unintended channel. Where a mux has an auto-closing gate, verify exactly which transfer consumes the open window and whether unrelated activity can interleave.
Acceptance tests for a topology
On a development board, verify each declared child adapter and client appears at the expected path. Exercise one client at a time, then concurrent operations on sibling channels. Test select and deselect failures, parent bus recovery, device suspend and resume, and kernel probe ordering. If the board supports a second master, test arbitration under coordinated ownership rather than simultaneous uncontrolled writes.
Acceptance evidence should state the physical wiring, adapter tree, lock mode for each mux, address reuse across channels, firmware description, controller and mux driver, test sequence, and any transfer interleaving observed. The application should fail with a useful error if a device is absent instead of silently choosing another adapter with the same numeric ID.
The Linux I2C mux framework is a concurrency and topology abstraction layered on a physical serial bus. Its safety depends on modeling the actual parent-child graph, understanding select-transfer-deselect locking, and respecting other bus owners. That is more reliable than treating adapter numbers as permanent wires.
Related:
- Linux Device Runtime PM: Usage Counts, Autosuspend, and Callback Order
- Building and Loading Your Own Linux Kernel Module
Sources: