Regmap Bulk Read Write and Cache- Free Linux Device Drivers Course

Regmap Bulk Read Write and Cache

Free Linux Kernel Development Course — Regmap API, Lecture 5

Kernel 6.x Ready
Original Driver Code
Beginner Friendly
free linux kernel development course
free embedded systems course
free linux device drivers course
regmap bulk read write linux kernel
regmap cache linux kernel
This lecture of our free linux kernel development course covers regmap_bulk_read(), regmap_bulk_write(), and how the Regmap API’s built-in caching system works on Linux kernel 6.x. These two topics close out the Regmap API chapter of this free embedded systems course and free linux device drivers course, and prepare you for real sensor and PMIC drivers.

What You Will Learn

  • When to use regmap_bulk_read() and regmap_bulk_write() instead of single-register calls
  • How regmap’s cache_type field controls caching behavior
  • How reg_defaults pre-populates the cache with power-on-reset values
  • How to build an original driver using bulk transfers and a cache
  • Common mistakes, best practices, and performance notes

Prerequisites

  • Completed lddch9_1 through lddch9_4 of this Regmap API series
  • Comfortable with regmap_config, regmap_read, regmap_write, and regmap_update_bits
  • A Linux kernel 6.x build environment with kernel headers installed

Understanding regmap_bulk_read and regmap_bulk_write

Some devices store related data across several consecutive registers — a three-axis accelerometer, for example, often places X, Y, and Z readings in six back-to-back registers. Reading them one register at a time with regmap_read() works, but issues one bus transaction per register. regmap_bulk_read() and regmap_bulk_write() transfer a whole block in a single, more efficient operation:

int regmap_bulk_read(struct regmap *map, unsigned int reg,
                      void *val, size_t val_count);
int regmap_bulk_write(struct regmap *map, unsigned int reg,
                       const void *val, size_t val_count);

reg is the starting register address, val is a buffer to fill (or read from), and val_count is how many register-sized values to transfer. Use these functions whenever you are dealing with a contiguous block of registers rather than a single value.

Practical Example: Bulk Reading Sensor Data

This original driver, ep_burst_sensor_demo, reads six consecutive 8-bit registers (X-low, X-high, Y-low, Y-high, Z-low, Z-high) from a fictional accelerometer in one regmap_bulk_read() call, exposed through a sysfs attribute.

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>

#define EP_AXIS_DATA_BASE  0x20
#define EP_AXIS_DATA_LEN   6

struct ep_burst_data {
	struct regmap *regmap;
};

static const struct regmap_config ep_burst_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = 0x30,
	.cache_type = REGCACHE_NONE,
};

static ssize_t axis_data_show(struct device *dev,
			      struct device_attribute *attr, char *buf)
{
	struct ep_burst_data *data = dev_get_drvdata(dev);
	u8 axis[EP_AXIS_DATA_LEN];
	int ret;

	ret = regmap_bulk_read(data->regmap, EP_AXIS_DATA_BASE,
				axis, EP_AXIS_DATA_LEN);
	if (ret)
		return ret;

	return sysfs_emit(buf, "x=%d y=%d z=%d\n",
			   (axis[1] << 8) | axis[0],
			   (axis[3] << 8) | axis[2],
			   (axis[5] << 8) | axis[4]);
}
static DEVICE_ATTR_RO(axis_data);

static int ep_burst_probe(struct i2c_client *client)
{
	struct ep_burst_data *data;

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

	data->regmap = devm_regmap_init_i2c(client, &ep_burst_regmap_config);
	if (IS_ERR(data->regmap))
		return PTR_ERR(data->regmap);

	i2c_set_clientdata(client, data);

	return device_create_file(&client->dev, &dev_attr_axis_data);
}

static void ep_burst_remove(struct i2c_client *client)
{
	device_remove_file(&client->dev, &dev_attr_axis_data);
}

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

