From dc65b1ed4bb34ab6235ff2cc6a917b9295c04c2c Mon Sep 17 00:00:00 2001 From: Sheetal Date: Fri, 23 Jan 2026 15:23:44 +0530 Subject: [PATCH] regmap: Add reg_default_cb callback for flat cache defaults Commit e062bdfdd6ad ("regmap: warn users about uninitialized flat cache") warns when REGCACHE_FLAT is used without full defaults. This causes false positives on hardware where many registers reset to zero but are not listed in reg_defaults, forcing drivers to maintain large tables just to silence the warning. Add a reg_default_cb() hook so drivers can supply defaults for registers not present in reg_defaults when populating REGCACHE_FLAT. This keeps the warning quiet for known zero-reset registers without bloating tables. Provide a generic regmap_default_zero_cb() helper for drivers that need zero defaults. The hook is only used for REGCACHE_FLAT; the core does not check readable/writeable access, so drivers must provide readable_reg/ writeable_reg callbacks and handle holes in the register map. Signed-off-by: Sheetal Link: https://patch.msgid.link/20260123095346.1258556-3-sheetal@nvidia.com Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 3 +++ drivers/base/regmap/regcache-flat.c | 19 +++++++++++++++++++ drivers/base/regmap/regcache.c | 3 ++- drivers/base/regmap/regmap.c | 2 ++ include/linux/regmap.h | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 1477329410ec4..5bf9931654387 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -117,6 +117,9 @@ struct regmap { void *val_buf, size_t val_size); int (*write)(void *context, const void *data, size_t count); + int (*reg_default_cb)(struct device *dev, unsigned int reg, + unsigned int *val); + unsigned long read_flag_mask; unsigned long write_flag_mask; diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c index 53cc59c84e2f0..c924817e19b1c 100644 --- a/drivers/base/regmap/regcache-flat.c +++ b/drivers/base/regmap/regcache-flat.c @@ -79,6 +79,25 @@ static int regcache_flat_populate(struct regmap *map) __set_bit(index, cache->valid); } + if (map->reg_default_cb) { + dev_dbg(map->dev, + "Populating regcache_flat using reg_default_cb callback\n"); + + for (i = 0; i <= map->max_register; i += map->reg_stride) { + unsigned int index = regcache_flat_get_index(map, i); + unsigned int value; + + if (test_bit(index, cache->valid)) + continue; + + if (map->reg_default_cb(map->dev, i, &value)) + continue; + + cache->data[index] = value; + __set_bit(index, cache->valid); + } + } + return 0; } diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 319c342bf5a06..31bdbf37dbed5 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -223,7 +223,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) goto err_free; } - if (map->num_reg_defaults && map->cache_ops->populate) { + if (map->cache_ops->populate && + (map->num_reg_defaults || map->reg_default_cb)) { dev_dbg(map->dev, "Populating %s cache\n", map->cache_ops->name); map->lock(map->lock_arg); ret = map->cache_ops->populate(map); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ae2215d4e61c3..4231e9d4b8ff5 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -813,6 +813,7 @@ struct regmap *__regmap_init(struct device *dev, map->precious_reg = config->precious_reg; map->writeable_noinc_reg = config->writeable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg; + map->reg_default_cb = config->reg_default_cb; map->cache_type = config->cache_type; spin_lock_init(&map->async_lock); @@ -1435,6 +1436,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) map->precious_reg = config->precious_reg; map->writeable_noinc_reg = config->writeable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg; + map->reg_default_cb = config->reg_default_cb; map->cache_type = config->cache_type; ret = regmap_set_name(map, config); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index b0b9be750d939..caff2240bdab7 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -359,6 +359,10 @@ typedef void (*regmap_unlock)(void *); * @reg_defaults: Power on reset values for registers (for use with * register cache support). * @num_reg_defaults: Number of elements in reg_defaults. + * @reg_default_cb: Optional callback to return default values for registers + * not listed in reg_defaults. This is only used for + * REGCACHE_FLAT population; drivers must ensure the readable_reg/ + * writeable_reg callbacks are defined to handle holes. * * @read_flag_mask: Mask to be set in the top bytes of the register when doing * a read. @@ -449,6 +453,8 @@ struct regmap_config { const struct regmap_access_table *rd_noinc_table; const struct reg_default *reg_defaults; unsigned int num_reg_defaults; + int (*reg_default_cb)(struct device *dev, unsigned int reg, + unsigned int *def); enum regcache_type cache_type; const void *reg_defaults_raw; unsigned int num_reg_defaults_raw; @@ -1349,6 +1355,14 @@ static inline int regmap_write_bits(struct regmap *map, unsigned int reg, return regmap_update_bits_base(map, reg, mask, val, NULL, false, true); } +static inline int regmap_default_zero_cb(struct device *dev, + unsigned int reg, + unsigned int *def) +{ + *def = 0; + return 0; +} + int regmap_get_val_bytes(struct regmap *map); int regmap_get_max_register(struct regmap *map); int regmap_get_reg_stride(struct regmap *map); -- 2.47.3