NVMEM Consumer APIs Explained-Free Linux Device Drivers Course

NVMEM Consumer APIs Explained
Reading and writing NVMEM cells from consumer drivers, and exposing NVMEM to user space — the closing lecture of our free Linux kernel development course NVMEM chapter

In the last four lectures of this free embedded Linux course we built NVMEM providers from scratch — a fake in-memory provider, an EEPROM-backed provider, an RTC-based provider, and a device-tree-described MMIO fuse provider. Every one of those providers exists for exactly one reason: so that some other driver, the consumer, can pull calibration data, a MAC address, a serial number, or a temperature grade out of non-volatile storage without caring how that storage is physically implemented. This lecture closes the loop from the consumer side, and then shows how the same data becomes visible from a shell prompt in user space.

nvmem consumer api nvmem_cell_read_u32 devm_nvmem_cell_get nvmem sysfs free linux kernel development course

What You Will Learn

  • How a consumer driver locates and opens an NVMEM cell that a provider has exposed
  • The difference between the raw nvmem_cell_read() API and the typed nvmem_cell_read_u16/u32/u64() helpers
  • Why the devm_-prefixed variants of every consumer API should be your default choice
  • How to write an original consumer driver that pulls two calibration cells at probe time
  • How the same NVMEM data is exposed to user space through sysfs, and how to read/write it with cat, hexdump, and echo
  • Common mistakes, security considerations, and best practices when consuming NVMEM cells

Prerequisites

  • Lecture ldd2ch12_1 through ldd2ch12_4 of this NVMEM chapter — provider registration, cell declaration, and device tree bindings
  • Comfort with platform_driver probe/remove and devm_* resource-managed helpers
  • A kernel build environment on a recent 6.x tree (real hardware or QEMU)

The Consumer Side, Conceptually

A provider only ever exposes bytes. It has no idea whether those bytes are a calibration constant, a thermal grade, or a MAC address — that meaning is attached at the consumer end, through a cell. A cell is a named, offset-and-size-bound slice of the provider’s storage, and a consumer asks the NVMEM core for that cell by name, not by offset. This indirection is what lets the same consumer driver run unmodified on two boards where the calibration data happens to live at different offsets in different storage devices — the device tree (or board file) is what maps the name to the offset, not the driver.

Consumer Lookup Path
consumer driver | | devm_nvmem_cell_get(dev, “calib”) v NVMEM core — resolves “calib” against —> nvmem-cell-names / nvmem-cells | (set by the device tree) v struct nvmem_cell * —- points into —-> provider’s backing storage | | nvmem_cell_read() / nvmem_cell_read_u32() v bytes handed back to the consumer

Consumer API Reference (Current Kernel)

All of these live in <linux/nvmem-consumer.h>. Two families exist: cell handle management, and cell reading/writing.

FunctionPurpose
nvmem_cell_get(dev, name)Look up and pin a cell by its consumer-side name; caller must release it
devm_nvmem_cell_get(dev, name)Same, but automatically released when the device detaches — prefer this
nvmem_cell_put(cell) / devm_nvmem_cell_put(dev, cell)Release a handle obtained above (rarely needed with the devm variant)
nvmem_cell_read(cell, &len)Read the whole cell as raw bytes; kernel allocates the buffer, caller frees it with kfree()
nvmem_cell_write(cell, buf, len)Write raw bytes back into the cell, if the provider supports writes
nvmem_cell_read_u16/u32/u64(dev, cell_id, &val)One-shot helpers: look up the cell by name, read it, cast it to a fixed-width integer, and release the handle — all in one call
nvmem_cell_read_variable_le_u32/u64(dev, cell_id, &val)Same as above, but for cells that are fewer than 32/64 bits wide and stored little-endian — common for bit-packed fuse fields

Notice the design: if all you need is “give me this one value as an integer,” the typed helpers do the get/read/put dance for you in a single call. If you need to read a cell more than once, or the cell holds a multi-byte blob rather than an integer, get a persistent handle with devm_nvmem_cell_get() and call nvmem_cell_read() on it directly.

Device Tree Recap

As lecture ldd2ch12_4 covered in detail, the consumer side of the binding is just two properties on the consumer’s own node:

ep_sensor@0 {
    compatible = "ep,sensor";
    nvmem-cells = <&ep_calib_cell>, <&ep_grade_cell>;
    nvmem-cell-names = "calib", "grade";
};

The string in nvmem-cell-names is exactly the string you pass as cell_id or name to every consumer API above. Get this string wrong and every lookup fails with -ENOENT at probe time — it is the single most common bug in NVMEM consumer code.

Original Example: ep_therm_consumer

The following driver is original to this course. It probes on our own ep,thermal-sensor compatible string, pulls a calibration offset and a thermal grade cell, and adjusts its behaviour accordingly — modelled on the pattern real SoC thermal drivers use, but with none of the vendor-specific code copied from anywhere.