static struct i2c_driver ep_burst_driver = {
	.driver = {
		.name = "ep_burst_sensor_demo",
		.of_match_table = ep_burst_of_match,
	},
	.probe = ep_burst_probe,
	.remove = ep_burst_remove,
};
module_i2c_driver(ep_burst_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala regmap_bulk_read demo driver");

Note that cache_type is set to REGCACHE_NONE here, since axis data changes constantly and should never be served from a stale cache.

Understanding Regmap Cache Support

Regmap can optionally remember the last known value of every register in software, avoiding a real bus transaction on every read. Whether caching is active, and how it is stored, depends on the cache_type field of regmap_config.

Regmap Cache Types

cache_type Description Best For
REGCACHE_NONE No caching, every access hits the bus (default) Fast-changing data such as sensor readings
REGCACHE_RBTREE Red-black tree storage, good for sparse register maps Devices with scattered, non-contiguous registers
REGCACHE_COMPRESSED Compressed storage for register maps with many repeated default values Devices with large maps that mostly hold defaults
REGCACHE_FLAT Plain flat array, fastest lookup Small, dense, fully populated register maps

By default, cache_type is REGCACHE_NONE and caching is disabled. When you enable a cache type, regmap can also be given a starting set of known values through reg_defaults, so the very first read after probe can be served instantly from cache instead of the bus.

reg_defaults and Cache Population

Many chips have a documented power-on-reset value for each register. You can hand these values to regmap once, and any read before the first real write will return the correct default from cache instead of triggering a bus transaction.

reg_default Fields

Field Meaning
reg Register address
def Its documented power-on-reset value

If a register is not listed in reg_defaults, regmap simply creates its cache entry the first time that register is read or written, so you only need to list values you already know from the datasheet. If cache_type is REGCACHE_NONE, reg_defaults is ignored entirely, since there is no cache to populate.

Practical Example: Driver Using an RBTREE Cache

This original driver, ep_cache_demo, declares three control registers with known reset defaults and enables an RBTREE cache so repeated reads of unchanged settings avoid the bus entirely.

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>

#define EP_CACHE_CTRL_REG    0x00
#define EP_CACHE_MODE_REG    0x01
#define EP_CACHE_GAIN_REG    0x02

static const struct reg_default ep_cache_reg_defaults[] = {
	{ EP_CACHE_CTRL_REG, 0x00 },
	{ EP_CACHE_MODE_REG, 0x01 },
	{ EP_CACHE_GAIN_REG, 0x04 },
};

static const struct regmap_config ep_cache_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = EP_CACHE_GAIN_REG,
	.reg_defaults = ep_cache_reg_defaults,
	.num_reg_defaults = ARRAY_SIZE(ep_cache_reg_defaults),
	.cache_type = REGCACHE_RBTREE,
};

static int ep_cache_probe(struct i2c_client *client)
{
	struct regmap *regmap;
	unsigned int val;
	int ret;

	regmap = devm_regmap_init_i2c(client, &ep_cache_regmap_config);
	if (IS_ERR(regmap))
		return PTR_ERR(regmap);

	/* Served from cache, no real bus transaction yet */
	ret = regmap_read(regmap, EP_CACHE_MODE_REG, &val);
	if (ret)
		return ret;

	dev_info(&client->dev, "mode register default = 0x%02x\n", val);
	return 0;
}

static const struct of_device_id ep_cache_of_match[] = {
	{ .compatible = "ep,cache-demo" },
	{ }
};
MODULE_DEVICE_TABLE(of, ep_cache_of_match);

