NVMEM Provider Device Tree Bindings-Free Linux Device Drivers Course

NVMEM Provider Device Tree Bindings

Free Linux Device Drivers Course — NVMEM Framework, Part 4

Chapter 12 · Lecture 4
NVMEM Framework
Kernel 6.x APIs
nvmem device tree bindings nvmem-cells nvmem-cell-names free linux device drivers course free embedded systems course free embedded linux course

So far in this free embedded systems course we’ve written the C side of an NVMEM provider — registration, cells, and read/write callbacks. None of that storage is useful to a consumer driver until it’s described somewhere discoverable, and on any DT-based platform that description lives in the device tree. This lecture covers NVMEM device tree bindings: how a provider node declares its storage as child cell nodes, and how a completely unrelated consumer node references those cells by name using nvmem-cells and nvmem-cell-names.

What You Will Learn

  • Why NVMEM providers don’t get their own top-level DT binding
  • How child nodes under a provider become individual data cells
  • The reg and optional bits cell properties, byte-level and bit-level
  • How consumer nodes bind to named cells with nvmem-cells / nvmem-cell-names
  • A complete original DT example: an MMIO fuse-box provider and an unrelated consumer node

Prerequisites

  • struct nvmem_cell_info and software-declared cells from Lecture 2 of this chapter
  • Basic device tree syntax: nodes, reg, #address-cells/#size-cells, phandles

Providers Borrow Their Parent’s Binding

The first thing to internalize is that NVMEM, as a framework, does not define its own device tree binding for the provider node itself. An NVMEM provider is described purely in terms of whatever bus it actually sits on — if it’s an I2C EEPROM, it’s described using the I2C binding as a child of the I2C controller node; if it’s a memory-mapped fuse block, it’s described using the standard reg-based MMIO binding. NVMEM adds exactly one optional property on top of that: a boolean read-only property that marks the whole device as non-writable from the framework’s side.

What NVMEM does define is the meaning of that provider node’s children: every child node under a provider is treated as one data cell — a named region of the provider’s storage.

Cell Properties: reg and bits

PropertyRequired?Meaning
regMandatoryTwo cells: byte offset into the provider, then size in bytes of the region
bitsOptionalTwo cells: bit offset (0-7) within the byte range, then number of bits — for sub-byte fields packed inside a larger register

A cell without bits simply covers whole bytes as given by reg. A cell with bits narrows that further down to individual bits inside the addressed range — useful for things like a single calibration trim bit packed alongside unrelated flags in the same byte.

An Original Provider Example: MMIO Fuse Box

Consider a fictional SoC fuse block, ep-fuse, mapped at a fixed physical address, exposing a factory-programmed serial number cell and a single-bit “secure boot enabled” flag packed into another byte:

Provider node: ep-fuse@40020000
epfuse: epfuse@40020000 { compatible = “ep,fuse-box”, “syscon”; reg = <0x40020000 0x1000>; #address-cells = <1>; #size-cells = <1>; epfuse_serial: serial@10 { reg = <0x10 4>; }; epfuse_secure_flag: secure-flag@30 { reg = <0x30 1>; bits = <3 1>; }; };

epfuse_serial covers 4 whole bytes starting at offset 0x10 — a plain byte-range cell. The epfuse_secure_flag cell narrows further: it addresses byte offset 0x30, then within that single byte picks out just bit 3, one bit wide. The framework builds an internal nvmem_cell for each child node and adds it to the system-wide cell list automatically — no driver code is needed to declare these cells when they come from DT; only the provider’s reg_read/reg_write callbacks and registration are required in C, as covered in the previous lecture.

Consumer Binding: nvmem-cells and nvmem-cell-names

A completely separate node — the consumer — references these cells by phandle, giving each one a lookup name of its own choosing:

Consumer node referencing the fuse cells
ep_secmon: ep-secmon { compatible = “ep,secmon”; nvmem-cells = <&epfuse_serial>, <&epfuse_secure_flag>; nvmem-cell-names = “serial”, “secure_flag”; };

Inside the ep-secmon driver, C code never needs to know that “serial” lives at offset 0x10 in some fuse block — it simply asks for the cell named "serial" through the standard NVMEM consumer API (devm_nvmem_cell_get() / nvmem_cell_read()), and the binding resolves the rest. This indirection is the entire point of the framework: swap the fuse box for a completely different chip on a new board revision, update only the DT, and the consumer driver doesn’t change at all.

Architecture: Why This Split Matters

Provider / Cell / Consumer relationship
[ epfuse provider node ] |– child: epfuse_serial (reg = 0x10, 4) |– child: epfuse_secure_flag (reg = 0x30,1 bits = 3,1) | | phandle reference v [ ep-secmon consumer node ] nvmem-cells = <serial>, <secure_flag> nvmem-cell-names = “serial”, “secure_flag”

The provider node owns the physical layout knowledge (offsets, bit positions, bus details). The consumer node owns only logical names. The NVMEM core sits between them, resolving phandles to cells and cells to provider callbacks at runtime — no consumer driver ever calls reg_read directly.

Common Mistakes

  • Giving the provider node its own made-up binding. There isn’t one — describe it purely per its parent bus (I2C, SPI, MMIO/syscon), and let NVMEM cell semantics apply only to its children.
  • Mismatched nvmem-cells and nvmem-cell-names array lengths. Every phandle in nvmem-cells needs a matching string at the same index in nvmem-cell-names; a length mismatch breaks lookup for cells after the mismatch point.
  • Using bits without checking the offset range. The bit offset must be 0-7 — it addresses a position within the byte(s) selected by reg, not an absolute bit address into the whole device.
  • Forgetting #address-cells/#size-cells on the provider node. Without them, child cell nodes’ reg properties won’t parse the way you expect.

Best Practices

  • Name cell nodes descriptively in DT (serial@10, not cell0@10) — it makes the binding self-documenting when someone reads the board DTS later.
  • Keep cell names in nvmem-cell-names stable across board revisions even if the underlying provider or offsets change — that’s the whole benefit of the indirection.
  • Reserve bits for genuinely sub-byte fields; if a cell always aligns to whole bytes, leave bits out entirely rather than specifying 0 8.
  • Document the read-only property explicitly on provider nodes holding factory-programmed data like serials or calibration trims, so accidental writes fail at the framework level.

Summary / Key Takeaways

  • NVMEM providers reuse their parent bus’s DT binding — there is no NVMEM-specific provider binding beyond the optional read-only property.
  • Every child node of a provider becomes a data cell; reg is mandatory, bits is optional for sub-byte fields.
  • Consumers bind to cells purely by phandle and logical name via nvmem-cells / nvmem-cell-names, staying completely decoupled from physical layout.

Conclusion

Device tree bindings are what turn a working NVMEM provider driver into something the rest of the system can actually discover and use — without them, cells only exist as hardcoded C structures tied to one board. Once you’re comfortable declaring provider nodes, cells, and consumer references, you have the full picture needed to both write new NVMEM providers and wire arbitrary consumer drivers to whatever storage a given board exposes. That completes the practical core of the NVMEM framework in this free linux device drivers course.

Interview Questions

Does the NVMEM framework define its own device tree binding for provider nodes?

No — a provider node is described using its parent bus’s binding (I2C, SPI, MMIO/syscon); NVMEM only adds an optional read-only property on top.

What does a child node under an NVMEM provider node represent?

It represents a single data cell — a named region of the provider’s storage, described by the mandatory reg property and the optional bits property.

What do the two cells of the bits property mean?

The bit offset (0-7) within the byte range selected by reg, followed by the number of bits — used for sub-byte fields packed inside a larger register.

How does a consumer node reference NVMEM cells, and why is that useful?

Through the nvmem-cells phandle list paired with nvmem-cell-names; it lets the consumer driver ask for a cell by logical name, staying decoupled from the provider’s physical layout.

What happens if nvmem-cells and nvmem-cell-names have mismatched lengths?

Name-based lookup breaks for the cells past the point where the arrays diverge, since each name is matched to a phandle by matching array index.

FAQ

Can an NVMEM provider be entirely software-only, with no device tree node at all?

Yes — providers can declare cells purely in C via nvmem_config.cells, as shown in an earlier lecture; DT-based cells are an alternative, not a requirement.

Is reg required on every cell node?

Yes, it’s the one mandatory cell property — it defines the byte offset and size of the cell within the provider’s storage.

Can a single provider expose both byte-range cells and bit-level cells?

Yes — some child nodes can use reg alone for whole-byte regions while others add bits for sub-byte fields, all under the same provider node.

Does the consumer driver need to know which bus the provider sits on?

No — that’s the point of the cell/consumer indirection; the consumer only deals with logical cell names through the standard NVMEM consumer API.

Where is the full official NVMEM device tree binding documented?

In the kernel’s device tree bindings documentation under the NVMEM section, alongside bindings for individual provider types.

Continue the Free Embedded Linux Course

Next: consumer drivers that read NVMEM cells at runtime.

Next Lecture Browse Full Course

Leave a Reply

Your email address will not be published. Required fields are marked *