// ep_therm_consumer.c
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/nvmem-consumer.h>

struct ep_therm_priv {
    struct device *dev;
    u32 calib_offset;
    u32 therm_grade;
};

static int ep_therm_probe(struct platform_device *pdev)
{
    struct ep_therm_priv *priv;
    int ret;

    priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    priv->dev = &pdev->dev;

    /* One-shot typed read: look up "calib", read it, release it */
    ret = nvmem_cell_read_u32(priv->dev, "calib", &priv->calib_offset);
    if (ret) {
        dev_err(priv->dev, "failed to read calib cell: %d\n", ret);
        return ret;
    }

    ret = nvmem_cell_read_u32(priv->dev, "grade", &priv->therm_grade);
    if (ret) {
        dev_err(priv->dev, "failed to read grade cell: %d\n", ret);
        return ret;
    }

    dev_info(priv->dev, "ep_therm: calib_offset=0x%x grade=%u\n",
             priv->calib_offset, priv->therm_grade);

    platform_set_drvdata(pdev, priv);
    return 0;
}

static const struct of_device_id ep_therm_of_match[] = {
    { .compatible = "ep,thermal-sensor" },
    { }
};
MODULE_DEVICE_TABLE(of, ep_therm_of_match);

static struct platform_driver ep_therm_driver = {
    .probe = ep_therm_probe,
    .driver = {
        .name = "ep_therm_consumer",
        .of_match_table = ep_therm_of_match,
    },
};
module_platform_driver(ep_therm_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala original NVMEM consumer demo");

Build and Run

Build it as an out-of-tree module against your configured kernel source tree, and bind it to a node exposing calib/grade cells (you can reuse the ep_eeprom_driver provider from ldd2ch12_2 as the backing storage):

$ make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
$ sudo insmod ep_therm_consumer.ko

Expected dmesg output:

$ dmesg | tail -3
[  912.441002] ep_therm_consumer ep_therm@0: ep_therm: calib_offset=0x2a grade=3

NVMEM in User Space

The NVMEM core doesn’t stop at kernel consumers — every registered NVMEM device also gets a raw binary sysfs file, so user-space tools and scripts can inspect the same storage without writing a single line of C. Each device gets a directory under /sys/bus/nvmem/devices/, named after the provider’s nvmem_config.name (with a numeric suffix appended if the provider didn’t request a fixed ID), and inside that directory sits a binary attribute file named nvmem.

Sysfs Path Pattern
/sys/bus/nvmem/devices/<dev-name><id>/nvmem ^^^^^^^^^^ ^^^ nvmem_config.name numeric ID (only if config->id was not -1, or name was unset)

Continuing our ep_eeprom_driver example from earlier in the chapter, registered with nvmem_config.name = "ep-eeprom", the file shows up as something like /sys/bus/nvmem/devices/ep-eeprom0/nvmem. Reading and writing it is just ordinary file I/O:

$ hexdump -C /sys/bus/nvmem/devices/ep-eeprom0/nvmem
00000000  2a 03 00 00 45 50 2d 44  45 4d 4f 00 00 00 00 00  |*...EP-DEMO.....|

$ sudo sh -c 'printf "\x2b" | dd of=/sys/bus/nvmem/devices/ep-eeprom0/nvmem bs=1 seek=0 conv=notrunc'
$ hexdump -C /sys/bus/nvmem/devices/ep-eeprom0/nvmem | head -1
00000000  2b 03 00 00 45 50 2d 44  45 4d 4f 00 00 00 00 00  |+...EP-DEMO.....|

Important: the sysfs file always exposes the provider’s entire register space, byte for byte — never individual cells. If you want to read just the “grade” cell from the shell, you must already know its offset and size, because the cell abstraction only exists on the kernel side of the consumer API. This is a deliberate design choice: cells are a kernel-side convenience layer, not a user-space ABI.

Real-World Use Cases

  • Factory calibration data (ADC offsets, RF trim values) read once at probe time by a sensor or radio driver
  • MAC addresses stored in board EEPROM and consumed by an Ethernet or Wi-Fi driver’s probe()
  • SoC speed/thermal binning grades read from on-chip fuses and used to select a DVFS operating-point table
  • Field-service and manufacturing test scripts reading/writing calibration data purely through sysfs, with no kernel driver involved at all

Common Mistakes and Troubleshooting

  • Cell name mismatch: the string passed to nvmem_cell_read_u32() must exactly match an entry in the consumer’s nvmem-cell-names, not the cell node’s name in the provider — these are frequently different, and mixing them up is the #1 cause of probe-time -ENOENT
  • Forgetting -EPROBE_DEFER: if the NVMEM provider hasn’t probed yet, cell lookups return -EPROBE_DEFER — propagate this return value from your probe() unchanged instead of treating it as a hard failure
  • Using nvmem_cell_get() instead of the devm_ variant: leads to leaked cell handles on driver unbind/error paths — always prefer devm_nvmem_cell_get() unless you have a specific reason not to
  • Assuming len is fixed: for nvmem_cell_read(), always use the returned len rather than a hardcoded size — cell width is defined in the device tree, not in your driver
  • Expecting the sysfs file to understand cells: a raw cat of the nvmem file dumps the whole backing store; offset math for a specific field is on you

Best Practices

  • Always use the devm_-prefixed consumer APIs inside driver probe() functions
  • Propagate -EPROBE_DEFER from cell lookups so probe ordering resolves itself instead of failing hard
  • Prefer the typed nvmem_cell_read_uNN() helpers for small fixed-width values; reserve raw nvmem_cell_read() for blobs (MAC addresses, serial strings, calibration tables)
  • Document the expected nvmem-cell-names strings in your driver’s device tree binding documentation — this is the contract between your driver and every board integrator

Security Considerations

The sysfs nvmem binary attribute’s read/write permissions are set by the provider driver at registration time (nvmem_config.read_only, and the underlying root_only flag some providers still expose). Treat any NVMEM region holding secrets — encryption keys, provisioning tokens, unique device identifiers used for attestation — as root_only and read-only wherever the hardware allows it; a world-writable nvmem file is an easy way to let an unprivileged user space process corrupt calibration data or brick a fused-once region.

Interview Questions

What is the difference between nvmem_cell_read() and nvmem_cell_read_u32()?

nvmem_cell_read() operates on an already-obtained struct nvmem_cell * handle and returns a raw, kernel-allocated buffer plus its length. nvmem_cell_read_u32() is a convenience wrapper that looks the cell up by name, reads it, casts it to a u32, releases the handle, and returns — all in one call, with no buffer for you to free.

Why should devm_nvmem_cell_get() be preferred over nvmem_cell_get()?

The devm_ variant registers the handle with the device’s resource-managed cleanup list, so it is automatically released on driver detach or a failed probe — eliminating a whole class of leak bugs on error paths.

Can a user-space program read an individual NVMEM cell directly?

No. The sysfs nvmem binary file exposes the provider’s entire raw storage, not the cell abstraction. Reading a specific field from user space requires already knowing that field’s offset and size.

What does it mean if a cell lookup returns -EPROBE_DEFER?

It means the NVMEM provider that owns the requested cell hasn’t finished probing yet. The consumer driver should return the same error code from its own probe() so the driver core retries later, once the provider is available.

Where does the mapping from a cell’s name to its offset in storage actually live?

In the device tree (or board file, for non-DT platforms) — specifically in the provider’s cell sub-nodes and the consumer’s nvmem-cells/nvmem-cell-names properties. The driver code never hardcodes offsets.

Summary and Conclusion

This closes out our NVMEM chapter. Across five lectures we went from an empty provider skeleton through cell declarations, RTC-backed storage, device tree bindings, and finally the consumer side and the user-space sysfs interface. The pattern to remember: providers expose raw storage and describe cells, the device tree binds names to offsets, and consumers ask for data by name — never by address. That indirection is what makes the same calibration-reading driver portable across every board that bothers to describe its NVMEM layout correctly.

In the next chapter of this free Linux device drivers course, we move from data storage into system reliability, and start building watchdog device drivers.

FAQ

Do I need to call nvmem_cell_put() if I used devm_nvmem_cell_get()?

No — the devm-managed handle is released automatically. You’d only call the plain put() variant if you obtained the cell with the non-devm get() function.

What happens if I call nvmem_cell_write() on a read-only provider?

The provider’s reg_write callback either isn’t set or returns an error, and nvmem_cell_write() propagates that failure back to the caller — nothing is silently dropped.

Is the NVMEM sysfs file always present?

Yes, for every device registered through nvmem_register()/devm_nvmem_register(), unless the provider explicitly disables sysfs export in its nvmem_config.

Can two different consumers request the same cell at the same time?

Yes — cell handles are reference-counted, and multiple consumers (or the same consumer calling get() more than once) can hold independent handles to the same underlying cell safely.

Why use nvmem_cell_read_variable_le_u32() instead of the plain u32 variant?

Because many fuse and calibration cells are only a few bits wide and packed at odd bit offsets. The variable-length little-endian helper handles that sub-byte/sub-word extraction for you, where the plain u32 reader assumes a full, aligned 32-bit field.

Where should I look this API up directly in the kernel source?

include/linux/nvmem-consumer.h for the prototypes, and drivers/nvmem/core.c for the implementation.

Want the full free Linux kernel development course?

Browse All Lectures Join EmbeddedPathashala

Leave a Reply

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