static struct i2c_driver ep_cache_driver = {
	.driver = {
		.name = "ep_cache_demo",
		.of_match_table = ep_cache_of_match,
	},
	.probe = ep_cache_probe,
};
module_i2c_driver(ep_cache_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala regmap cache demo driver");

Building and Testing the Driver

obj-m += ep_cache_demo.o
KDIR := /lib/modules/$(shell uname -r)/build

all:
	make -C $(KDIR) M=$(PWD) modules
make
sudo insmod ep_cache_demo.ko
dmesg | tail -n 5

Expected output:

ep_cache_demo 1-0052: mode register default = 0x01

For the bulk-read driver, load it and read the sysfs attribute:

sudo insmod ep_burst_sensor_demo.ko
cat /sys/bus/i2c/devices/1-0053/axis_data
# x=12 y=-4 z=980

Cache Type Comparison

Cache Type Memory Use Lookup Speed Typical Register Map
REGCACHE_NONE None N/A (always hits bus) Any
REGCACHE_RBTREE Low, grows with used registers Good Sparse
REGCACHE_FLAT Higher, fixed size array Fastest Small and dense
REGCACHE_COMPRESSED Low Moderate Large, mostly-default maps

Common Mistakes

Mistake Consequence Fix
Using regmap_bulk_read on non-contiguous registers Wrong data returned, since the function assumes consecutive addresses Confirm the registers are truly back-to-back in the datasheet
Enabling a cache on fast-changing sensor data registers Stale readings returned to userspace Keep cache_type as REGCACHE_NONE for volatile data, or mark them volatile
Forgetting max_register when using a cache Cache cannot size itself correctly, reads may fail Always set max_register in regmap_config
Assuming reg_defaults populates every register Registers you never listed simply have no default, not zero Only rely on reg_defaults for registers you explicitly listed

Best Practices

  • Use regmap_bulk_read/write only for genuinely contiguous register blocks
  • Choose REGCACHE_RBTREE for sparse maps and REGCACHE_FLAT for small dense maps
  • Mark frequently changing registers as volatile so the cache never serves stale values for them
  • Populate reg_defaults directly from the datasheet’s reset value table

Performance Considerations

Bulk transfers reduce the number of bus transactions from one-per-register to one-per-block, which matters a great deal on slower buses like I2C. A properly configured cache avoids bus traffic entirely for registers that have not changed since their default or last write, but an incorrectly cached volatile register can silently return outdated data, so caching should always be paired with correct volatile_reg marking from lddch9_2.

Security Considerations

Do not expose bulk read/write ranges to userspace without validating the requested length against max_register; an unchecked val_count can lead to out-of-bounds access on the buffer or unintended reads of adjacent registers.

Summary

  • regmap_bulk_read/write transfer contiguous register blocks in a single operation
  • cache_type controls whether and how regmap caches register values (NONE, RBTREE, FLAT, COMPRESSED)
  • reg_defaults pre-populates the cache with known power-on-reset values
  • Caching must be combined with correct volatile_reg marking to avoid stale data

Conclusion

With regmap_bulk_read(), regmap_bulk_write(), and regmap’s caching system, you now have the complete toolkit this free linux kernel development course set out to teach for the Regmap API. Together with regmap_read, regmap_write, regmap_update_bits, and regmap_multi_reg_write from earlier lectures, you can write clean, efficient I2C and SPI drivers on kernel 6.x. This closes the Regmap API chapter of our free linux device drivers course; the next chapter in this free embedded systems course moves on to a new subsystem.

Frequently Asked Questions

When should I use regmap_bulk_read instead of regmap_read in a loop?

Use regmap_bulk_read whenever the registers are contiguous, since it issues one bus transaction instead of one per register.

What is the default cache_type if I don’t set one?

The default is REGCACHE_NONE, meaning caching is disabled and every access goes to the bus.

Does reg_defaults work if cache_type is REGCACHE_NONE?

No, reg_defaults is ignored entirely when caching is disabled since there is no cache to populate.

Which cache type should I pick for a sparse register map?

REGCACHE_RBTREE is generally the best choice for sparse, non-contiguous register maps.

Can a cached register still be read from hardware directly?

Yes, if you mark it as volatile through your volatile_reg callback, regmap will always read it from hardware instead of the cache.

Is regmap_bulk_write atomic across all registers?

It performs the transfer as a single bus operation where the underlying bus supports it, but you should still check the return value for partial failures.

Do I need to list every register in reg_defaults?

No, only list registers whose reset value you know; others get their cache entry created on first access.

Continue the Free Linux Kernel Development Course

 

Leave a Reply

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