U-Boot I2C Offset Width: An Explicit Suffix Changes the Next Unsuffixed Read
Two identical-looking U-Boot I2C read commands can produce different
bus transactions if an earlier command changed the chip’s offset width.
In the v2025.01 driver-model path, omitting an address-length suffix
means use the chip’s existing setting. It does not always restore a
one-byte default.
This article examines i2c read with
CONFIG_DM_I2C and the shared chip object. The offset is the
register or memory address sent inside a transaction, not the I2C slave
address. Repeated-start requirements, EEPROM page programming and bus
electrical recovery are separate topics.
Separate
the slave address from the offset representation
The command
implementation parses the chip address and internal offset
separately. An optional suffix on the offset selects its byte length. In
this command path, supported explicit suffix lengths are bounded by the
command’s own check.
For driver model, the missing-suffix default is a sentinel value
meaning that no offset-length update should be requested. The legacy
non-driver-model path instead supplies a one-byte default. Copying an
explanation from the legacy path therefore changes the meaning of an
unsuffixed command.
A useful transaction record includes bus identity, chip address,
internal offset, offset width, transfer length and relevant chip flags.
An address such as a register number is incomplete evidence without its
encoded width.

The width belongs to the
chip object
The I2C
uclass implementation stores offset_len in the chip’s
parent-platform data. i2c_set_chip_offset_len() validates
the maximum and assigns that field; it is not a temporary argument
attached only to one transaction.
The command obtains the chip object, applies an explicit length when
present, then calls dm_i2c_read(). It does not restore the
prior length afterward. If the same chip object is found by a later
unsuffixed read, that later command keeps the stored width.
This also applies when the explicit-width command subsequently fails
during transfer: the state update happened earlier. A failed bus
operation is not evidence that the chip configuration rolled back. Keep
the configuration result and transaction result separate when a
diagnostic sequence is repeated.
The uclass’s existing-chip lookup returns the already found object
without resetting its offset length to the lookup function’s default
argument. That distinction explains why the command’s helper passing a
nominal one-byte value does not undo a previous explicit setting.
Identify how the
initial value was created
For a device-tree-described chip, the inspected conversion path reads
u-boot,i2c-offset-len, defaulting to one when the property
is absent. A dynamically bound generic chip can receive an initial
length from its creation path. These are initialization sources, not
guarantees that the value remains unchanged for the entire boot.
Other users of the same object may also adjust its state. Therefore,
comparing two test runs requires their initialization and preceding
command history, not merely the final read line copied into a
report.
The ordinary transfer builder uses the current stored width to
construct the offset bytes. A zero width changes whether an
offset-address message is supplied; it should not be substituted for a
numeric offset of zero. Chip flags can select additional transfer
behavior, so this article does not promise an identical waveform across
every driver and flag combination.
Make the
diagnostic transaction self-describing
On a controlled fixture, compare a fresh unsuffixed read with an
explicit-width read followed by the same unsuffixed read. Inspect the
chip state or a permitted bus trace to establish which width was
actually consumed. Include an injected transfer failure after a valid
width update to test the no-rollback boundary.
Use the peripheral’s documented transaction format and safe readable
registers. Even a nominal read can have side effects on some devices, so
do not probe arbitrary live registers to discover the expected
width.
No I2C command or bus transaction was executed here. The
source-derived rule is that an explicit suffix changes shared per-chip
state in this driver-model command path; a later omitted suffix inherits
that state rather than erasing its history.